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/javax/annotation/processing/Generated.java b/javax/annotation/processing/Generated.java
new file mode 100644
index 0000000..cd3e666
--- /dev/null
+++ b/javax/annotation/processing/Generated.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2005, 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 javax.annotation.processing;
+
+import java.lang.annotation.*;
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.*;
+
+// Android-changed: Javadoc removed (this is just a stub).
+
+@Documented
+@Retention(SOURCE)
+@Target({PACKAGE, TYPE, METHOD, CONSTRUCTOR, FIELD,
+    LOCAL_VARIABLE, PARAMETER})
+public @interface Generated {
+
+    String[] value();
+
+    String date() default "";
+
+    String comments() default "";
+}
diff --git a/javax/crypto/AEADBadTagException.java b/javax/crypto/AEADBadTagException.java
new file mode 100644
index 0000000..8587fcf
--- /dev/null
+++ b/javax/crypto/AEADBadTagException.java
@@ -0,0 +1,55 @@
+/*
+ * 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 javax.crypto;
+
+/**
+ * This exception is thrown when a {@link Cipher} operating in
+ * an AEAD mode (such as GCM/CCM) is unable to verify the supplied
+ * authentication tag.
+ *
+ * @since 1.7
+ */
+public class AEADBadTagException extends BadPaddingException {
+
+    private static final long serialVersionUID = -488059093241685509L;
+
+    /**
+     * Constructs a AEADBadTagException with no detail message.
+     */
+    public AEADBadTagException() {
+        super();
+    }
+
+    /**
+     * Constructs a AEADBadTagException with the specified
+     * detail message.
+     *
+     * @param msg the detail message.
+     */
+    public AEADBadTagException(String msg) {
+        super(msg);
+    }
+}
diff --git a/javax/crypto/BadPaddingException.java b/javax/crypto/BadPaddingException.java
new file mode 100644
index 0000000..cc6455f
--- /dev/null
+++ b/javax/crypto/BadPaddingException.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 1997, 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 javax.crypto;
+
+import java.security.GeneralSecurityException;
+
+/**
+ * This exception is thrown when a particular padding mechanism is
+ * expected for the input data but the data is not padded properly.
+ *
+ * @author Gigi Ankney
+ * @since 1.4
+ */
+
+public class BadPaddingException extends GeneralSecurityException {
+
+    private static final long serialVersionUID = -5315033893984728443L;
+
+    /**
+     * Constructs a BadPaddingException with no detail
+     * message. A detail message is a String that describes this
+     * particular exception.
+     */
+    public BadPaddingException() {
+        super();
+    }
+
+    /**
+     * Constructs a BadPaddingException with the specified
+     * detail message.
+     *
+     * @param msg the detail message.
+     */
+    public BadPaddingException(String msg) {
+        super(msg);
+    }
+}
diff --git a/javax/crypto/Cipher.annotated.java b/javax/crypto/Cipher.annotated.java
new file mode 100644
index 0000000..bafd946
--- /dev/null
+++ b/javax/crypto/Cipher.annotated.java
@@ -0,0 +1,136 @@
+/*
+ * 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 javax.crypto;
+
+import java.util.*;
+import java.util.regex.*;
+import java.security.*;
+import javax.crypto.spec.*;
+import sun.security.jca.*;
+import java.nio.ReadOnlyBufferException;
+import java.nio.ByteBuffer;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.Provider.Service;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class Cipher {
+
+protected Cipher(javax.crypto.CipherSpi cipherSpi, java.security.Provider provider, java.lang.String transformation) { throw new RuntimeException("Stub!"); }
+
+public static final javax.crypto.Cipher getInstance(java.lang.String transformation) throws java.security.NoSuchAlgorithmException, javax.crypto.NoSuchPaddingException { throw new RuntimeException("Stub!"); }
+
+public static final javax.crypto.Cipher getInstance(java.lang.String transformation, java.lang.String provider) throws java.security.NoSuchAlgorithmException, javax.crypto.NoSuchPaddingException, java.security.NoSuchProviderException { throw new RuntimeException("Stub!"); }
+
+public static final javax.crypto.Cipher getInstance(java.lang.String transformation, java.security.Provider provider) throws java.security.NoSuchAlgorithmException, javax.crypto.NoSuchPaddingException { throw new RuntimeException("Stub!"); }
+
+public final java.security.Provider getProvider() { throw new RuntimeException("Stub!"); }
+
+public final java.lang.String getAlgorithm() { throw new RuntimeException("Stub!"); }
+
+public final int getBlockSize() { throw new RuntimeException("Stub!"); }
+
+public final int getOutputSize(int inputLen) { throw new RuntimeException("Stub!"); }
+
+public final byte[] getIV() { throw new RuntimeException("Stub!"); }
+
+public final java.security.AlgorithmParameters getParameters() { throw new RuntimeException("Stub!"); }
+
+public final javax.crypto.ExemptionMechanism getExemptionMechanism() { throw new RuntimeException("Stub!"); }
+
+public final void init(int opmode, java.security.Key key) throws java.security.InvalidKeyException { throw new RuntimeException("Stub!"); }
+
+public final void init(int opmode, java.security.Key key, java.security.SecureRandom random) throws java.security.InvalidKeyException { throw new RuntimeException("Stub!"); }
+
+public final void init(int opmode, java.security.Key key, java.security.spec.AlgorithmParameterSpec params) throws java.security.InvalidAlgorithmParameterException, java.security.InvalidKeyException { throw new RuntimeException("Stub!"); }
+
+public final void init(int opmode, java.security.Key key, java.security.spec.AlgorithmParameterSpec params, java.security.SecureRandom random) throws java.security.InvalidAlgorithmParameterException, java.security.InvalidKeyException { throw new RuntimeException("Stub!"); }
+
+public final void init(int opmode, java.security.Key key, java.security.AlgorithmParameters params) throws java.security.InvalidAlgorithmParameterException, java.security.InvalidKeyException { throw new RuntimeException("Stub!"); }
+
+public final void init(int opmode, java.security.Key key, java.security.AlgorithmParameters params, java.security.SecureRandom random) throws java.security.InvalidAlgorithmParameterException, java.security.InvalidKeyException { throw new RuntimeException("Stub!"); }
+
+public final void init(int opmode, java.security.cert.Certificate certificate) throws java.security.InvalidKeyException { throw new RuntimeException("Stub!"); }
+
+public final void init(int opmode, java.security.cert.Certificate certificate, java.security.SecureRandom random) throws java.security.InvalidKeyException { throw new RuntimeException("Stub!"); }
+
+public final byte[] update(byte[] input) { throw new RuntimeException("Stub!"); }
+
+public final byte[] update(byte[] input, int inputOffset, int inputLen) { throw new RuntimeException("Stub!"); }
+
+public final int update(byte[] input, int inputOffset, int inputLen, byte[] output) throws javax.crypto.ShortBufferException { throw new RuntimeException("Stub!"); }
+
+public final int update(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws javax.crypto.ShortBufferException { throw new RuntimeException("Stub!"); }
+
+public final int update(java.nio.ByteBuffer input, java.nio.ByteBuffer output) throws javax.crypto.ShortBufferException { throw new RuntimeException("Stub!"); }
+
+public final byte[] doFinal() throws javax.crypto.BadPaddingException, javax.crypto.IllegalBlockSizeException { throw new RuntimeException("Stub!"); }
+
+public final int doFinal(byte[] output, int outputOffset) throws javax.crypto.BadPaddingException, javax.crypto.IllegalBlockSizeException, javax.crypto.ShortBufferException { throw new RuntimeException("Stub!"); }
+
+public final byte[] doFinal(byte[] input) throws javax.crypto.BadPaddingException, javax.crypto.IllegalBlockSizeException { throw new RuntimeException("Stub!"); }
+
+public final byte[] doFinal(byte[] input, int inputOffset, int inputLen) throws javax.crypto.BadPaddingException, javax.crypto.IllegalBlockSizeException { throw new RuntimeException("Stub!"); }
+
+public final int doFinal(byte[] input, int inputOffset, int inputLen, byte[] output) throws javax.crypto.BadPaddingException, javax.crypto.IllegalBlockSizeException, javax.crypto.ShortBufferException { throw new RuntimeException("Stub!"); }
+
+public final int doFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws javax.crypto.BadPaddingException, javax.crypto.IllegalBlockSizeException, javax.crypto.ShortBufferException { throw new RuntimeException("Stub!"); }
+
+public final int doFinal(java.nio.ByteBuffer input, java.nio.ByteBuffer output) throws javax.crypto.BadPaddingException, javax.crypto.IllegalBlockSizeException, javax.crypto.ShortBufferException { throw new RuntimeException("Stub!"); }
+
+public final byte[] wrap(java.security.Key key) throws javax.crypto.IllegalBlockSizeException, java.security.InvalidKeyException { throw new RuntimeException("Stub!"); }
+
+public final java.security.Key unwrap(byte[] wrappedKey, java.lang.String wrappedKeyAlgorithm, int wrappedKeyType) throws java.security.InvalidKeyException, java.security.NoSuchAlgorithmException { throw new RuntimeException("Stub!"); }
+
+public static final int getMaxAllowedKeyLength(java.lang.String transformation) throws java.security.NoSuchAlgorithmException { throw new RuntimeException("Stub!"); }
+
+public static final java.security.spec.AlgorithmParameterSpec getMaxAllowedParameterSpec(java.lang.String transformation) throws java.security.NoSuchAlgorithmException { throw new RuntimeException("Stub!"); }
+
+public final void updateAAD(byte[] src) { throw new RuntimeException("Stub!"); }
+
+public final void updateAAD(byte[] src, int offset, int len) { throw new RuntimeException("Stub!"); }
+
+public final void updateAAD(java.nio.ByteBuffer src) { throw new RuntimeException("Stub!"); }
+
[email protected]
+public javax.crypto.CipherSpi getCurrentSpi() { throw new RuntimeException("Stub!"); }
+
+public static final int DECRYPT_MODE = 2; // 0x2
+
+public static final int ENCRYPT_MODE = 1; // 0x1
+
+public static final int PRIVATE_KEY = 2; // 0x2
+
+public static final int PUBLIC_KEY = 1; // 0x1
+
+public static final int SECRET_KEY = 3; // 0x3
+
+public static final int UNWRAP_MODE = 4; // 0x4
+
+public static final int WRAP_MODE = 3; // 0x3
+}
+
diff --git a/javax/crypto/Cipher.java b/javax/crypto/Cipher.java
new file mode 100644
index 0000000..7968f2f
--- /dev/null
+++ b/javax/crypto/Cipher.java
@@ -0,0 +1,2997 @@
+/*
+ * 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 javax.crypto;
+
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.regex.*;
+
+import static java.util.Locale.ENGLISH;
+
+import java.security.*;
+import java.security.Provider.Service;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+
+import javax.crypto.spec.*;
+
+import java.nio.ByteBuffer;
+import java.nio.ReadOnlyBufferException;
+import sun.security.jca.*;
+
+/**
+ * This class provides the functionality of a cryptographic cipher for
+ * encryption and decryption. It forms the core of the Java Cryptographic
+ * Extension (JCE) framework.
+ *
+ * <p>In order to create a Cipher object, the application calls the
+ * Cipher's <code>getInstance</code> method, and passes the name of the
+ * requested <i>transformation</i> to it. Optionally, the name of a provider
+ * may be specified.
+ *
+ * <p>A <i>transformation</i> is a string that describes the operation (or
+ * set of operations) to be performed on the given input, to produce some
+ * output. A transformation always includes the name of a cryptographic
+ * algorithm (e.g., <i>DES</i>), and may be followed by a feedback mode and
+ * padding scheme.
+ *
+ * <p> A transformation is of the form:
+ *
+ * <ul>
+ * <li>"<i>algorithm/mode/padding</i>" or
+ *
+ * <li>"<i>algorithm</i>"
+ * </ul>
+ *
+ * <P> (in the latter case,
+ * provider-specific default values for the mode and padding scheme are used).
+ * For example, the following is a valid transformation:
+ *
+ * <pre>
+ *     Cipher c = Cipher.getInstance("<i>DES/CBC/PKCS5Padding</i>");
+ * </pre>
+ *
+ * Using modes such as <code>CFB</code> and <code>OFB</code>, block
+ * ciphers can encrypt data in units smaller than the cipher's actual
+ * block size.  When requesting such a mode, you may optionally specify
+ * the number of bits to be processed at a time by appending this number
+ * to the mode name as shown in the "<code>DES/CFB8/NoPadding</code>" and
+ * "<code>DES/OFB32/PKCS5Padding</code>" transformations. If no such
+ * number is specified, a provider-specific default is used. (For
+ * example, the SunJCE provider uses a default of 64 bits for DES.)
+ * Thus, block ciphers can be turned into byte-oriented stream ciphers by
+ * using an 8 bit mode such as CFB8 or OFB8.
+ * <p>
+ * Modes such as Authenticated Encryption with Associated Data (AEAD)
+ * provide authenticity assurances for both confidential data and
+ * Additional Associated Data (AAD) that is not encrypted.  (Please see
+ * <a href="http://www.ietf.org/rfc/rfc5116.txt"> RFC 5116 </a> for more
+ * information on AEAD and AEAD algorithms such as GCM/CCM.) Both
+ * confidential and AAD data can be used when calculating the
+ * authentication tag (similar to a {@link Mac}).  This tag is appended
+ * to the ciphertext during encryption, and is verified on decryption.
+ * <p>
+ * AEAD modes such as GCM/CCM perform all AAD authenticity calculations
+ * before starting the ciphertext authenticity calculations.  To avoid
+ * implementations having to internally buffer ciphertext, all AAD data
+ * must be supplied to GCM/CCM implementations (via the {@code
+ * updateAAD} methods) <b>before</b> the ciphertext is processed (via
+ * the {@code update} and {@code doFinal} methods).
+ * <p>
+ * Note that GCM mode has a uniqueness requirement on IVs used in
+ * encryption with a given key. When IVs are repeated for GCM
+ * encryption, such usages are subject to forgery attacks. Thus, after
+ * each encryption operation using GCM mode, callers should re-initialize
+ * the cipher objects with GCM parameters which has a different IV value.
+ * <pre>
+ *     GCMParameterSpec s = ...;
+ *     cipher.init(..., s);
+ *
+ *     // If the GCM parameters were generated by the provider, it can
+ *     // be retrieved by:
+ *     // cipher.getParameters().getParameterSpec(GCMParameterSpec.class);
+ *
+ *     cipher.updateAAD(...);  // AAD
+ *     cipher.update(...);     // Multi-part update
+ *     cipher.doFinal(...);    // conclusion of operation
+ *
+ *     // Use a different IV value for every encryption
+ *     byte[] newIv = ...;
+ *     s = new GCMParameterSpec(s.getTLen(), newIv);
+ *     cipher.init(..., s);
+ *     ...
+ *
+ * </pre>
+ * <p> Android provides the following <code>Cipher</code> transformations:
+ * <table>
+ *   <thead>
+ *     <tr>
+ *       <th>Algorithm</th>
+ *       <th>Modes</th>
+ *       <th>Paddings</th>
+ *       <th>Supported API Levels</th>
+ *       <th>Notes</th>
+ *     </tr>
+ *   </thead>
+ *   <tbody>
+ *     <tr>
+ *       <td rowspan="2"><span style="white-space: nowrap">AES</span></td>
+ *       <td><span style="white-space: nowrap">CBC</span><br><span style="white-space: nowrap">CFB</span><br><span style="white-space: nowrap">CTR</span><br><span style="white-space: nowrap">CTS</span><br><span style="white-space: nowrap">ECB</span><br><span style="white-space: nowrap">OFB</span></td>
+ *       <td><span style="white-space: nowrap">ISO10126Padding</span><br><span style="white-space: nowrap">NoPadding</span><br><span style="white-space: nowrap">PKCS5Padding</span></td>
+ *       <td><span style="white-space: nowrap">1+</span></td>
+ *       <td></td>
+ *     </tr>
+ *     <tr>
+ *       <td><span style="white-space: nowrap">GCM</span></td>
+ *       <td><span style="white-space: nowrap">NoPadding</span></td>
+ *       <td><span style="white-space: nowrap">10+</span></td>
+ *       <td></td>
+ *     </tr>
+ *     <tr>
+ *       <td rowspan="2"><span style="white-space: nowrap">AES_128</span></td>
+ *       <td><span style="white-space: nowrap">CBC</span><br><span style="white-space: nowrap">ECB</span></td>
+ *       <td><span style="white-space: nowrap">NoPadding</span><br><span style="white-space: nowrap">PKCS5Padding</span></td>
+ *       <td><span style="white-space: nowrap">26+</span></td>
+ *       <td></td>
+ *     </tr>
+ *     <tr>
+ *       <td><span style="white-space: nowrap">GCM</span></td>
+ *       <td><span style="white-space: nowrap">NoPadding</span></td>
+ *       <td><span style="white-space: nowrap">26+</span></td>
+ *       <td></td>
+ *     </tr>
+ *     <tr>
+ *       <td rowspan="2"><span style="white-space: nowrap">AES_256</span></td>
+ *       <td><span style="white-space: nowrap">CBC</span><br><span style="white-space: nowrap">ECB</span></td>
+ *       <td><span style="white-space: nowrap">NoPadding</span><br><span style="white-space: nowrap">PKCS5Padding</span></td>
+ *       <td><span style="white-space: nowrap">26+</span></td>
+ *       <td></td>
+ *     </tr>
+ *     <tr>
+ *       <td><span style="white-space: nowrap">GCM</span></td>
+ *       <td><span style="white-space: nowrap">NoPadding</span></td>
+ *       <td><span style="white-space: nowrap">26+</span></td>
+ *       <td></td>
+ *     </tr>
+ *     <tr>
+ *       <td rowspan="2"><span style="white-space: nowrap">ARC4</span></td>
+ *       <td><span style="white-space: nowrap">ECB</span></td>
+ *       <td><span style="white-space: nowrap">NoPadding</span></td>
+ *       <td><span style="white-space: nowrap">10+</span></td>
+ *       <td></td>
+ *     </tr>
+ *     <tr>
+ *       <td><span style="white-space: nowrap">NONE</span></td>
+ *       <td><span style="white-space: nowrap">NoPadding</span></td>
+ *       <td><span style="white-space: nowrap">28+</span></td>
+ *       <td></td>
+ *     </tr>
+ *     <tr>
+ *       <td><span style="white-space: nowrap">BLOWFISH</span></td>
+ *       <td><span style="white-space: nowrap">CBC</span><br><span style="white-space: nowrap">CFB</span><br><span style="white-space: nowrap">CTR</span><br><span style="white-space: nowrap">CTS</span><br><span style="white-space: nowrap">ECB</span><br><span style="white-space: nowrap">OFB</span></td>
+ *       <td><span style="white-space: nowrap">ISO10126Padding</span><br><span style="white-space: nowrap">NoPadding</span><br><span style="white-space: nowrap">PKCS5Padding</span></td>
+ *       <td><span style="white-space: nowrap">10+</span></td>
+ *       <td></td>
+ *     </tr>
+ *     <tr>
+ *       <td><span style="white-space: nowrap">ChaCha20</span></td>
+ *       <td><span style="white-space: nowrap">NONE</span><br><span style="white-space: nowrap">Poly1305</span></td>
+ *       <td><span style="white-space: nowrap">NoPadding</span></td>
+ *       <td><span style="white-space: nowrap">28+</span></td>
+ *       <td>ChaCha with 20 rounds, 96-bit nonce, and 32-bit counter as described in RFC 7539.</td>
+ *     </tr>
+ *     <tr>
+ *       <td><span style="white-space: nowrap">DES</span></td>
+ *       <td><span style="white-space: nowrap">CBC</span><br><span style="white-space: nowrap">CFB</span><br><span style="white-space: nowrap">CTR</span><br><span style="white-space: nowrap">CTS</span><br><span style="white-space: nowrap">ECB</span><br><span style="white-space: nowrap">OFB</span></td>
+ *       <td><span style="white-space: nowrap">ISO10126Padding</span><br><span style="white-space: nowrap">NoPadding</span><br><span style="white-space: nowrap">PKCS5Padding</span></td>
+ *       <td><span style="white-space: nowrap">1+</span></td>
+ *       <td></td>
+ *     </tr>
+ *     <tr>
+ *       <td><span style="white-space: nowrap">DESede</span></td>
+ *       <td><span style="white-space: nowrap">CBC</span><br><span style="white-space: nowrap">CFB</span><br><span style="white-space: nowrap">CTR</span><br><span style="white-space: nowrap">CTS</span><br><span style="white-space: nowrap">ECB</span><br><span style="white-space: nowrap">OFB</span></td>
+ *       <td><span style="white-space: nowrap">ISO10126Padding</span><br><span style="white-space: nowrap">NoPadding</span><br><span style="white-space: nowrap">PKCS5Padding</span></td>
+ *       <td><span style="white-space: nowrap">1+</span></td>
+ *       <td></td>
+ *     </tr>
+ *     <tr>
+ *       <td rowspan="3"><span style="white-space: nowrap">RSA</span></td>
+ *       <td rowspan="3"><span style="white-space: nowrap">ECB</span><br><span style="white-space: nowrap">NONE</span></td>
+ *       <td><span style="white-space: nowrap">NoPadding</span><br><span style="white-space: nowrap">OAEPPadding</span><br><span style="white-space: nowrap">PKCS1Padding</span></td>
+ *       <td><span style="white-space: nowrap">1+</span></td>
+ *       <td></td>
+ *     </tr>
+ *     <tr>
+ *       <td><span style="white-space: nowrap">OAEPwithSHA-1andMGF1Padding</span><br><span style="white-space: nowrap">OAEPwithSHA-256andMGF1Padding</span></td>
+ *       <td><span style="white-space: nowrap">10+</span></td>
+ *       <td></td>
+ *     </tr>
+ *     <tr>
+ *       <td><span style="white-space: nowrap">OAEPwithSHA-224andMGF1Padding</span><br><span style="white-space: nowrap">OAEPwithSHA-384andMGF1Padding</span><br><span style="white-space: nowrap">OAEPwithSHA-512andMGF1Padding</span></td>
+ *       <td><span style="white-space: nowrap">23+</span></td>
+ *       <td></td>
+ *     </tr>
+ *   </tbody>
+ * </table>
+ *
+ * These transformations are described in the
+ * <a href="{@docRoot}/../technotes/guides/security/StandardNames.html#Cipher">
+ * Cipher section</a> of the
+ * Java Cryptography Architecture Standard Algorithm Name Documentation.
+ *
+ * @author Jan Luehe
+ * @see KeyGenerator
+ * @see SecretKey
+ * @since 1.4
+ */
+
+public class Cipher {
+
+    // Android-note: Android reimplements provider selection.
+    //
+    // Android uses different provider/impl selection code than upstream does.  Provider
+    // selection permeates much of this class, so this class is forked significantly
+    // from the upstream version.  Not every change is marked, and any changes to upstream code
+    // should be evaluated to see if they should be merged.
+    //
+    // The changes are chiefly in construction (constructors, getInstance, and createCipher) and
+    // initialization (init and chooseProvider).  Most of the actual implementation is in the
+    // classes and methods at the bottom of this file.
+
+
+    // Android-removed: this debugging mechanism is not used in Android.
+    /*
+    private static final Debug debug =
+                        Debug.getInstance("jca", "Cipher");
+
+    private static final Debug pdebug =
+                        Debug.getInstance("provider", "Provider");
+    private static final boolean skipDebug =
+        Debug.isOn("engine=") && !Debug.isOn("cipher");
+    */
+
+    /**
+     * Constant used to initialize cipher to encryption mode.
+     */
+    public static final int ENCRYPT_MODE = 1;
+
+    /**
+     * Constant used to initialize cipher to decryption mode.
+     */
+    public static final int DECRYPT_MODE = 2;
+
+    /**
+     * Constant used to initialize cipher to key-wrapping mode.
+     */
+    public static final int WRAP_MODE = 3;
+
+    /**
+     * Constant used to initialize cipher to key-unwrapping mode.
+     */
+    public static final int UNWRAP_MODE = 4;
+
+    /**
+     * Constant used to indicate the to-be-unwrapped key is a "public key".
+     */
+    public static final int PUBLIC_KEY = 1;
+
+    /**
+     * Constant used to indicate the to-be-unwrapped key is a "private key".
+     */
+    public static final int PRIVATE_KEY = 2;
+
+    /**
+     * Constant used to indicate the to-be-unwrapped key is a "secret key".
+     */
+    public static final int SECRET_KEY = 3;
+
+    // The provider
+    private Provider provider;
+
+    // The provider implementation (delegate)
+    private CipherSpi spi;
+
+    // The transformation
+    // Android-changed: Made final.
+    final private String transformation;
+
+    // Android-added: Added tokenizedTransformation.
+    // The tokenized version of transformation
+    final private String[] tokenizedTransformation;
+
+    // Android-removed: Removed cryptoPerm.
+    /*
+    // Crypto permission representing the maximum allowable cryptographic
+    // strength that this Cipher object can be used for. (The cryptographic
+    // strength is a function of the keysize and algorithm parameters encoded
+    // in the crypto permission.)
+    private CryptoPermission cryptoPerm;
+    */
+
+    // The exemption mechanism that needs to be enforced
+    private ExemptionMechanism exmech;
+
+    // Flag which indicates whether or not this cipher has been initialized
+    private boolean initialized = false;
+
+    // The operation mode - store the operation mode after the
+    // cipher has been initialized.
+    private int opmode = 0;
+
+    // The OID for the KeyUsage extension in an X.509 v3 certificate
+    private static final String KEY_USAGE_EXTENSION_OID = "2.5.29.15";
+
+    // BEGIN Android-changed: Reimplement provider selection.
+    // See note at top of class.
+    private final SpiAndProviderUpdater spiAndProviderUpdater;
+    /*
+    // next SPI  to try in provider selection
+    // null once provider is selected
+    private CipherSpi firstSpi;
+
+    // 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;
+
+    // list of transform Strings to lookup in the provider
+    private List<Transform> transforms;
+
+    private final Object lock;
+    */
+    // END Android-changed: Reimplement provider selection.
+
+    /**
+     * Creates a Cipher object.
+     *
+     * @param cipherSpi the delegate
+     * @param provider the provider
+     * @param transformation the transformation
+     */
+    protected Cipher(CipherSpi cipherSpi,
+                     Provider provider,
+                     String transformation) {
+        if (cipherSpi == null) {
+            throw new NullPointerException("cipherSpi == null");
+        }
+        if (!(cipherSpi instanceof NullCipherSpi) && provider == null) {
+            throw new NullPointerException("provider == null");
+        }
+
+        this.spi = cipherSpi;
+        this.provider = provider;
+        this.transformation = transformation;
+        this.tokenizedTransformation = null;
+
+        this.spiAndProviderUpdater =
+            new SpiAndProviderUpdater(provider, cipherSpi);
+    }
+
+    private Cipher(CipherSpi cipherSpi,
+                   Provider provider,
+                   String transformation,
+                   String[] tokenizedTransformation) {
+        this.spi = cipherSpi;
+        this.provider = provider;
+        this.transformation = transformation;
+        this.tokenizedTransformation = tokenizedTransformation;
+
+        this.spiAndProviderUpdater =
+            new SpiAndProviderUpdater(provider, cipherSpi);
+    }
+
+    private static String[] tokenizeTransformation(String transformation)
+            throws NoSuchAlgorithmException {
+        if (transformation == null || transformation.isEmpty()) {
+            throw new NoSuchAlgorithmException("No transformation given");
+        }
+        /*
+         * array containing the components of a Cipher transformation:
+         *
+         * index 0: algorithm component (e.g., DES)
+         * index 1: feedback component (e.g., CFB)
+         * index 2: padding component (e.g., PKCS5Padding)
+         */
+        String[] parts = new String[3];
+        int count = 0;
+        StringTokenizer parser = new StringTokenizer(transformation, "/");
+        try {
+            while (parser.hasMoreTokens() && count < 3) {
+                parts[count++] = parser.nextToken().trim();
+            }
+            if (count == 0 || count == 2 || parser.hasMoreTokens()) {
+                throw new NoSuchAlgorithmException("Invalid transformation"
+                                               + " format:" +
+                                               transformation);
+            }
+        } catch (NoSuchElementException e) {
+            throw new NoSuchAlgorithmException("Invalid transformation " +
+                                           "format:" + transformation);
+        }
+        if ((parts[0] == null) || (parts[0].length() == 0)) {
+            throw new NoSuchAlgorithmException("Invalid transformation:" +
+                                   "algorithm not specified-"
+                                   + transformation);
+        }
+        return parts;
+    }
+
+    // BEGIN Android-removed: Reimplement provider selection.
+    // See note at top of class.
+    /*
+    // Provider attribute name for supported chaining mode
+    private final static String ATTR_MODE = "SupportedModes";
+    // Provider attribute name for supported padding names
+    private final static String ATTR_PAD  = "SupportedPaddings";
+
+    // constants indicating whether the provider supports
+    // a given mode or padding
+    private final static int S_NO    = 0;       // does not support
+    private final static int S_MAYBE = 1;       // unable to determine
+    private final static int S_YES   = 2;       // does support
+
+    /**
+     * Nested class to deal with modes and paddings.
+     *
+    private static class Transform {
+        // transform string to lookup in the provider
+        final String transform;
+        // the mode/padding suffix in upper case. for example, if the algorithm
+        // to lookup is "DES/CBC/PKCS5Padding" suffix is "/CBC/PKCS5PADDING"
+        // if loopup is "DES", suffix is the empty string
+        // needed because aliases prevent straight transform.equals()
+        final String suffix;
+        // value to pass to setMode() or null if no such call required
+        final String mode;
+        // value to pass to setPadding() or null if no such call required
+        final String pad;
+        Transform(String alg, String suffix, String mode, String pad) {
+            this.transform = alg + suffix;
+            this.suffix = suffix.toUpperCase(Locale.ENGLISH);
+            this.mode = mode;
+            this.pad = pad;
+        }
+        // set mode and padding for the given SPI
+        void setModePadding(CipherSpi spi) throws NoSuchAlgorithmException,
+                NoSuchPaddingException {
+            if (mode != null) {
+                spi.engineSetMode(mode);
+            }
+            if (pad != null) {
+                spi.engineSetPadding(pad);
+            }
+        }
+        // check whether the given services supports the mode and
+        // padding described by this Transform
+        int supportsModePadding(Service s) {
+            int smode = supportsMode(s);
+            if (smode == S_NO) {
+                return smode;
+            }
+            int spad = supportsPadding(s);
+            // our constants are defined so that Math.min() is a tri-valued AND
+            return Math.min(smode, spad);
+        }
+
+        // separate methods for mode and padding
+        // called directly by Cipher only to throw the correct exception
+        int supportsMode(Service s) {
+            return supports(s, ATTR_MODE, mode);
+        }
+        int supportsPadding(Service s) {
+            return supports(s, ATTR_PAD, pad);
+        }
+
+        private static int supports(Service s, String attrName, String value) {
+            if (value == null) {
+                return S_YES;
+            }
+            String regexp = s.getAttribute(attrName);
+            if (regexp == null) {
+                return S_MAYBE;
+            }
+            return matches(regexp, value) ? S_YES : S_NO;
+        }
+
+        // ConcurrentMap<String,Pattern> for previously compiled patterns
+        private final static ConcurrentMap<String, Pattern> patternCache =
+            new ConcurrentHashMap<String, Pattern>();
+
+        private static boolean matches(String regexp, String str) {
+            Pattern pattern = patternCache.get(regexp);
+            if (pattern == null) {
+                pattern = Pattern.compile(regexp);
+                patternCache.putIfAbsent(regexp, pattern);
+            }
+            return pattern.matcher(str.toUpperCase(Locale.ENGLISH)).matches();
+        }
+
+    }
+
+    private static List<Transform> getTransforms(String transformation)
+            throws NoSuchAlgorithmException {
+        String[] parts = tokenizeTransformation(transformation);
+
+        String alg = parts[0];
+        String mode = parts[1];
+        String pad = parts[2];
+        if ((mode != null) && (mode.length() == 0)) {
+            mode = null;
+        }
+        if ((pad != null) && (pad.length() == 0)) {
+            pad = null;
+        }
+
+        if ((mode == null) && (pad == null)) {
+            // DES
+            Transform tr = new Transform(alg, "", null, null);
+            return Collections.singletonList(tr);
+        } else { // if ((mode != null) && (pad != null)) {
+            // DES/CBC/PKCS5Padding
+            List<Transform> list = new ArrayList<>(4);
+            list.add(new Transform(alg, "/" + mode + "/" + pad, null, null));
+            list.add(new Transform(alg, "/" + mode, null, pad));
+            list.add(new Transform(alg, "//" + pad, mode, null));
+            list.add(new Transform(alg, "", mode, pad));
+            return list;
+        }
+    }
+
+    // get the transform matching the specified service
+    private static Transform getTransform(Service s,
+                                          List<Transform> transforms) {
+        String alg = s.getAlgorithm().toUpperCase(Locale.ENGLISH);
+        for (Transform tr : transforms) {
+            if (alg.endsWith(tr.suffix)) {
+                return tr;
+            }
+        }
+        return null;
+    }
+    */
+    // END Android-removed: Reimplement provider selection.
+
+    /**
+     * Returns a <code>Cipher</code> object that implements the specified
+     * transformation.
+     *
+     * <p> This method traverses the list of registered security Providers,
+     * starting with the most preferred Provider.
+     * A new Cipher object encapsulating the
+     * CipherSpi 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 transformation the name of the transformation, e.g.,
+     * <i>DES/CBC/PKCS5Padding</i>.
+     * 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 transformation names.
+     *
+     * @return a cipher that implements the requested transformation.
+     *
+     * @exception NoSuchAlgorithmException if <code>transformation</code>
+     *          is null, empty, in an invalid format,
+     *          or if no Provider supports a CipherSpi implementation for the
+     *          specified algorithm.
+     *
+     * @exception NoSuchPaddingException if <code>transformation</code>
+     *          contains a padding scheme that is not available.
+     *
+     * @see java.security.Provider
+     */
+    public static final Cipher getInstance(String transformation)
+            throws NoSuchAlgorithmException, NoSuchPaddingException
+    {
+        return createCipher(transformation, null);
+    }
+
+    /**
+     * Returns a <code>Cipher</code> object that implements the specified
+     * transformation.
+     *
+     * <p> A new Cipher object encapsulating the
+     * CipherSpi 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 transformation the name of the transformation,
+     * e.g., <i>DES/CBC/PKCS5Padding</i>.
+     * 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 transformation names.
+     *
+     * @param provider the name of the provider.
+     *
+     * @return a cipher that implements the requested transformation.
+     *
+     * @exception NoSuchAlgorithmException if <code>transformation</code>
+     *          is null, empty, in an invalid format,
+     *          or if a CipherSpi 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 NoSuchPaddingException if <code>transformation</code>
+     *          contains a padding scheme that is not available.
+     *
+     * @exception IllegalArgumentException if the <code>provider</code>
+     *          is null or empty.
+     *
+     * @see java.security.Provider
+     */
+    public static final Cipher getInstance(String transformation,
+                                           String provider)
+            throws NoSuchAlgorithmException, NoSuchProviderException,
+            NoSuchPaddingException
+    {
+        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 getInstance(transformation, p);
+    }
+
+    /**
+     * Returns a <code>Cipher</code> object that implements the specified
+     * transformation.
+     *
+     * <p> A new Cipher object encapsulating the
+     * CipherSpi 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 transformation the name of the transformation,
+     * e.g., <i>DES/CBC/PKCS5Padding</i>.
+     * 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 transformation names.
+     *
+     * @param provider the provider.
+     *
+     * @return a cipher that implements the requested transformation.
+     *
+     * @exception NoSuchAlgorithmException if <code>transformation</code>
+     *          is null, empty, in an invalid format,
+     *          or if a CipherSpi implementation for the specified algorithm
+     *          is not available from the specified Provider object.
+     *
+     * @exception NoSuchPaddingException if <code>transformation</code>
+     *          contains a padding scheme that is not available.
+     *
+     * @exception IllegalArgumentException if the <code>provider</code>
+     *          is null.
+     *
+     * @see java.security.Provider
+     */
+    public static final Cipher getInstance(String transformation,
+                                           Provider provider)
+            throws NoSuchAlgorithmException, NoSuchPaddingException
+    {
+        if (provider == null) {
+            throw new IllegalArgumentException("Missing provider");
+        }
+        return createCipher(transformation, provider);
+    }
+
+    static final Cipher createCipher(String transformation, Provider provider)
+        throws NoSuchAlgorithmException, NoSuchPaddingException {
+        Providers.checkBouncyCastleDeprecation(provider, "Cipher", transformation);
+        String[] tokenizedTransformation = tokenizeTransformation(transformation);
+
+        CipherSpiAndProvider cipherSpiAndProvider = null;
+        try {
+            cipherSpiAndProvider =
+                tryCombinations(null /*params*/, provider, tokenizedTransformation);
+        } catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
+            // Shouldn't happen.
+            throw new IllegalStateException("Key/Algorithm excepton despite not passing one", e);
+        }
+
+        if (cipherSpiAndProvider == null) {
+            if (provider == null) {
+                throw new NoSuchAlgorithmException("No provider found for " + transformation);
+            } else {
+                throw new NoSuchAlgorithmException("Provider " + provider.getName()
+                        + " does not provide " + transformation);
+            }
+        }
+
+        // exceptions and stuff
+        return new Cipher(null, provider, transformation, tokenizedTransformation);
+    }
+
+    /**
+     * Choose the Spi from the first provider available. Used if
+     * delayed provider selection is not possible because init()
+     * is not the first method called.
+     */
+    void updateProviderIfNeeded() {
+        try {
+            spiAndProviderUpdater.updateAndGetSpiAndProvider(null, spi, provider);
+        } catch (Exception lastException) {
+            ProviderException e = new ProviderException
+                    ("Could not construct CipherSpi instance");
+            if (lastException != null) {
+                e.initCause(lastException);
+            }
+            throw e;
+        }
+    }
+
+    private void chooseProvider(InitType initType, int opmode, Key key,
+            AlgorithmParameterSpec paramSpec,
+            AlgorithmParameters params, SecureRandom random)
+            throws InvalidKeyException, InvalidAlgorithmParameterException {
+
+        try {
+            final InitParams initParams = new InitParams(initType, opmode, key, random,
+                                                         paramSpec, params);
+            spiAndProviderUpdater.updateAndGetSpiAndProvider(initParams, spi, provider);
+        } catch (Exception lastException) {
+            // no working provider found, fail
+            if (lastException instanceof InvalidKeyException) {
+                throw (InvalidKeyException)lastException;
+            }
+            if (lastException instanceof InvalidAlgorithmParameterException) {
+                throw (InvalidAlgorithmParameterException)lastException;
+            }
+            if (lastException instanceof RuntimeException) {
+                throw (RuntimeException)lastException;
+            }
+            String kName = (key != null) ? key.getClass().getName() : "(null)";
+            throw new InvalidKeyException
+                ("No installed provider supports this key: "
+                + kName, lastException);
+        }
+    }
+
+    /**
+     * Returns the provider of this <code>Cipher</code> object.
+     *
+     * @return the provider of this <code>Cipher</code> object
+     */
+    public final Provider getProvider() {
+        updateProviderIfNeeded();
+        return this.provider;
+    }
+
+    /**
+     * Returns the algorithm name of this <code>Cipher</code> object.
+     *
+     * <p>This is the same name that was specified in one of the
+     * <code>getInstance</code> calls that created this <code>Cipher</code>
+     * object..
+     *
+     * @return the algorithm name of this <code>Cipher</code> object.
+     */
+    public final String getAlgorithm() {
+        return this.transformation;
+    }
+
+    /**
+     * Returns the block size (in bytes).
+     *
+     * @return the block size (in bytes), or 0 if the underlying algorithm is
+     * not a block cipher
+     */
+    public final int getBlockSize() {
+        updateProviderIfNeeded();
+        return spi.engineGetBlockSize();
+    }
+
+    /**
+     * Returns the length in bytes that an output buffer would need to be in
+     * order to hold the result of the next <code>update</code> or
+     * <code>doFinal</code> operation, given the input length
+     * <code>inputLen</code> (in bytes).
+     *
+     * <p>This call takes into account any unprocessed (buffered) data from a
+     * previous <code>update</code> call, padding, and AEAD tagging.
+     *
+     * <p>The actual output length of the next <code>update</code> or
+     * <code>doFinal</code> call may be smaller than the length returned by
+     * this method.
+     *
+     * @param inputLen the input length (in bytes)
+     *
+     * @return the required output buffer size (in bytes)
+     *
+     * @exception IllegalStateException if this cipher is in a wrong state
+     * (e.g., has not yet been initialized)
+     */
+    public final int getOutputSize(int inputLen) {
+
+        if (!initialized && !(this instanceof NullCipher)) {
+            throw new IllegalStateException("Cipher not initialized");
+        }
+        if (inputLen < 0) {
+            throw new IllegalArgumentException("Input size must be equal " +
+                                               "to or greater than zero");
+        }
+        updateProviderIfNeeded();
+        return spi.engineGetOutputSize(inputLen);
+    }
+
+    /**
+     * Returns the initialization vector (IV) in a new buffer.
+     *
+     * <p>This is useful in the case where a random IV was created,
+     * or in the context of password-based encryption or
+     * decryption, where the IV is derived from a user-supplied password.
+     *
+     * @return the initialization vector in a new buffer, or null if the
+     * underlying algorithm does not use an IV, or if the IV has not yet
+     * been set.
+     */
+    public final byte[] getIV() {
+        updateProviderIfNeeded();
+        return spi.engineGetIV();
+    }
+
+    /**
+     * Returns the parameters used with this cipher.
+     *
+     * <p>The returned parameters may be the same that were used to initialize
+     * this cipher, or may contain a combination of default and random
+     * parameter values used by the underlying cipher implementation if this
+     * cipher requires algorithm parameters but was not initialized with any.
+     *
+     * @return the parameters used with this cipher, or null if this cipher
+     * does not use any parameters.
+     */
+    public final AlgorithmParameters getParameters() {
+        updateProviderIfNeeded();
+        return spi.engineGetParameters();
+    }
+
+    /**
+     * Returns the exemption mechanism object used with this cipher.
+     *
+     * @return the exemption mechanism object used with this cipher, or
+     * null if this cipher does not use any exemption mechanism.
+     */
+    public final ExemptionMechanism getExemptionMechanism() {
+        updateProviderIfNeeded();
+        return exmech;
+    }
+
+    // BEGIN Android-removed: Eliminate crypto permission checking.
+    // Android doesn't implement SecurityManager permissions.
+    /*
+    //
+    // Crypto permission check code below
+    //
+    private void checkCryptoPerm(CipherSpi checkSpi, Key key)
+            throws InvalidKeyException {
+        if (cryptoPerm == CryptoAllPermission.INSTANCE) {
+            return;
+        }
+        // Check if key size and default parameters are within legal limits
+        AlgorithmParameterSpec params;
+        try {
+            params = getAlgorithmParameterSpec(checkSpi.engineGetParameters());
+        } catch (InvalidParameterSpecException ipse) {
+            throw new InvalidKeyException
+                ("Unsupported default algorithm parameters");
+        }
+        if (!passCryptoPermCheck(checkSpi, key, params)) {
+            throw new InvalidKeyException(
+                "Illegal key size or default parameters");
+        }
+    }
+
+    private void checkCryptoPerm(CipherSpi checkSpi, Key key,
+            AlgorithmParameterSpec params) throws InvalidKeyException,
+            InvalidAlgorithmParameterException {
+        if (cryptoPerm == CryptoAllPermission.INSTANCE) {
+            return;
+        }
+        // Determine keysize and check if it is within legal limits
+        if (!passCryptoPermCheck(checkSpi, key, null)) {
+            throw new InvalidKeyException("Illegal key size");
+        }
+        if ((params != null) && (!passCryptoPermCheck(checkSpi, key, params))) {
+            throw new InvalidAlgorithmParameterException("Illegal parameters");
+        }
+    }
+
+    private void checkCryptoPerm(CipherSpi checkSpi, Key key,
+            AlgorithmParameters params)
+            throws InvalidKeyException, InvalidAlgorithmParameterException {
+        if (cryptoPerm == CryptoAllPermission.INSTANCE) {
+            return;
+        }
+        // Convert the specified parameters into specs and then delegate.
+        AlgorithmParameterSpec pSpec;
+        try {
+            pSpec = getAlgorithmParameterSpec(params);
+        } catch (InvalidParameterSpecException ipse) {
+            throw new InvalidAlgorithmParameterException
+                ("Failed to retrieve algorithm parameter specification");
+        }
+        checkCryptoPerm(checkSpi, key, pSpec);
+    }
+
+    private boolean passCryptoPermCheck(CipherSpi checkSpi, Key key,
+                                        AlgorithmParameterSpec params)
+            throws InvalidKeyException {
+        String em = cryptoPerm.getExemptionMechanism();
+        int keySize = checkSpi.engineGetKeySize(key);
+        // Use the "algorithm" component of the cipher
+        // transformation so that the perm check would
+        // work when the key has the "aliased" algo.
+        String algComponent;
+        int index = transformation.indexOf('/');
+        if (index != -1) {
+            algComponent = transformation.substring(0, index);
+        } else {
+            algComponent = transformation;
+        }
+        CryptoPermission checkPerm =
+            new CryptoPermission(algComponent, keySize, params, em);
+
+        if (!cryptoPerm.implies(checkPerm)) {
+            if (debug != null) {
+                debug.println("Crypto Permission check failed");
+                debug.println("granted: " + cryptoPerm);
+                debug.println("requesting: " + checkPerm);
+            }
+            return false;
+        }
+        if (exmech == null) {
+            return true;
+        }
+        try {
+            if (!exmech.isCryptoAllowed(key)) {
+                if (debug != null) {
+                    debug.println(exmech.getName() + " isn't enforced");
+                }
+                return false;
+            }
+        } catch (ExemptionMechanismException eme) {
+            if (debug != null) {
+                debug.println("Cannot determine whether "+
+                              exmech.getName() + " has been enforced");
+                eme.printStackTrace();
+            }
+            return false;
+        }
+        return true;
+    }
+    */
+    // END Android-removed: Eliminate crypto permission checking.
+
+    // check if opmode is one of the defined constants
+    // throw InvalidParameterExeption if not
+    private static void checkOpmode(int opmode) {
+        if ((opmode < ENCRYPT_MODE) || (opmode > UNWRAP_MODE)) {
+            throw new InvalidParameterException("Invalid operation mode");
+        }
+    }
+
+    private static String getOpmodeString(int opmode) {
+        switch (opmode) {
+            case ENCRYPT_MODE:
+                return "encryption";
+            case DECRYPT_MODE:
+                return "decryption";
+            case WRAP_MODE:
+                return "key wrapping";
+            case UNWRAP_MODE:
+                return "key unwrapping";
+            default:
+                return "";
+        }
+    }
+
+    /**
+     * Initializes this cipher with a key.
+     *
+     * <p>The cipher is initialized for one of the following four operations:
+     * encryption, decryption, key wrapping or key unwrapping, depending
+     * on the value of <code>opmode</code>.
+     *
+     * <p>If this cipher requires any algorithm parameters that cannot be
+     * derived from the given <code>key</code>, the underlying cipher
+     * implementation is supposed to generate the required parameters itself
+     * (using provider-specific default or random values) if it is being
+     * initialized for encryption or key wrapping, and raise an
+     * <code>InvalidKeyException</code> if it is being
+     * initialized for decryption or key unwrapping.
+     * The generated parameters can be retrieved using
+     * {@link #getParameters() getParameters} or
+     * {@link #getIV() getIV} (if the parameter is an IV).
+     *
+     * <p>If this cipher requires algorithm parameters that cannot be
+     * derived from the input parameters, and there are no reasonable
+     * provider-specific default values, initialization will
+     * necessarily fail.
+     *
+     * <p>If this cipher (including its underlying feedback or padding scheme)
+     * requires any random bytes (e.g., for parameter generation), it will get
+     * them using the {@link java.security.SecureRandom}
+     * implementation of the highest-priority
+     * installed provider as the source of randomness.
+     * (If none of the installed providers supply an implementation of
+     * SecureRandom, a system-provided source of randomness will be used.)
+     *
+     * <p>Note that when a Cipher object is initialized, it loses all
+     * previously-acquired state. In other words, initializing a Cipher is
+     * equivalent to creating a new instance of that Cipher and initializing
+     * it.
+     *
+     * @param opmode the operation mode of this cipher (this is one of
+     * the following:
+     * <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,
+     * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)
+     * @param key the key
+     *
+     * @exception InvalidKeyException if the given key is inappropriate for
+     * initializing this cipher, or requires
+     * algorithm parameters that cannot be
+     * determined from the given key, or if the given key has a keysize that
+     * exceeds the maximum allowable keysize (as determined from the
+     * configured jurisdiction policy files).
+     * @throws UnsupportedOperationException if (@code opmode} is
+     * {@code WRAP_MODE} or {@code UNWRAP_MODE} but the mode is not implemented
+     * by the underlying {@code CipherSpi}.
+     */
+    public final void init(int opmode, Key key) throws InvalidKeyException {
+        init(opmode, key, JceSecurity.RANDOM);
+    }
+
+    /**
+     * Initializes this cipher with a key and a source of randomness.
+     *
+     * <p>The cipher is initialized for one of the following four operations:
+     * encryption, decryption, key wrapping or  key unwrapping, depending
+     * on the value of <code>opmode</code>.
+     *
+     * <p>If this cipher requires any algorithm parameters that cannot be
+     * derived from the given <code>key</code>, the underlying cipher
+     * implementation is supposed to generate the required parameters itself
+     * (using provider-specific default or random values) if it is being
+     * initialized for encryption or key wrapping, and raise an
+     * <code>InvalidKeyException</code> if it is being
+     * initialized for decryption or key unwrapping.
+     * The generated parameters can be retrieved using
+     * {@link #getParameters() getParameters} or
+     * {@link #getIV() getIV} (if the parameter is an IV).
+     *
+     * <p>If this cipher requires algorithm parameters that cannot be
+     * derived from the input parameters, and there are no reasonable
+     * provider-specific default values, initialization will
+     * necessarily fail.
+     *
+     * <p>If this cipher (including its underlying feedback or padding scheme)
+     * requires any random bytes (e.g., for parameter generation), it will get
+     * them from <code>random</code>.
+     *
+     * <p>Note that when a Cipher object is initialized, it loses all
+     * previously-acquired state. In other words, initializing a Cipher is
+     * equivalent to creating a new instance of that Cipher and initializing
+     * it.
+     *
+     * @param opmode the operation mode of this cipher (this is one of the
+     * following:
+     * <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,
+     * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)
+     * @param key the encryption key
+     * @param random the source of randomness
+     *
+     * @exception InvalidKeyException if the given key is inappropriate for
+     * initializing this cipher, or requires
+     * algorithm parameters that cannot be
+     * determined from the given key, or if the given key has a keysize that
+     * exceeds the maximum allowable keysize (as determined from the
+     * configured jurisdiction policy files).
+     * @throws UnsupportedOperationException if (@code opmode} is
+     * {@code WRAP_MODE} or {@code UNWRAP_MODE} but the mode is not implemented
+     * by the underlying {@code CipherSpi}.
+     */
+    public final void init(int opmode, Key key, SecureRandom random)
+            throws InvalidKeyException
+    {
+        initialized = false;
+        checkOpmode(opmode);
+
+        try {
+            chooseProvider(InitType.KEY, opmode, key, null, null, random);
+        } catch (InvalidAlgorithmParameterException e) {
+            // should never occur
+            throw new InvalidKeyException(e);
+        }
+
+        initialized = true;
+        this.opmode = opmode;
+
+        // Android-removed: this debugging mechanism is not used in Android.
+        /*
+        if (!skipDebug && pdebug != null) {
+            pdebug.println("Cipher." + transformation + " " +
+                getOpmodeString(opmode) + " algorithm from: " +
+                this.provider.getName());
+        }
+        */
+    }
+
+    /**
+     * Initializes this cipher with a key and a set of algorithm
+     * parameters.
+     *
+     * <p>The cipher is initialized for one of the following four operations:
+     * encryption, decryption, key wrapping or  key unwrapping, depending
+     * on the value of <code>opmode</code>.
+     *
+     * <p>If this cipher requires any algorithm parameters and
+     * <code>params</code> is null, the underlying cipher implementation is
+     * supposed to generate the required parameters itself (using
+     * provider-specific default or random values) if it is being
+     * initialized for encryption or key wrapping, and raise an
+     * <code>InvalidAlgorithmParameterException</code> if it is being
+     * initialized for decryption or key unwrapping.
+     * The generated parameters can be retrieved using
+     * {@link #getParameters() getParameters} or
+     * {@link #getIV() getIV} (if the parameter is an IV).
+     *
+     * <p>If this cipher requires algorithm parameters that cannot be
+     * derived from the input parameters, and there are no reasonable
+     * provider-specific default values, initialization will
+     * necessarily fail.
+     *
+     * <p>If this cipher (including its underlying feedback or padding scheme)
+     * requires any random bytes (e.g., for parameter generation), it will get
+     * them using the {@link java.security.SecureRandom}
+     * implementation of the highest-priority
+     * installed provider as the source of randomness.
+     * (If none of the installed providers supply an implementation of
+     * SecureRandom, a system-provided source of randomness will be used.)
+     *
+     * <p>Note that when a Cipher object is initialized, it loses all
+     * previously-acquired state. In other words, initializing a Cipher is
+     * equivalent to creating a new instance of that Cipher and initializing
+     * it.
+     *
+     * @param opmode the operation mode of this cipher (this is one of the
+     * following:
+     * <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,
+     * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)
+     * @param key the encryption key
+     * @param params the algorithm parameters
+     *
+     * @exception InvalidKeyException if the given key is inappropriate for
+     * initializing this cipher, or its keysize exceeds the maximum allowable
+     * keysize (as determined from the configured jurisdiction policy files).
+     * @exception InvalidAlgorithmParameterException if the given algorithm
+     * parameters are inappropriate for this cipher,
+     * or this cipher requires
+     * algorithm parameters and <code>params</code> is null, or the given
+     * algorithm parameters imply a cryptographic strength that would exceed
+     * the legal limits (as determined from the configured jurisdiction
+     * policy files).
+     * @throws UnsupportedOperationException if (@code opmode} is
+     * {@code WRAP_MODE} or {@code UNWRAP_MODE} but the mode is not implemented
+     * by the underlying {@code CipherSpi}.
+     */
+    public final void init(int opmode, Key key, AlgorithmParameterSpec params)
+            throws InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        init(opmode, key, params, JceSecurity.RANDOM);
+    }
+
+    /**
+     * Initializes this cipher with a key, a set of algorithm
+     * parameters, and a source of randomness.
+     *
+     * <p>The cipher is initialized for one of the following four operations:
+     * encryption, decryption, key wrapping or  key unwrapping, depending
+     * on the value of <code>opmode</code>.
+     *
+     * <p>If this cipher requires any algorithm parameters and
+     * <code>params</code> is null, the underlying cipher implementation is
+     * supposed to generate the required parameters itself (using
+     * provider-specific default or random values) if it is being
+     * initialized for encryption or key wrapping, and raise an
+     * <code>InvalidAlgorithmParameterException</code> if it is being
+     * initialized for decryption or key unwrapping.
+     * The generated parameters can be retrieved using
+     * {@link #getParameters() getParameters} or
+     * {@link #getIV() getIV} (if the parameter is an IV).
+     *
+     * <p>If this cipher requires algorithm parameters that cannot be
+     * derived from the input parameters, and there are no reasonable
+     * provider-specific default values, initialization will
+     * necessarily fail.
+     *
+     * <p>If this cipher (including its underlying feedback or padding scheme)
+     * requires any random bytes (e.g., for parameter generation), it will get
+     * them from <code>random</code>.
+     *
+     * <p>Note that when a Cipher object is initialized, it loses all
+     * previously-acquired state. In other words, initializing a Cipher is
+     * equivalent to creating a new instance of that Cipher and initializing
+     * it.
+     *
+     * @param opmode the operation mode of this cipher (this is one of the
+     * following:
+     * <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,
+     * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)
+     * @param key the encryption key
+     * @param params the algorithm parameters
+     * @param random the source of randomness
+     *
+     * @exception InvalidKeyException if the given key is inappropriate for
+     * initializing this cipher, or its keysize exceeds the maximum allowable
+     * keysize (as determined from the configured jurisdiction policy files).
+     * @exception InvalidAlgorithmParameterException if the given algorithm
+     * parameters are inappropriate for this cipher,
+     * or this cipher requires
+     * algorithm parameters and <code>params</code> is null, or the given
+     * algorithm parameters imply a cryptographic strength that would exceed
+     * the legal limits (as determined from the configured jurisdiction
+     * policy files).
+     * @throws UnsupportedOperationException if (@code opmode} is
+     * {@code WRAP_MODE} or {@code UNWRAP_MODE} but the mode is not implemented
+     * by the underlying {@code CipherSpi}.
+     */
+    public final void init(int opmode, Key key, AlgorithmParameterSpec params,
+                           SecureRandom random)
+            throws InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        initialized = false;
+        checkOpmode(opmode);
+
+        chooseProvider(InitType.ALGORITHM_PARAM_SPEC, opmode, key, params, null, random);
+
+        initialized = true;
+        this.opmode = opmode;
+
+        // Android-removed: this debugging mechanism is not used in Android.
+        /*
+        if (!skipDebug && pdebug != null) {
+            pdebug.println("Cipher." + transformation + " " +
+                getOpmodeString(opmode) + " algorithm from: " +
+                this.provider.getName());
+        }
+        */
+    }
+
+    /**
+     * Initializes this cipher with a key and a set of algorithm
+     * parameters.
+     *
+     * <p>The cipher is initialized for one of the following four operations:
+     * encryption, decryption, key wrapping or  key unwrapping, depending
+     * on the value of <code>opmode</code>.
+     *
+     * <p>If this cipher requires any algorithm parameters and
+     * <code>params</code> is null, the underlying cipher implementation is
+     * supposed to generate the required parameters itself (using
+     * provider-specific default or random values) if it is being
+     * initialized for encryption or key wrapping, and raise an
+     * <code>InvalidAlgorithmParameterException</code> if it is being
+     * initialized for decryption or key unwrapping.
+     * The generated parameters can be retrieved using
+     * {@link #getParameters() getParameters} or
+     * {@link #getIV() getIV} (if the parameter is an IV).
+     *
+     * <p>If this cipher requires algorithm parameters that cannot be
+     * derived from the input parameters, and there are no reasonable
+     * provider-specific default values, initialization will
+     * necessarily fail.
+     *
+     * <p>If this cipher (including its underlying feedback or padding scheme)
+     * requires any random bytes (e.g., for parameter generation), it will get
+     * them using the {@link java.security.SecureRandom}
+     * implementation of the highest-priority
+     * installed provider as the source of randomness.
+     * (If none of the installed providers supply an implementation of
+     * SecureRandom, a system-provided source of randomness will be used.)
+     *
+     * <p>Note that when a Cipher object is initialized, it loses all
+     * previously-acquired state. In other words, initializing a Cipher is
+     * equivalent to creating a new instance of that Cipher and initializing
+     * it.
+     *
+     * @param opmode the operation mode of this cipher (this is one of the
+     * following: <code>ENCRYPT_MODE</code>,
+     * <code>DECRYPT_MODE</code>, <code>WRAP_MODE</code>
+     * or <code>UNWRAP_MODE</code>)
+     * @param key the encryption key
+     * @param params the algorithm parameters
+     *
+     * @exception InvalidKeyException if the given key is inappropriate for
+     * initializing this cipher, or its keysize exceeds the maximum allowable
+     * keysize (as determined from the configured jurisdiction policy files).
+     * @exception InvalidAlgorithmParameterException if the given algorithm
+     * parameters are inappropriate for this cipher,
+     * or this cipher requires
+     * algorithm parameters and <code>params</code> is null, or the given
+     * algorithm parameters imply a cryptographic strength that would exceed
+     * the legal limits (as determined from the configured jurisdiction
+     * policy files).
+     * @throws UnsupportedOperationException if (@code opmode} is
+     * {@code WRAP_MODE} or {@code UNWRAP_MODE} but the mode is not implemented
+     * by the underlying {@code CipherSpi}.
+     */
+    public final void init(int opmode, Key key, AlgorithmParameters params)
+            throws InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        init(opmode, key, params, JceSecurity.RANDOM);
+    }
+
+    /**
+     * Initializes this cipher with a key, a set of algorithm
+     * parameters, and a source of randomness.
+     *
+     * <p>The cipher is initialized for one of the following four operations:
+     * encryption, decryption, key wrapping or  key unwrapping, depending
+     * on the value of <code>opmode</code>.
+     *
+     * <p>If this cipher requires any algorithm parameters and
+     * <code>params</code> is null, the underlying cipher implementation is
+     * supposed to generate the required parameters itself (using
+     * provider-specific default or random values) if it is being
+     * initialized for encryption or key wrapping, and raise an
+     * <code>InvalidAlgorithmParameterException</code> if it is being
+     * initialized for decryption or key unwrapping.
+     * The generated parameters can be retrieved using
+     * {@link #getParameters() getParameters} or
+     * {@link #getIV() getIV} (if the parameter is an IV).
+     *
+     * <p>If this cipher requires algorithm parameters that cannot be
+     * derived from the input parameters, and there are no reasonable
+     * provider-specific default values, initialization will
+     * necessarily fail.
+     *
+     * <p>If this cipher (including its underlying feedback or padding scheme)
+     * requires any random bytes (e.g., for parameter generation), it will get
+     * them from <code>random</code>.
+     *
+     * <p>Note that when a Cipher object is initialized, it loses all
+     * previously-acquired state. In other words, initializing a Cipher is
+     * equivalent to creating a new instance of that Cipher and initializing
+     * it.
+     *
+     * @param opmode the operation mode of this cipher (this is one of the
+     * following: <code>ENCRYPT_MODE</code>,
+     * <code>DECRYPT_MODE</code>, <code>WRAP_MODE</code>
+     * or <code>UNWRAP_MODE</code>)
+     * @param key the encryption key
+     * @param params the algorithm parameters
+     * @param random the source of randomness
+     *
+     * @exception InvalidKeyException if the given key is inappropriate for
+     * initializing this cipher, or its keysize exceeds the maximum allowable
+     * keysize (as determined from the configured jurisdiction policy files).
+     * @exception InvalidAlgorithmParameterException if the given algorithm
+     * parameters are inappropriate for this cipher,
+     * or this cipher requires
+     * algorithm parameters and <code>params</code> is null, or the given
+     * algorithm parameters imply a cryptographic strength that would exceed
+     * the legal limits (as determined from the configured jurisdiction
+     * policy files).
+     * @throws UnsupportedOperationException if (@code opmode} is
+     * {@code WRAP_MODE} or {@code UNWRAP_MODE} but the mode is not implemented
+     * by the underlying {@code CipherSpi}.
+     */
+    public final void init(int opmode, Key key, AlgorithmParameters params,
+                           SecureRandom random)
+            throws InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        initialized = false;
+        checkOpmode(opmode);
+
+        chooseProvider(InitType.ALGORITHM_PARAMS, opmode, key, null, params, random);
+
+        initialized = true;
+        this.opmode = opmode;
+
+        // Android-removed: this debugging mechanism is not used in Android.
+        /*
+        if (!skipDebug && pdebug != null) {
+            pdebug.println("Cipher." + transformation + " " +
+                getOpmodeString(opmode) + " algorithm from: " +
+                this.provider.getName());
+        }
+        */
+    }
+
+    /**
+     * Initializes this cipher with the public key from the given certificate.
+     * <p> The cipher is initialized for one of the following four operations:
+     * encryption, decryption, key wrapping or  key unwrapping, depending
+     * on the value of <code>opmode</code>.
+     *
+     * <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 the operation represented by the value
+     * of <code>opmode</code>,
+     * an <code>InvalidKeyException</code>
+     * is thrown.
+     *
+     * <p> If this cipher requires any algorithm parameters that cannot be
+     * derived from the public key in the given certificate, the underlying
+     * cipher
+     * implementation is supposed to generate the required parameters itself
+     * (using provider-specific default or random values) if it is being
+     * initialized for encryption or key wrapping, and raise an <code>
+     * InvalidKeyException</code> if it is being initialized for decryption or
+     * key unwrapping.
+     * The generated parameters can be retrieved using
+     * {@link #getParameters() getParameters} or
+     * {@link #getIV() getIV} (if the parameter is an IV).
+     *
+     * <p>If this cipher requires algorithm parameters that cannot be
+     * derived from the input parameters, and there are no reasonable
+     * provider-specific default values, initialization will
+     * necessarily fail.
+     *
+     * <p>If this cipher (including its underlying feedback or padding scheme)
+     * requires any random bytes (e.g., for parameter generation), it will get
+     * them using the
+     * <code>SecureRandom</code>
+     * implementation of the highest-priority
+     * installed provider as the source of randomness.
+     * (If none of the installed providers supply an implementation of
+     * SecureRandom, a system-provided source of randomness will be used.)
+     *
+     * <p>Note that when a Cipher object is initialized, it loses all
+     * previously-acquired state. In other words, initializing a Cipher is
+     * equivalent to creating a new instance of that Cipher and initializing
+     * it.
+     *
+     * @param opmode the operation mode of this cipher (this is one of the
+     * following:
+     * <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,
+     * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)
+     * @param certificate the certificate
+     *
+     * @exception InvalidKeyException if the public key in the given
+     * certificate is inappropriate for initializing this cipher, or this
+     * cipher requires algorithm parameters that cannot be determined from the
+     * public key in the given certificate, or the keysize of the public key
+     * in the given certificate has a keysize that exceeds the maximum
+     * allowable keysize (as determined by the configured jurisdiction policy
+     * files).
+     * @throws UnsupportedOperationException if (@code opmode} is
+     * {@code WRAP_MODE} or {@code UNWRAP_MODE} but the mode is not implemented
+     * by the underlying {@code CipherSpi}.
+     */
+    public final void init(int opmode, Certificate certificate)
+            throws InvalidKeyException
+    {
+        init(opmode, certificate, JceSecurity.RANDOM);
+    }
+
+    /**
+     * Initializes this cipher with the public key from the given certificate
+     * and
+     * a source of randomness.
+     *
+     * <p>The cipher is initialized for one of the following four operations:
+     * encryption, decryption, key wrapping
+     * or key unwrapping, depending on
+     * the value of <code>opmode</code>.
+     *
+     * <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 the operation represented by the value of
+     * <code>opmode</code>,
+     * an <code>InvalidKeyException</code>
+     * is thrown.
+     *
+     * <p>If this cipher requires any algorithm parameters that cannot be
+     * derived from the public key in the given <code>certificate</code>,
+     * the underlying cipher
+     * implementation is supposed to generate the required parameters itself
+     * (using provider-specific default or random values) if it is being
+     * initialized for encryption or key wrapping, and raise an
+     * <code>InvalidKeyException</code> if it is being
+     * initialized for decryption or key unwrapping.
+     * The generated parameters can be retrieved using
+     * {@link #getParameters() getParameters} or
+     * {@link #getIV() getIV} (if the parameter is an IV).
+     *
+     * <p>If this cipher requires algorithm parameters that cannot be
+     * derived from the input parameters, and there are no reasonable
+     * provider-specific default values, initialization will
+     * necessarily fail.
+     *
+     * <p>If this cipher (including its underlying feedback or padding scheme)
+     * requires any random bytes (e.g., for parameter generation), it will get
+     * them from <code>random</code>.
+     *
+     * <p>Note that when a Cipher object is initialized, it loses all
+     * previously-acquired state. In other words, initializing a Cipher is
+     * equivalent to creating a new instance of that Cipher and initializing
+     * it.
+     *
+     * @param opmode the operation mode of this cipher (this is one of the
+     * following:
+     * <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,
+     * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)
+     * @param certificate the certificate
+     * @param random the source of randomness
+     *
+     * @exception InvalidKeyException if the public key in the given
+     * certificate is inappropriate for initializing this cipher, or this
+     * cipher
+     * requires algorithm parameters that cannot be determined from the
+     * public key in the given certificate, or the keysize of the public key
+     * in the given certificate has a keysize that exceeds the maximum
+     * allowable keysize (as determined by the configured jurisdiction policy
+     * files).
+     * @throws UnsupportedOperationException if (@code opmode} is
+     * {@code WRAP_MODE} or {@code UNWRAP_MODE} but the mode is not implemented
+     * by the underlying {@code CipherSpi}.
+     */
+    public final void init(int opmode, Certificate certificate,
+                           SecureRandom random)
+            throws InvalidKeyException
+    {
+        initialized = false;
+        checkOpmode(opmode);
+
+        // Check key usage if the certificate is of
+        // type X.509.
+        if (certificate instanceof java.security.cert.X509Certificate) {
+            // Check whether the cert has a key usage extension
+            // marked as a critical extension.
+            X509Certificate cert = (X509Certificate)certificate;
+            Set<String> critSet = cert.getCriticalExtensionOIDs();
+
+            if (critSet != null && !critSet.isEmpty()
+                && critSet.contains(KEY_USAGE_EXTENSION_OID)) {
+                boolean[] keyUsageInfo = cert.getKeyUsage();
+                // keyUsageInfo[2] is for keyEncipherment;
+                // keyUsageInfo[3] is for dataEncipherment.
+                if ((keyUsageInfo != null) &&
+                    (((opmode == Cipher.ENCRYPT_MODE) &&
+                      (keyUsageInfo.length > 3) &&
+                      (keyUsageInfo[3] == false)) ||
+                     ((opmode == Cipher.WRAP_MODE) &&
+                      (keyUsageInfo.length > 2) &&
+                      (keyUsageInfo[2] == false)))) {
+                    throw new InvalidKeyException("Wrong key usage");
+                }
+            }
+        }
+
+        PublicKey publicKey =
+            (certificate==null? null:certificate.getPublicKey());
+
+        try {
+            chooseProvider(InitType.KEY, opmode, (Key) publicKey, null, null, random);
+        } catch (InvalidAlgorithmParameterException e) {
+            // should never occur
+            throw new InvalidKeyException(e);
+        }
+
+        initialized = true;
+        this.opmode = opmode;
+
+        // Android-removed: this debugging mechanism is not used in Android.
+        /*
+        if (!skipDebug && pdebug != null) {
+            pdebug.println("Cipher." + transformation + " " +
+                getOpmodeString(opmode) + " algorithm from: " +
+                this.provider.getName());
+        }
+        */
+    }
+
+    /**
+     * Ensures that Cipher is in a valid state for update() and doFinal()
+     * calls - should be initialized and in ENCRYPT_MODE or DECRYPT_MODE.
+     * @throws IllegalStateException if Cipher object is not in valid state.
+     */
+    private void checkCipherState() {
+        if (!(this instanceof NullCipher)) {
+            if (!initialized) {
+                throw new IllegalStateException("Cipher not initialized");
+            }
+            if ((opmode != Cipher.ENCRYPT_MODE) &&
+                (opmode != Cipher.DECRYPT_MODE)) {
+                throw new IllegalStateException("Cipher not initialized " +
+                                                "for encryption/decryption");
+            }
+        }
+    }
+
+    /**
+     * Continues a multiple-part encryption or decryption operation
+     * (depending on how this cipher was initialized), processing another data
+     * part.
+     *
+     * <p>The bytes in the <code>input</code> buffer are processed, and the
+     * result is stored in a new buffer.
+     *
+     * <p>If <code>input</code> has a length of zero, this method returns
+     * <code>null</code>.
+     *
+     * @param input the input buffer
+     *
+     * @return the new buffer with the result, or null if the underlying
+     * cipher is a block cipher and the input data is too short to result in a
+     * new block.
+     *
+     * @exception IllegalStateException if this cipher is in a wrong state
+     * (e.g., has not been initialized)
+     */
+    public final byte[] update(byte[] input) {
+        checkCipherState();
+
+        // Input sanity check
+        if (input == null) {
+            throw new IllegalArgumentException("Null input buffer");
+        }
+
+        updateProviderIfNeeded();
+        if (input.length == 0) {
+            return null;
+        }
+        return spi.engineUpdate(input, 0, input.length);
+    }
+
+    /**
+     * Continues a multiple-part encryption or decryption operation
+     * (depending on how this cipher was initialized), processing another data
+     * part.
+     *
+     * <p>The first <code>inputLen</code> bytes in the <code>input</code>
+     * buffer, starting at <code>inputOffset</code> inclusive, are processed,
+     * and the result is stored in a new buffer.
+     *
+     * <p>If <code>inputLen</code> is zero, this method returns
+     * <code>null</code>.
+     *
+     * @param input the input buffer
+     * @param inputOffset the offset in <code>input</code> where the input
+     * starts
+     * @param inputLen the input length
+     *
+     * @return the new buffer with the result, or null if the underlying
+     * cipher is a block cipher and the input data is too short to result in a
+     * new block.
+     *
+     * @exception IllegalStateException if this cipher is in a wrong state
+     * (e.g., has not been initialized)
+     */
+    public final byte[] update(byte[] input, int inputOffset, int inputLen) {
+        checkCipherState();
+
+        // Input sanity check
+        if (input == null || inputOffset < 0
+            || inputLen > (input.length - inputOffset) || inputLen < 0) {
+            throw new IllegalArgumentException("Bad arguments");
+        }
+
+        updateProviderIfNeeded();
+        if (inputLen == 0) {
+            return null;
+        }
+        return spi.engineUpdate(input, inputOffset, inputLen);
+    }
+
+    /**
+     * Continues a multiple-part encryption or decryption operation
+     * (depending on how this cipher was initialized), processing another data
+     * part.
+     *
+     * <p>The first <code>inputLen</code> bytes in the <code>input</code>
+     * buffer, starting at <code>inputOffset</code> inclusive, are processed,
+     * and the result is stored in the <code>output</code> buffer.
+     *
+     * <p>If the <code>output</code> buffer is too small to hold the result,
+     * a <code>ShortBufferException</code> is thrown. In this case, repeat this
+     * call with a larger output buffer. Use
+     * {@link #getOutputSize(int) getOutputSize} to determine how big
+     * the output buffer should be.
+     *
+     * <p>If <code>inputLen</code> is zero, this method returns
+     * a length of zero.
+     *
+     * <p>Note: this method should be copy-safe, which means the
+     * <code>input</code> and <code>output</code> buffers can reference
+     * the same byte array and no unprocessed input data is overwritten
+     * when the result is copied into the output buffer.
+     *
+     * @param input the input buffer
+     * @param inputOffset the offset in <code>input</code> where the input
+     * starts
+     * @param inputLen the input length
+     * @param output the buffer for the result
+     *
+     * @return the number of bytes stored in <code>output</code>
+     *
+     * @exception IllegalStateException if this cipher is in a wrong state
+     * (e.g., has not been initialized)
+     * @exception ShortBufferException if the given output buffer is too small
+     * to hold the result
+     */
+    public final int update(byte[] input, int inputOffset, int inputLen,
+                            byte[] output)
+            throws ShortBufferException {
+        checkCipherState();
+
+        // Input sanity check
+        if (input == null || inputOffset < 0
+            || inputLen > (input.length - inputOffset) || inputLen < 0) {
+            throw new IllegalArgumentException("Bad arguments");
+        }
+
+        updateProviderIfNeeded();
+        if (inputLen == 0) {
+            return 0;
+        }
+        return spi.engineUpdate(input, inputOffset, inputLen,
+                                      output, 0);
+    }
+
+    /**
+     * Continues a multiple-part encryption or decryption operation
+     * (depending on how this cipher was initialized), processing another data
+     * part.
+     *
+     * <p>The first <code>inputLen</code> bytes in the <code>input</code>
+     * buffer, starting at <code>inputOffset</code> inclusive, are processed,
+     * and the result is stored in the <code>output</code> buffer, starting at
+     * <code>outputOffset</code> inclusive.
+     *
+     * <p>If the <code>output</code> buffer is too small to hold the result,
+     * a <code>ShortBufferException</code> is thrown. In this case, repeat this
+     * call with a larger output buffer. Use
+     * {@link #getOutputSize(int) getOutputSize} to determine how big
+     * the output buffer should be.
+     *
+     * <p>If <code>inputLen</code> is zero, this method returns
+     * a length of zero.
+     *
+     * <p>Note: this method should be copy-safe, which means the
+     * <code>input</code> and <code>output</code> buffers can reference
+     * the same byte array and no unprocessed input data is overwritten
+     * when the result is copied into the output buffer.
+     *
+     * @param input the input buffer
+     * @param inputOffset the offset in <code>input</code> where the input
+     * starts
+     * @param inputLen the input length
+     * @param output the buffer for the result
+     * @param outputOffset the offset in <code>output</code> where the result
+     * is stored
+     *
+     * @return the number of bytes stored in <code>output</code>
+     *
+     * @exception IllegalStateException if this cipher is in a wrong state
+     * (e.g., has not been initialized)
+     * @exception ShortBufferException if the given output buffer is too small
+     * to hold the result
+     */
+    public final int update(byte[] input, int inputOffset, int inputLen,
+                            byte[] output, int outputOffset)
+            throws ShortBufferException {
+        checkCipherState();
+
+        // Input sanity check
+        if (input == null || inputOffset < 0
+            || inputLen > (input.length - inputOffset) || inputLen < 0
+            || outputOffset < 0) {
+            throw new IllegalArgumentException("Bad arguments");
+        }
+
+        updateProviderIfNeeded();
+        if (inputLen == 0) {
+            return 0;
+        }
+        return spi.engineUpdate(input, inputOffset, inputLen,
+                                      output, outputOffset);
+    }
+
+    /**
+     * Continues a multiple-part encryption or decryption operation
+     * (depending on how this cipher was initialized), processing another data
+     * part.
+     *
+     * <p>All <code>input.remaining()</code> bytes starting at
+     * <code>input.position()</code> are processed. The result is stored
+     * in the output buffer.
+     * Upon return, the input buffer's position will be equal
+     * to its limit; its limit will not have changed. The output buffer's
+     * position will have advanced by n, where n is the value returned
+     * by this method; the output buffer's limit will not have changed.
+     *
+     * <p>If <code>output.remaining()</code> bytes are insufficient to
+     * hold the result, a <code>ShortBufferException</code> is thrown.
+     * In this case, repeat this call with a larger output buffer. Use
+     * {@link #getOutputSize(int) getOutputSize} to determine how big
+     * the output buffer should be.
+     *
+     * <p>Note: this method should be copy-safe, which means the
+     * <code>input</code> and <code>output</code> buffers can reference
+     * the same block of memory and no unprocessed input data is overwritten
+     * when the result is copied into the output buffer.
+     *
+     * @param input the input ByteBuffer
+     * @param output the output ByteByffer
+     *
+     * @return the number of bytes stored in <code>output</code>
+     *
+     * @exception IllegalStateException if this cipher is in a wrong state
+     * (e.g., has not been initialized)
+     * @exception IllegalArgumentException if input and output are the
+     *   same object
+     * @exception ReadOnlyBufferException if the output buffer is read-only
+     * @exception ShortBufferException if there is insufficient space in the
+     * output buffer
+     * @since 1.5
+     */
+    public final int update(ByteBuffer input, ByteBuffer output)
+            throws ShortBufferException {
+        checkCipherState();
+
+        if ((input == null) || (output == null)) {
+            throw new IllegalArgumentException("Buffers must not be null");
+        }
+        if (input == output) {
+            throw new IllegalArgumentException("Input and output buffers must "
+                + "not be the same object, consider using buffer.duplicate()");
+        }
+        if (output.isReadOnly()) {
+            throw new ReadOnlyBufferException();
+        }
+
+        updateProviderIfNeeded();
+        return spi.engineUpdate(input, output);
+    }
+
+    /**
+     * Finishes a multiple-part encryption or decryption operation, depending
+     * on how this cipher was initialized.
+     *
+     * <p>Input data that may have been buffered during a previous
+     * <code>update</code> operation is processed, with padding (if requested)
+     * being applied.
+     * If an AEAD mode such as GCM/CCM is being used, the authentication
+     * tag is appended in the case of encryption, or verified in the
+     * case of decryption.
+     * The result is stored in a new buffer.
+     *
+     * <p>Upon finishing, this method resets this cipher object to the state
+     * it was in when previously initialized via a call to <code>init</code>.
+     * That is, the object is reset and available to encrypt or decrypt
+     * (depending on the operation mode that was specified in the call to
+     * <code>init</code>) more data.
+     *
+     * <p>Note: if any exception is thrown, this cipher object may need to
+     * be reset before it can be used again.
+     *
+     * @return the new buffer with the result
+     *
+     * @exception IllegalStateException if this cipher is in a wrong state
+     * (e.g., has not been initialized)
+     * @exception IllegalBlockSizeException if this cipher is a block cipher,
+     * no padding has been requested (only in encryption mode), and the total
+     * input length of the data processed by this cipher is not a multiple of
+     * block size; or if this encryption algorithm is unable to
+     * process the input data provided.
+     * @exception BadPaddingException if this cipher is in decryption mode,
+     * and (un)padding has been requested, but the decrypted data is not
+     * bounded by the appropriate padding bytes
+     * @exception AEADBadTagException if this cipher is decrypting in an
+     * AEAD mode (such as GCM/CCM), and the received authentication tag
+     * does not match the calculated value
+     */
+    public final byte[] doFinal()
+            throws IllegalBlockSizeException, BadPaddingException {
+        checkCipherState();
+
+        updateProviderIfNeeded();
+        return spi.engineDoFinal(null, 0, 0);
+    }
+
+    /**
+     * Finishes a multiple-part encryption or decryption operation, depending
+     * on how this cipher was initialized.
+     *
+     * <p>Input data that may have been buffered during a previous
+     * <code>update</code> operation is processed, with padding (if requested)
+     * being applied.
+     * If an AEAD mode such as GCM/CCM is being used, the authentication
+     * tag is appended in the case of encryption, or verified in the
+     * case of decryption.
+     * The result is stored in the <code>output</code> buffer, starting at
+     * <code>outputOffset</code> inclusive.
+     *
+     * <p>If the <code>output</code> buffer is too small to hold the result,
+     * a <code>ShortBufferException</code> is thrown. In this case, repeat this
+     * call with a larger output buffer. Use
+     * {@link #getOutputSize(int) getOutputSize} to determine how big
+     * the output buffer should be.
+     *
+     * <p>Upon finishing, this method resets this cipher object to the state
+     * it was in when previously initialized via a call to <code>init</code>.
+     * That is, the object is reset and available to encrypt or decrypt
+     * (depending on the operation mode that was specified in the call to
+     * <code>init</code>) more data.
+     *
+     * <p>Note: if any exception is thrown, this cipher object may need to
+     * be reset before it can be used again.
+     *
+     * @param output the buffer for the result
+     * @param outputOffset the offset in <code>output</code> where the result
+     * is stored
+     *
+     * @return the number of bytes stored in <code>output</code>
+     *
+     * @exception IllegalStateException if this cipher is in a wrong state
+     * (e.g., has not been initialized)
+     * @exception IllegalBlockSizeException if this cipher is a block cipher,
+     * no padding has been requested (only in encryption mode), and the total
+     * input length of the data processed by this cipher is not a multiple of
+     * block size; or if this encryption algorithm is unable to
+     * process the input data provided.
+     * @exception ShortBufferException if the given output buffer is too small
+     * to hold the result
+     * @exception BadPaddingException if this cipher is in decryption mode,
+     * and (un)padding has been requested, but the decrypted data is not
+     * bounded by the appropriate padding bytes
+     * @exception AEADBadTagException if this cipher is decrypting in an
+     * AEAD mode (such as GCM/CCM), and the received authentication tag
+     * does not match the calculated value
+     */
+    public final int doFinal(byte[] output, int outputOffset)
+            throws IllegalBlockSizeException, ShortBufferException,
+               BadPaddingException {
+        checkCipherState();
+
+        // Input sanity check
+        if ((output == null) || (outputOffset < 0)) {
+            throw new IllegalArgumentException("Bad arguments");
+        }
+
+        updateProviderIfNeeded();
+        return spi.engineDoFinal(null, 0, 0, output, outputOffset);
+    }
+
+    /**
+     * Encrypts or decrypts data in a single-part operation, or finishes a
+     * multiple-part operation. The data is encrypted or decrypted,
+     * depending on how this cipher was initialized.
+     *
+     * <p>The bytes in the <code>input</code> buffer, and any input bytes that
+     * may have been buffered during a previous <code>update</code> operation,
+     * are processed, with padding (if requested) being applied.
+     * If an AEAD mode such as GCM/CCM is being used, the authentication
+     * tag is appended in the case of encryption, or verified in the
+     * case of decryption.
+     * The result is stored in a new buffer.
+     *
+     * <p>Upon finishing, this method resets this cipher object to the state
+     * it was in when previously initialized via a call to <code>init</code>.
+     * That is, the object is reset and available to encrypt or decrypt
+     * (depending on the operation mode that was specified in the call to
+     * <code>init</code>) more data.
+     *
+     * <p>Note: if any exception is thrown, this cipher object may need to
+     * be reset before it can be used again.
+     *
+     * @param input the input buffer
+     *
+     * @return the new buffer with the result
+     *
+     * @exception IllegalStateException if this cipher is in a wrong state
+     * (e.g., has not been initialized)
+     * @exception IllegalBlockSizeException if this cipher is a block cipher,
+     * no padding has been requested (only in encryption mode), and the total
+     * input length of the data processed by this cipher is not a multiple of
+     * block size; or if this encryption algorithm is unable to
+     * process the input data provided.
+     * @exception BadPaddingException if this cipher is in decryption mode,
+     * and (un)padding has been requested, but the decrypted data is not
+     * bounded by the appropriate padding bytes
+     * @exception AEADBadTagException if this cipher is decrypting in an
+     * AEAD mode (such as GCM/CCM), and the received authentication tag
+     * does not match the calculated value
+     */
+    public final byte[] doFinal(byte[] input)
+            throws IllegalBlockSizeException, BadPaddingException {
+        checkCipherState();
+
+        // Input sanity check
+        if (input == null) {
+            throw new IllegalArgumentException("Null input buffer");
+        }
+
+        updateProviderIfNeeded();
+        return spi.engineDoFinal(input, 0, input.length);
+    }
+
+    /**
+     * Encrypts or decrypts data in a single-part operation, or finishes a
+     * multiple-part operation. The data is encrypted or decrypted,
+     * depending on how this cipher was initialized.
+     *
+     * <p>The first <code>inputLen</code> bytes in the <code>input</code>
+     * buffer, starting at <code>inputOffset</code> inclusive, and any input
+     * bytes that may have been buffered during a previous <code>update</code>
+     * operation, are processed, with padding (if requested) being applied.
+     * If an AEAD mode such as GCM/CCM is being used, the authentication
+     * tag is appended in the case of encryption, or verified in the
+     * case of decryption.
+     * The result is stored in a new buffer.
+     *
+     * <p>Upon finishing, this method resets this cipher object to the state
+     * it was in when previously initialized via a call to <code>init</code>.
+     * That is, the object is reset and available to encrypt or decrypt
+     * (depending on the operation mode that was specified in the call to
+     * <code>init</code>) more data.
+     *
+     * <p>Note: if any exception is thrown, this cipher object may need to
+     * be reset before it can be used again.
+     *
+     * @param input the input buffer
+     * @param inputOffset the offset in <code>input</code> where the input
+     * starts
+     * @param inputLen the input length
+     *
+     * @return the new buffer with the result
+     *
+     * @exception IllegalStateException if this cipher is in a wrong state
+     * (e.g., has not been initialized)
+     * @exception IllegalBlockSizeException if this cipher is a block cipher,
+     * no padding has been requested (only in encryption mode), and the total
+     * input length of the data processed by this cipher is not a multiple of
+     * block size; or if this encryption algorithm is unable to
+     * process the input data provided.
+     * @exception BadPaddingException if this cipher is in decryption mode,
+     * and (un)padding has been requested, but the decrypted data is not
+     * bounded by the appropriate padding bytes
+     * @exception AEADBadTagException if this cipher is decrypting in an
+     * AEAD mode (such as GCM/CCM), and the received authentication tag
+     * does not match the calculated value
+     */
+    public final byte[] doFinal(byte[] input, int inputOffset, int inputLen)
+            throws IllegalBlockSizeException, BadPaddingException {
+        checkCipherState();
+
+        // Input sanity check
+        if (input == null || inputOffset < 0
+            || inputLen > (input.length - inputOffset) || inputLen < 0) {
+            throw new IllegalArgumentException("Bad arguments");
+        }
+
+        updateProviderIfNeeded();
+        return spi.engineDoFinal(input, inputOffset, inputLen);
+    }
+
+    /**
+     * Encrypts or decrypts data in a single-part operation, or finishes a
+     * multiple-part operation. The data is encrypted or decrypted,
+     * depending on how this cipher was initialized.
+     *
+     * <p>The first <code>inputLen</code> bytes in the <code>input</code>
+     * buffer, starting at <code>inputOffset</code> inclusive, and any input
+     * bytes that may have been buffered during a previous <code>update</code>
+     * operation, are processed, with padding (if requested) being applied.
+     * If an AEAD mode such as GCM/CCM is being used, the authentication
+     * tag is appended in the case of encryption, or verified in the
+     * case of decryption.
+     * The result is stored in the <code>output</code> buffer.
+     *
+     * <p>If the <code>output</code> buffer is too small to hold the result,
+     * a <code>ShortBufferException</code> is thrown. In this case, repeat this
+     * call with a larger output buffer. Use
+     * {@link #getOutputSize(int) getOutputSize} to determine how big
+     * the output buffer should be.
+     *
+     * <p>Upon finishing, this method resets this cipher object to the state
+     * it was in when previously initialized via a call to <code>init</code>.
+     * That is, the object is reset and available to encrypt or decrypt
+     * (depending on the operation mode that was specified in the call to
+     * <code>init</code>) more data.
+     *
+     * <p>Note: if any exception is thrown, this cipher object may need to
+     * be reset before it can be used again.
+     *
+     * <p>Note: this method should be copy-safe, which means the
+     * <code>input</code> and <code>output</code> buffers can reference
+     * the same byte array and no unprocessed input data is overwritten
+     * when the result is copied into the output buffer.
+     *
+     * @param input the input buffer
+     * @param inputOffset the offset in <code>input</code> where the input
+     * starts
+     * @param inputLen the input length
+     * @param output the buffer for the result
+     *
+     * @return the number of bytes stored in <code>output</code>
+     *
+     * @exception IllegalStateException if this cipher is in a wrong state
+     * (e.g., has not been initialized)
+     * @exception IllegalBlockSizeException if this cipher is a block cipher,
+     * no padding has been requested (only in encryption mode), and the total
+     * input length of the data processed by this cipher is not a multiple of
+     * block size; or if this encryption algorithm is unable to
+     * process the input data provided.
+     * @exception ShortBufferException if the given output buffer is too small
+     * to hold the result
+     * @exception BadPaddingException if this cipher is in decryption mode,
+     * and (un)padding has been requested, but the decrypted data is not
+     * bounded by the appropriate padding bytes
+     * @exception AEADBadTagException if this cipher is decrypting in an
+     * AEAD mode (such as GCM/CCM), and the received authentication tag
+     * does not match the calculated value
+     */
+    public final int doFinal(byte[] input, int inputOffset, int inputLen,
+                             byte[] output)
+            throws ShortBufferException, IllegalBlockSizeException,
+            BadPaddingException {
+        checkCipherState();
+
+        // Input sanity check
+        if (input == null || inputOffset < 0
+            || inputLen > (input.length - inputOffset) || inputLen < 0) {
+            throw new IllegalArgumentException("Bad arguments");
+        }
+
+        updateProviderIfNeeded();
+        return spi.engineDoFinal(input, inputOffset, inputLen,
+                                       output, 0);
+    }
+
+    /**
+     * Encrypts or decrypts data in a single-part operation, or finishes a
+     * multiple-part operation. The data is encrypted or decrypted,
+     * depending on how this cipher was initialized.
+     *
+     * <p>The first <code>inputLen</code> bytes in the <code>input</code>
+     * buffer, starting at <code>inputOffset</code> inclusive, and any input
+     * bytes that may have been buffered during a previous
+     * <code>update</code> operation, are processed, with padding
+     * (if requested) being applied.
+     * If an AEAD mode such as GCM/CCM is being used, the authentication
+     * tag is appended in the case of encryption, or verified in the
+     * case of decryption.
+     * The result is stored in the <code>output</code> buffer, starting at
+     * <code>outputOffset</code> inclusive.
+     *
+     * <p>If the <code>output</code> buffer is too small to hold the result,
+     * a <code>ShortBufferException</code> is thrown. In this case, repeat this
+     * call with a larger output buffer. Use
+     * {@link #getOutputSize(int) getOutputSize} to determine how big
+     * the output buffer should be.
+     *
+     * <p>Upon finishing, this method resets this cipher object to the state
+     * it was in when previously initialized via a call to <code>init</code>.
+     * That is, the object is reset and available to encrypt or decrypt
+     * (depending on the operation mode that was specified in the call to
+     * <code>init</code>) more data.
+     *
+     * <p>Note: if any exception is thrown, this cipher object may need to
+     * be reset before it can be used again.
+     *
+     * <p>Note: this method should be copy-safe, which means the
+     * <code>input</code> and <code>output</code> buffers can reference
+     * the same byte array and no unprocessed input data is overwritten
+     * when the result is copied into the output buffer.
+     *
+     * @param input the input buffer
+     * @param inputOffset the offset in <code>input</code> where the input
+     * starts
+     * @param inputLen the input length
+     * @param output the buffer for the result
+     * @param outputOffset the offset in <code>output</code> where the result
+     * is stored
+     *
+     * @return the number of bytes stored in <code>output</code>
+     *
+     * @exception IllegalStateException if this cipher is in a wrong state
+     * (e.g., has not been initialized)
+     * @exception IllegalBlockSizeException if this cipher is a block cipher,
+     * no padding has been requested (only in encryption mode), and the total
+     * input length of the data processed by this cipher is not a multiple of
+     * block size; or if this encryption algorithm is unable to
+     * process the input data provided.
+     * @exception ShortBufferException if the given output buffer is too small
+     * to hold the result
+     * @exception BadPaddingException if this cipher is in decryption mode,
+     * and (un)padding has been requested, but the decrypted data is not
+     * bounded by the appropriate padding bytes
+     * @exception AEADBadTagException if this cipher is decrypting in an
+     * AEAD mode (such as GCM/CCM), and the received authentication tag
+     * does not match the calculated value
+     */
+    public final int doFinal(byte[] input, int inputOffset, int inputLen,
+                             byte[] output, int outputOffset)
+            throws ShortBufferException, IllegalBlockSizeException,
+            BadPaddingException {
+        checkCipherState();
+
+        // Input sanity check
+        if (input == null || inputOffset < 0
+            || inputLen > (input.length - inputOffset) || inputLen < 0
+            || outputOffset < 0) {
+            throw new IllegalArgumentException("Bad arguments");
+        }
+
+        updateProviderIfNeeded();
+        return spi.engineDoFinal(input, inputOffset, inputLen,
+                                       output, outputOffset);
+    }
+
+    /**
+     * Encrypts or decrypts data in a single-part operation, or finishes a
+     * multiple-part operation. The data is encrypted or decrypted,
+     * depending on how this cipher was initialized.
+     *
+     * <p>All <code>input.remaining()</code> bytes starting at
+     * <code>input.position()</code> are processed.
+     * If an AEAD mode such as GCM/CCM is being used, the authentication
+     * tag is appended in the case of encryption, or verified in the
+     * case of decryption.
+     * The result is stored in the output buffer.
+     * Upon return, the input buffer's position will be equal
+     * to its limit; its limit will not have changed. The output buffer's
+     * position will have advanced by n, where n is the value returned
+     * by this method; the output buffer's limit will not have changed.
+     *
+     * <p>If <code>output.remaining()</code> bytes are insufficient to
+     * hold the result, a <code>ShortBufferException</code> is thrown.
+     * In this case, repeat this call with a larger output buffer. Use
+     * {@link #getOutputSize(int) getOutputSize} to determine how big
+     * the output buffer should be.
+     *
+     * <p>Upon finishing, this method resets this cipher object to the state
+     * it was in when previously initialized via a call to <code>init</code>.
+     * That is, the object is reset and available to encrypt or decrypt
+     * (depending on the operation mode that was specified in the call to
+     * <code>init</code>) more data.
+     *
+     * <p>Note: if any exception is thrown, this cipher object may need to
+     * be reset before it can be used again.
+     *
+     * <p>Note: this method should be copy-safe, which means the
+     * <code>input</code> and <code>output</code> buffers can reference
+     * the same byte array and no unprocessed input data is overwritten
+     * when the result is copied into the output buffer.
+     *
+     * @param input the input ByteBuffer
+     * @param output the output ByteBuffer
+     *
+     * @return the number of bytes stored in <code>output</code>
+     *
+     * @exception IllegalStateException if this cipher is in a wrong state
+     * (e.g., has not been initialized)
+     * @exception IllegalArgumentException if input and output are the
+     *   same object
+     * @exception ReadOnlyBufferException if the output buffer is read-only
+     * @exception IllegalBlockSizeException if this cipher is a block cipher,
+     * no padding has been requested (only in encryption mode), and the total
+     * input length of the data processed by this cipher is not a multiple of
+     * block size; or if this encryption algorithm is unable to
+     * process the input data provided.
+     * @exception ShortBufferException if there is insufficient space in the
+     * output buffer
+     * @exception BadPaddingException if this cipher is in decryption mode,
+     * and (un)padding has been requested, but the decrypted data is not
+     * bounded by the appropriate padding bytes
+     * @exception AEADBadTagException if this cipher is decrypting in an
+     * AEAD mode (such as GCM/CCM), and the received authentication tag
+     * does not match the calculated value
+     *
+     * @since 1.5
+     */
+    public final int doFinal(ByteBuffer input, ByteBuffer output)
+            throws ShortBufferException, IllegalBlockSizeException,
+            BadPaddingException {
+        checkCipherState();
+
+        if ((input == null) || (output == null)) {
+            throw new IllegalArgumentException("Buffers must not be null");
+        }
+        if (input == output) {
+            throw new IllegalArgumentException("Input and output buffers must "
+                + "not be the same object, consider using buffer.duplicate()");
+        }
+        if (output.isReadOnly()) {
+            throw new ReadOnlyBufferException();
+        }
+
+        updateProviderIfNeeded();
+        return spi.engineDoFinal(input, output);
+    }
+
+    /**
+     * Wrap a key.
+     *
+     * @param key the key to be wrapped.
+     *
+     * @return the wrapped key.
+     *
+     * @exception IllegalStateException if this cipher is in a wrong
+     * state (e.g., has not been initialized).
+     *
+     * @exception IllegalBlockSizeException if this cipher is a block
+     * cipher, no padding has been requested, and the length of the
+     * encoding of the key to be wrapped is not a
+     * multiple of the block size.
+     *
+     * @exception InvalidKeyException if it is impossible or unsafe to
+     * wrap the key with this cipher (e.g., a hardware protected key is
+     * being passed to a software-only cipher).
+     *
+     * @throws UnsupportedOperationException if the corresponding method in the
+     * {@code CipherSpi} is not supported.
+     */
+    public final byte[] wrap(Key key)
+            throws IllegalBlockSizeException, InvalidKeyException {
+        if (!(this instanceof NullCipher)) {
+            if (!initialized) {
+                throw new IllegalStateException("Cipher not initialized");
+            }
+            if (opmode != Cipher.WRAP_MODE) {
+                throw new IllegalStateException("Cipher not initialized " +
+                                                "for wrapping keys");
+            }
+        }
+
+        updateProviderIfNeeded();
+        return spi.engineWrap(key);
+    }
+
+    /**
+     * Unwrap a previously wrapped key.
+     *
+     * @param wrappedKey the key to be unwrapped.
+     *
+     * @param wrappedKeyAlgorithm the algorithm associated with the wrapped
+     * key.
+     *
+     * @param wrappedKeyType the type of the wrapped key. This must be one of
+     * <code>SECRET_KEY</code>, <code>PRIVATE_KEY</code>, or
+     * <code>PUBLIC_KEY</code>.
+     *
+     * @return the unwrapped key.
+     *
+     * @exception IllegalStateException if this cipher is in a wrong state
+     * (e.g., has not been initialized).
+     *
+     * @exception NoSuchAlgorithmException if no installed providers
+     * can create keys of type <code>wrappedKeyType</code> for the
+     * <code>wrappedKeyAlgorithm</code>.
+     *
+     * @exception InvalidKeyException if <code>wrappedKey</code> does not
+     * represent a wrapped key of type <code>wrappedKeyType</code> for
+     * the <code>wrappedKeyAlgorithm</code>.
+     *
+     * @throws UnsupportedOperationException if the corresponding method in the
+     * {@code CipherSpi} is not supported.
+     */
+    public final Key unwrap(byte[] wrappedKey,
+                            String wrappedKeyAlgorithm,
+                            int wrappedKeyType)
+            throws InvalidKeyException, NoSuchAlgorithmException {
+
+        if (!(this instanceof NullCipher)) {
+            if (!initialized) {
+                throw new IllegalStateException("Cipher not initialized");
+            }
+            if (opmode != Cipher.UNWRAP_MODE) {
+                throw new IllegalStateException("Cipher not initialized " +
+                                                "for unwrapping keys");
+            }
+        }
+        if ((wrappedKeyType != SECRET_KEY) &&
+            (wrappedKeyType != PRIVATE_KEY) &&
+            (wrappedKeyType != PUBLIC_KEY)) {
+            throw new InvalidParameterException("Invalid key type");
+        }
+
+        updateProviderIfNeeded();
+        return spi.engineUnwrap(wrappedKey,
+                                      wrappedKeyAlgorithm,
+                                      wrappedKeyType);
+    }
+
+    private AlgorithmParameterSpec getAlgorithmParameterSpec(
+                                      AlgorithmParameters params)
+            throws InvalidParameterSpecException {
+        if (params == null) {
+            return null;
+        }
+
+        String alg = params.getAlgorithm().toUpperCase(Locale.ENGLISH);
+
+        if (alg.equalsIgnoreCase("RC2")) {
+            return params.getParameterSpec(RC2ParameterSpec.class);
+        }
+
+        if (alg.equalsIgnoreCase("RC5")) {
+            return params.getParameterSpec(RC5ParameterSpec.class);
+        }
+
+        if (alg.startsWith("PBE")) {
+            return params.getParameterSpec(PBEParameterSpec.class);
+        }
+
+        if (alg.startsWith("DES")) {
+            return params.getParameterSpec(IvParameterSpec.class);
+        }
+        return null;
+    }
+
+    /**
+     * Returns the maximum key length for the specified transformation
+     * according to the installed JCE jurisdiction policy files. If
+     * JCE unlimited strength jurisdiction policy files are installed,
+     * Integer.MAX_VALUE will be returned.
+     * For more information on default key size in JCE jurisdiction
+     * policy files, please see Appendix E in the
+     * <a href=
+     *   "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppC">
+     * Java Cryptography Architecture Reference Guide</a>.
+     *
+     * @param transformation the cipher transformation.
+     * @return the maximum key length in bits or Integer.MAX_VALUE.
+     * @exception NullPointerException if <code>transformation</code> is null.
+     * @exception NoSuchAlgorithmException if <code>transformation</code>
+     * is not a valid transformation, i.e. in the form of "algorithm" or
+     * "algorithm/mode/padding".
+     * @since 1.5
+     */
+    public static final int getMaxAllowedKeyLength(String transformation)
+            throws NoSuchAlgorithmException {
+        // Android-changed: Remove references to CryptoPermission.
+        // Throw early if transformation == null or isn't valid.
+        //
+        // CryptoPermission cp = getConfiguredPermission(transformation);
+        // return cp.getMaxAllowedKeyLength();
+        if (transformation == null) {
+            throw new NullPointerException("transformation == null");
+        }
+        // Throws NoSuchAlgorithmException if necessary.
+        tokenizeTransformation(transformation);
+        return Integer.MAX_VALUE;
+    }
+
+    /**
+     * Returns an AlgorithmParameterSpec object which contains
+     * the maximum cipher parameter value according to the
+     * jurisdiction policy file. If JCE unlimited strength jurisdiction
+     * policy files are installed or there is no maximum limit on the
+     * parameters for the specified transformation in the policy file,
+     * null will be returned.
+     *
+     * @param transformation the cipher transformation.
+     * @return an AlgorithmParameterSpec which holds the maximum
+     * value or null.
+     * @exception NullPointerException if <code>transformation</code>
+     * is null.
+     * @exception NoSuchAlgorithmException if <code>transformation</code>
+     * is not a valid transformation, i.e. in the form of "algorithm" or
+     * "algorithm/mode/padding".
+     * @since 1.5
+     */
+    public static final AlgorithmParameterSpec getMaxAllowedParameterSpec(
+            String transformation) throws NoSuchAlgorithmException {
+        // Android-changed: Remove references to CryptoPermission.
+        // Throw early if transformation == null or isn't valid.
+        //
+        // CryptoPermission cp = getConfiguredPermission(transformation);
+        // return cp.getAlgorithmParameterSpec();
+        if (transformation == null) {
+            throw new NullPointerException("transformation == null");
+        }
+        // Throws NoSuchAlgorithmException if necessary.
+        tokenizeTransformation(transformation);
+        return null;
+    }
+
+    /**
+     * Continues a multi-part update of the Additional Authentication
+     * Data (AAD).
+     * <p>
+     * Calls to this method provide AAD to the cipher when operating in
+     * modes such as AEAD (GCM/CCM).  If this cipher is operating in
+     * either GCM or CCM mode, all AAD must be supplied before beginning
+     * operations on the ciphertext (via the {@code update} and {@code
+     * doFinal} methods).
+     *
+     * @param src the buffer containing the Additional Authentication Data
+     *
+     * @throws IllegalArgumentException if the {@code src}
+     * byte array is null
+     * @throws IllegalStateException if this cipher is in a wrong state
+     * (e.g., has not been initialized), does not accept AAD, or if
+     * operating in either GCM or CCM mode and one of the {@code update}
+     * methods has already been called for the active
+     * encryption/decryption operation
+     * @throws UnsupportedOperationException if the corresponding method
+     * in the {@code CipherSpi} has not been overridden by an
+     * implementation
+     *
+     * @since 1.7
+     */
+    public final void updateAAD(byte[] src) {
+        if (src == null) {
+            throw new IllegalArgumentException("src buffer is null");
+        }
+
+        updateAAD(src, 0, src.length);
+    }
+
+    /**
+     * Continues a multi-part update of the Additional Authentication
+     * Data (AAD), using a subset of the provided buffer.
+     * <p>
+     * Calls to this method provide AAD to the cipher when operating in
+     * modes such as AEAD (GCM/CCM).  If this cipher is operating in
+     * either GCM or CCM mode, all AAD must be supplied before beginning
+     * operations on the ciphertext (via the {@code update} and {@code
+     * doFinal} methods).
+     *
+     * @param src the buffer containing the AAD
+     * @param offset the offset in {@code src} where the AAD input starts
+     * @param len the number of AAD bytes
+     *
+     * @throws IllegalArgumentException if the {@code src}
+     * byte array is null, or the {@code offset} or {@code length}
+     * is less than 0, or the sum of the {@code offset} and
+     * {@code len} is greater than the length of the
+     * {@code src} byte array
+     * @throws IllegalStateException if this cipher is in a wrong state
+     * (e.g., has not been initialized), does not accept AAD, or if
+     * operating in either GCM or CCM mode and one of the {@code update}
+     * methods has already been called for the active
+     * encryption/decryption operation
+     * @throws UnsupportedOperationException if the corresponding method
+     * in the {@code CipherSpi} has not been overridden by an
+     * implementation
+     *
+     * @since 1.7
+     */
+    public final void updateAAD(byte[] src, int offset, int len) {
+        checkCipherState();
+
+        // Input sanity check
+        if ((src == null) || (offset < 0) || (len < 0)
+                || ((len + offset) > src.length)) {
+            throw new IllegalArgumentException("Bad arguments");
+        }
+
+        updateProviderIfNeeded();
+        if (len == 0) {
+            return;
+        }
+        spi.engineUpdateAAD(src, offset, len);
+    }
+
+    /**
+     * Continues a multi-part update of the Additional Authentication
+     * Data (AAD).
+     * <p>
+     * Calls to this method provide AAD to the cipher when operating in
+     * modes such as AEAD (GCM/CCM).  If this cipher is operating in
+     * either GCM or CCM mode, all AAD must be supplied before beginning
+     * operations on the ciphertext (via the {@code update} and {@code
+     * doFinal} methods).
+     * <p>
+     * All {@code src.remaining()} bytes starting at
+     * {@code src.position()} are processed.
+     * Upon return, the input buffer's position will be equal
+     * to its limit; its limit will not have changed.
+     *
+     * @param src the buffer containing the AAD
+     *
+     * @throws IllegalArgumentException if the {@code src ByteBuffer}
+     * is null
+     * @throws IllegalStateException if this cipher is in a wrong state
+     * (e.g., has not been initialized), does not accept AAD, or if
+     * operating in either GCM or CCM mode and one of the {@code update}
+     * methods has already been called for the active
+     * encryption/decryption operation
+     * @throws UnsupportedOperationException if the corresponding method
+     * in the {@code CipherSpi} has not been overridden by an
+     * implementation
+     *
+     * @since 1.7
+     */
+    public final void updateAAD(ByteBuffer src) {
+        checkCipherState();
+
+        // Input sanity check
+        if (src == null) {
+            throw new IllegalArgumentException("src ByteBuffer is null");
+        }
+
+        updateProviderIfNeeded();
+        if (src.remaining() == 0) {
+            return;
+        }
+        spi.engineUpdateAAD(src);
+    }
+
+    // BEGIN Android-added: Bulk of the new provider implementation.
+    // See note at top of class.
+    /**
+     * Returns the {@code CipherSpi} backing this {@code Cipher} or {@code null} if no
+     * {@code CipherSpi} is backing this {@code Cipher}.
+     *
+     * @hide
+     */
+    public CipherSpi getCurrentSpi() {
+        return spi;
+    }
+
+    /** The attribute used for supported paddings. */
+    private static final String ATTRIBUTE_PADDINGS = "SupportedPaddings";
+
+    /** The attribute used for supported modes. */
+    private static final String ATTRIBUTE_MODES = "SupportedModes";
+
+    /**
+     * If the attribute listed exists, check that it matches the regular
+     * expression.
+     */
+    static boolean matchAttribute(Provider.Service service, String attr, String value) {
+        if (value == null) {
+            return true;
+        }
+        final String pattern = service.getAttribute(attr);
+        if (pattern == null) {
+            return true;
+        }
+        final String valueUc = value.toUpperCase(Locale.US);
+        return valueUc.matches(pattern.toUpperCase(Locale.US));
+    }
+
+    /** Items that need to be set on the Cipher instance. */
+    enum NeedToSet {
+        NONE, MODE, PADDING, BOTH,
+    }
+
+    /**
+     * Expresses the various types of transforms that may be used during
+     * initialization.
+     */
+    static class Transform {
+        private final String name;
+        private final NeedToSet needToSet;
+
+        public Transform(String name, NeedToSet needToSet) {
+            this.name = name;
+            this.needToSet = needToSet;
+        }
+    }
+
+    /**
+     * Keeps track of the possible arguments to {@code Cipher#init(...)}.
+     */
+    static class InitParams {
+        final InitType initType;
+        final int opmode;
+        final Key key;
+        final SecureRandom random;
+        final AlgorithmParameterSpec spec;
+        final AlgorithmParameters params;
+
+        InitParams(InitType initType, int opmode, Key key, SecureRandom random,
+                AlgorithmParameterSpec spec, AlgorithmParameters params) {
+            this.initType = initType;
+            this.opmode = opmode;
+            this.key = key;
+            this.random = random;
+            this.spec = spec;
+            this.params = params;
+        }
+    }
+
+    /**
+     * Used to keep track of which underlying {@code CipherSpi#engineInit(...)}
+     * variant to call when testing suitability.
+     */
+    static enum InitType {
+        KEY, ALGORITHM_PARAMS, ALGORITHM_PARAM_SPEC,
+    }
+
+    class SpiAndProviderUpdater {
+        /**
+         * Lock held while the SPI is initializing.
+         */
+        private final Object initSpiLock = new Object();
+
+        /**
+         * The provider specified when instance created.
+         */
+        private final Provider specifiedProvider;
+
+        /**
+         * The SPI implementation.
+         */
+        private final CipherSpi specifiedSpi;
+
+        SpiAndProviderUpdater(Provider specifiedProvider, CipherSpi specifiedSpi) {
+            this.specifiedProvider = specifiedProvider;
+            this.specifiedSpi = specifiedSpi;
+        }
+
+        void setCipherSpiImplAndProvider(CipherSpi cipherSpi, Provider provider) {
+            Cipher.this.spi = cipherSpi;
+            Cipher.this.provider = provider;
+        }
+
+        /**
+         * Makes sure a CipherSpi that matches this type is selected. If
+         * {@code key != null} then it assumes that a suitable provider exists for
+         * this instance (used by {@link Cipher#init}. If the {@code initParams} is passed
+         * in, then the {@code CipherSpi} returned will be initialized.
+         *
+         * @throws InvalidKeyException if the specified key cannot be used to
+         *                             initialize this cipher.
+         */
+        CipherSpiAndProvider updateAndGetSpiAndProvider(
+                InitParams initParams,
+                CipherSpi spiImpl,
+                Provider provider)
+                throws InvalidKeyException, InvalidAlgorithmParameterException {
+            if (specifiedSpi != null) {
+                return new CipherSpiAndProvider(specifiedSpi, provider);
+            }
+            synchronized (initSpiLock) {
+                // This is not only a matter of performance. Many methods like update, doFinal, etc.
+                // call {@code #getSpi()} (ie, {@code #getSpi(null /* params */)}) and without this
+                // shortcut they would override an spi that was chosen using the key.
+                if (spiImpl != null && initParams == null) {
+                    return new CipherSpiAndProvider(spiImpl, provider);
+                }
+                final CipherSpiAndProvider sap = tryCombinations(
+                        initParams, specifiedProvider, tokenizedTransformation);
+                if (sap == null) {
+                    throw new ProviderException("No provider found for "
+                            + Arrays.toString(tokenizedTransformation));
+                }
+                setCipherSpiImplAndProvider(sap.cipherSpi, sap.provider);
+                return new CipherSpiAndProvider(sap.cipherSpi, sap.provider);
+            }
+        }
+
+        /**
+         * Convenience call when the Key is not available.
+         */
+        CipherSpiAndProvider updateAndGetSpiAndProvider(CipherSpi spiImpl, Provider provider) {
+            try {
+                return updateAndGetSpiAndProvider(null, spiImpl, provider);
+            } catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
+                throw new ProviderException("Exception thrown when params == null", e);
+           }
+        }
+
+        CipherSpi getCurrentSpi(CipherSpi spiImpl) {
+            if (specifiedSpi != null) {
+                return specifiedSpi;
+            }
+
+            synchronized (initSpiLock) {
+                return spiImpl;
+            }
+        }
+    }
+
+    /**
+     * Tries to find the correct {@code Cipher} transform to use. Returns a
+     * {@link org.apache.harmony.security.fortress.Engine.SpiAndProvider}, throws the first exception that was
+     * encountered during attempted initialization, or {@code null} if there are
+     * no providers that support the {@code initParams}.
+     * <p>
+     * {@code tokenizedTransformation} must be in the format returned by
+     * {@link Cipher#checkTransformation(String)}. The combinations of mode strings
+     * tried are as follows:
+     * <ul>
+     * <li><code>[cipher]/[mode]/[padding]</code>
+     * <li><code>[cipher]/[mode]</code>
+     * <li><code>[cipher]//[padding]</code>
+     * <li><code>[cipher]</code>
+     * </ul>
+     * {@code services} is a list of cipher services. Needs to be non-null only if
+     * {@code provider != null}
+     */
+    static CipherSpiAndProvider tryCombinations(InitParams initParams, Provider provider,
+            String[] tokenizedTransformation)
+            throws InvalidKeyException,
+            InvalidAlgorithmParameterException {
+        // Enumerate all the transforms we need to try
+        ArrayList<Transform> transforms = new ArrayList<Transform>();
+        if (tokenizedTransformation[1] != null && tokenizedTransformation[2] != null) {
+            transforms.add(new Transform(tokenizedTransformation[0] + "/" + tokenizedTransformation[1] + "/"
+                    + tokenizedTransformation[2], NeedToSet.NONE));
+        }
+        if (tokenizedTransformation[1] != null) {
+            transforms.add(new Transform(tokenizedTransformation[0] + "/" + tokenizedTransformation[1],
+                    NeedToSet.PADDING));
+        }
+        if (tokenizedTransformation[2] != null) {
+            transforms.add(new Transform(tokenizedTransformation[0] + "//" + tokenizedTransformation[2],
+                    NeedToSet.MODE));
+        }
+        transforms.add(new Transform(tokenizedTransformation[0], NeedToSet.BOTH));
+
+        // Try each of the transforms and keep track of the first exception
+        // encountered.
+        Exception cause = null;
+
+        if (provider != null) {
+            for (Transform transform : transforms) {
+                Provider.Service service = provider.getService("Cipher", transform.name);
+                if (service == null) {
+                    continue;
+                }
+                return tryTransformWithProvider(initParams, tokenizedTransformation, transform.needToSet,
+                                service);
+            }
+        } else {
+            for (Provider prov : Security.getProviders()) {
+                for (Transform transform : transforms) {
+                    Provider.Service service = prov.getService("Cipher", transform.name);
+                    if (service == null) {
+                        continue;
+                    }
+
+                    if (initParams == null || initParams.key == null
+                            || service.supportsParameter(initParams.key)) {
+                        try {
+                            CipherSpiAndProvider sap = tryTransformWithProvider(initParams,
+                                    tokenizedTransformation, transform.needToSet, service);
+                            if (sap != null) {
+                                return sap;
+                            }
+                        } catch (Exception e) {
+                            if (cause == null) {
+                                cause = e;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        if (cause instanceof InvalidKeyException) {
+            throw (InvalidKeyException) cause;
+        } else if (cause instanceof InvalidAlgorithmParameterException) {
+            throw (InvalidAlgorithmParameterException) cause;
+        } else if (cause instanceof RuntimeException) {
+            throw (RuntimeException) cause;
+        } else if (cause != null) {
+            throw new InvalidKeyException("No provider can be initialized with given key", cause);
+        } else if (initParams == null || initParams.key == null) {
+            return null;
+        } else {
+            // Since the key is not null, a suitable provider exists,
+            // and it is an InvalidKeyException.
+            throw new InvalidKeyException(
+                    "No provider offers " + Arrays.toString(tokenizedTransformation) + " for "
+                    + initParams.key.getAlgorithm() + " key of class "
+                    + initParams.key.getClass().getName() + " and export format "
+                    + initParams.key.getFormat());
+        }
+    }
+
+    static class CipherSpiAndProvider {
+        CipherSpi cipherSpi;
+        Provider provider;
+
+        CipherSpiAndProvider(CipherSpi cipherSpi, Provider provider) {
+            this.cipherSpi = cipherSpi;
+            this.provider = provider;
+        }
+    }
+
+    /**
+     * Tries to initialize the {@code Cipher} from a given {@code service}. If
+     * initialization is successful, the initialized {@code spi} is returned. If
+     * the {@code service} cannot be initialized with the specified
+     * {@code initParams}, then it's expected to throw
+     * {@code InvalidKeyException} or {@code InvalidAlgorithmParameterException}
+     * as a hint to the caller that it should continue searching for a
+     * {@code Service} that will work.
+     */
+    static CipherSpiAndProvider tryTransformWithProvider(InitParams initParams,
+            String[] tokenizedTransformation, NeedToSet type, Provider.Service service)
+                throws InvalidKeyException, InvalidAlgorithmParameterException  {
+        try {
+            /*
+             * Check to see if the Cipher even supports the attributes before
+             * trying to instantiate it.
+             */
+            if (!matchAttribute(service, ATTRIBUTE_MODES, tokenizedTransformation[1])
+                    || !matchAttribute(service, ATTRIBUTE_PADDINGS, tokenizedTransformation[2])) {
+                return null;
+            }
+
+            CipherSpiAndProvider sap = new CipherSpiAndProvider(
+                (CipherSpi) service.newInstance(null), service.getProvider());
+            if (sap.cipherSpi == null || sap.provider == null) {
+                return null;
+            }
+            CipherSpi spi = sap.cipherSpi;
+            if (((type == NeedToSet.MODE) || (type == NeedToSet.BOTH))
+                    && (tokenizedTransformation[1] != null)) {
+                spi.engineSetMode(tokenizedTransformation[1]);
+            }
+            if (((type == NeedToSet.PADDING) || (type == NeedToSet.BOTH))
+                    && (tokenizedTransformation[2] != null)) {
+                spi.engineSetPadding(tokenizedTransformation[2]);
+            }
+
+            if (initParams != null) {
+                switch (initParams.initType) {
+                    case ALGORITHM_PARAMS:
+                        spi.engineInit(initParams.opmode, initParams.key, initParams.params,
+                                initParams.random);
+                        break;
+                    case ALGORITHM_PARAM_SPEC:
+                        spi.engineInit(initParams.opmode, initParams.key, initParams.spec,
+                                initParams.random);
+                        break;
+                    case KEY:
+                        spi.engineInit(initParams.opmode, initParams.key, initParams.random);
+                        break;
+                    default:
+                        throw new AssertionError("This should never be reached");
+                }
+            }
+            return new CipherSpiAndProvider(spi, sap.provider);
+        } catch (NoSuchAlgorithmException ignored) {
+        } catch (NoSuchPaddingException ignored) {
+        }
+        return null;
+    }
+    // END Android-added: Bulk of the new provider implementation.
+}
diff --git a/javax/crypto/CipherInputStream.java b/javax/crypto/CipherInputStream.java
new file mode 100644
index 0000000..8cbda3b
--- /dev/null
+++ b/javax/crypto/CipherInputStream.java
@@ -0,0 +1,357 @@
+/*
+ * 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 javax.crypto;
+
+import java.io.InputStream;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+
+/**
+ * A CipherInputStream is composed of an InputStream and a Cipher so
+ * that read() methods return data that are read in from the
+ * underlying InputStream but have been additionally processed by the
+ * Cipher.  The Cipher must be fully initialized before being used by
+ * a CipherInputStream.
+ *
+ * <p> For example, if the Cipher is initialized for decryption, the
+ * CipherInputStream will attempt to read in data and decrypt them,
+ * before returning the decrypted data.
+ *
+ * <p> This class adheres strictly to the semantics, especially the
+ * failure semantics, of its ancestor classes
+ * java.io.FilterInputStream and java.io.InputStream.  This class has
+ * exactly those methods specified in its ancestor classes, and
+ * overrides them all.  Moreover, this class catches all exceptions
+ * that are not thrown by its ancestor classes.  In particular, the
+ * <code>skip</code> method skips, and the <code>available</code>
+ * method counts only data that have been processed by the encapsulated Cipher.
+ *
+ * <p> It is crucial for a programmer using this class not to use
+ * methods that are not defined or overriden in this class (such as a
+ * new method or constructor that is later added to one of the super
+ * classes), because the design and implementation of those methods
+ * are unlikely to have considered security impact with regard to
+ * CipherInputStream.
+ *
+ * @author  Li Gong
+ * @see     java.io.InputStream
+ * @see     java.io.FilterInputStream
+ * @see     javax.crypto.Cipher
+ * @see     javax.crypto.CipherOutputStream
+ *
+ * @since 1.4
+ */
+
+public class CipherInputStream extends FilterInputStream {
+
+    // the cipher engine to use to process stream data
+    private Cipher cipher;
+
+    // the underlying input stream
+    private InputStream input;
+
+    /* the buffer holding data that have been read in from the
+       underlying stream, but have not been processed by the cipher
+       engine. the size 512 bytes is somewhat randomly chosen */
+    private byte[] ibuffer = new byte[512];
+
+    // having reached the end of the underlying input stream
+    private boolean done = false;
+
+    /* the buffer holding data that have been processed by the cipher
+       engine, but have not been read out */
+    private byte[] obuffer;
+    // the offset pointing to the next "new" byte
+    private int ostart = 0;
+    // the offset pointing to the last "new" byte
+    private int ofinish = 0;
+    // stream status
+    private boolean closed = false;
+
+    /**
+     * private convenience function.
+     *
+     * Entry condition: ostart = ofinish
+     *
+     * Exit condition: ostart <= ofinish
+     *
+     * return (ofinish-ostart) (we have this many bytes for you)
+     * return 0 (no data now, but could have more later)
+     * return -1 (absolutely no more data)
+     *
+     * Note:  Exceptions are only thrown after the stream is completely read.
+     * For AEAD ciphers a read() of any length will internally cause the
+     * whole stream to be read fully and verify the authentication tag before
+     * returning decrypted data or exceptions.
+     */
+    private int getMoreData() throws IOException {
+        // Android-changed: The method was creating a new object every time update(byte[], int, int)
+        // or doFinal() was called resulting in the old object being GCed. With do(byte[], int) and
+        // update(byte[], int, int, byte[], int), we use already initialized obuffer.
+        if (done) return -1;
+        ofinish = 0;
+        ostart = 0;
+        int expectedOutputSize = cipher.getOutputSize(ibuffer.length);
+        if (obuffer == null || expectedOutputSize > obuffer.length) {
+            obuffer = new byte[expectedOutputSize];
+        }
+        int readin = input.read(ibuffer);
+        if (readin == -1) {
+            done = true;
+            try {
+                // doFinal resets the cipher and it is the final call that is made. If there isn't
+                // any more byte available, it returns 0. In case of any exception is raised,
+                // obuffer will get reset and therefore, it is equivalent to no bytes returned.
+                ofinish = cipher.doFinal(obuffer, 0);
+            } catch (IllegalBlockSizeException | BadPaddingException e) {
+                obuffer = null;
+                throw new IOException(e);
+            } catch (ShortBufferException e) {
+                obuffer = null;
+                throw new IllegalStateException("ShortBufferException is not expected", e);
+            }
+        } else {
+            // update returns number of bytes stored in obuffer.
+            try {
+                ofinish = cipher.update(ibuffer, 0, readin, obuffer, 0);
+            } catch (IllegalStateException e) {
+                obuffer = null;
+                throw e;
+            } catch (ShortBufferException e) {
+                // Should not reset the value of ofinish as the cipher is still not invalidated.
+                obuffer = null;
+                throw new IllegalStateException("ShortBufferException is not expected", e);
+            }
+        }
+        return ofinish;
+    }
+
+    /**
+     * Constructs a CipherInputStream from an InputStream and a
+     * Cipher.
+     * <br>Note: if the specified input stream or cipher is
+     * null, a NullPointerException may be thrown later when
+     * they are used.
+     * @param is the to-be-processed input stream
+     * @param c an initialized Cipher object
+     */
+    public CipherInputStream(InputStream is, Cipher c) {
+        super(is);
+        input = is;
+        cipher = c;
+    }
+
+    /**
+     * Constructs a CipherInputStream from an InputStream without
+     * specifying a Cipher. This has the effect of constructing a
+     * CipherInputStream using a NullCipher.
+     * <br>Note: if the specified input stream is null, a
+     * NullPointerException may be thrown later when it is used.
+     * @param is the to-be-processed input stream
+     */
+    protected CipherInputStream(InputStream is) {
+        super(is);
+        input = is;
+        cipher = new NullCipher();
+    }
+
+    /**
+     * 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>
+     *
+     * @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.
+     * @since JCE1.2
+     */
+    public int read() throws IOException {
+        if (ostart >= ofinish) {
+            // we loop for new data as the spec says we are blocking
+            int i = 0;
+            while (i == 0) i = getMoreData();
+            if (i == -1) return -1;
+        }
+        return ((int) obuffer[ostart++] & 0xff);
+    };
+
+    /**
+     * Reads up to <code>b.length</code> bytes of data from this input
+     * stream into an array of bytes.
+     * <p>
+     * The <code>read</code> method of <code>InputStream</code> calls
+     * the <code>read</code> method of three arguments with the arguments
+     * <code>b</code>, <code>0</code>, and <code>b.length</code>.
+     *
+     * @param      b   the buffer into which the data is read.
+     * @return     the total number of bytes read into the buffer, or
+     *             <code>-1</code> is 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.InputStream#read(byte[], int, int)
+     * @since      JCE1.2
+     */
+    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. This method blocks until some input is
+     * available. If the first argument is <code>null,</code> up to
+     * <code>len</code> bytes are read and discarded.
+     *
+     * @param      b     the buffer into which the data is read.
+     * @param      off   the start offset in the destination array
+     *                   <code>buf</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  IOException  if an I/O error occurs.
+     * @see        java.io.InputStream#read()
+     * @since      JCE1.2
+     */
+    public int read(byte b[], int off, int len) throws IOException {
+        if (ostart >= ofinish) {
+            // we loop for new data as the spec says we are blocking
+            int i = 0;
+            while (i == 0) i = getMoreData();
+            if (i == -1) return -1;
+        }
+        if (len <= 0) {
+            return 0;
+        }
+        int available = ofinish - ostart;
+        if (len < available) available = len;
+        if (b != null) {
+            System.arraycopy(obuffer, ostart, b, off, available);
+        }
+        ostart = ostart + available;
+        return available;
+    }
+
+    /**
+     * Skips <code>n</code> bytes of input from the bytes that can be read
+     * from this input stream without blocking.
+     *
+     * <p>Fewer bytes than requested might be skipped.
+     * The actual number of bytes skipped is equal to <code>n</code> or
+     * the result of a call to
+     * {@link #available() available},
+     * whichever is smaller.
+     * If <code>n</code> is less than zero, no bytes are skipped.
+     *
+     * <p>The actual number of bytes skipped is returned.
+     *
+     * @param      n the number of bytes to be skipped.
+     * @return     the actual number of bytes skipped.
+     * @exception  IOException  if an I/O error occurs.
+     * @since JCE1.2
+     */
+    public long skip(long n) throws IOException {
+        int available = ofinish - ostart;
+        if (n > available) {
+            n = available;
+        }
+        if (n < 0) {
+            return 0;
+        }
+        ostart += n;
+        return n;
+    }
+
+    /**
+     * Returns the number of bytes that can be read from this input
+     * stream without blocking. The <code>available</code> method of
+     * <code>InputStream</code> returns <code>0</code>. This method
+     * <B>should</B> be overridden by subclasses.
+     *
+     * @return     the number of bytes that can be read from this input stream
+     *             without blocking.
+     * @exception  IOException  if an I/O error occurs.
+     * @since      JCE1.2
+     */
+    public int available() throws IOException {
+        return (ofinish - ostart);
+    }
+
+    /**
+     * Closes this input stream and releases any system resources
+     * associated with the stream.
+     * <p>
+     * The <code>close</code> method of <code>CipherInputStream</code>
+     * calls the <code>close</code> method of its underlying input
+     * stream.
+     *
+     * @exception  IOException  if an I/O error occurs.
+     * @since JCE1.2
+     */
+    public void close() throws IOException {
+        if (closed) {
+            return;
+        }
+
+        closed = true;
+        input.close();
+
+        // Android-removed: Removed a now-inaccurate comment
+        if (!done) {
+            try {
+                cipher.doFinal();
+            }
+            catch (BadPaddingException | IllegalBlockSizeException ex) {
+                // Android-changed: Added throw if bad tag is seen.  See b/31590622.
+                if (ex instanceof AEADBadTagException) {
+                    throw new IOException(ex);
+                }
+            }
+        }
+        ostart = 0;
+        ofinish = 0;
+    }
+
+    /**
+     * 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()
+     * @since   JCE1.2
+     */
+    public boolean markSupported() {
+        return false;
+    }
+}
diff --git a/javax/crypto/CipherOutputStream.java b/javax/crypto/CipherOutputStream.java
new file mode 100644
index 0000000..370f7af
--- /dev/null
+++ b/javax/crypto/CipherOutputStream.java
@@ -0,0 +1,221 @@
+/*
+ * 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 javax.crypto;
+
+import java.io.*;
+
+/**
+ * A CipherOutputStream is composed of an OutputStream and a Cipher so
+ * that write() methods first process the data before writing them out
+ * to the underlying OutputStream.  The cipher must be fully
+ * initialized before being used by a CipherOutputStream.
+ *
+ * <p> For example, if the cipher is initialized for encryption, the
+ * CipherOutputStream will attempt to encrypt data before writing out the
+ * encrypted data.
+ *
+ * <p> This class adheres strictly to the semantics, especially the
+ * failure semantics, of its ancestor classes
+ * java.io.OutputStream and java.io.FilterOutputStream.  This class
+ * has exactly those methods specified in its ancestor classes, and
+ * overrides them all.  Moreover, this class catches all exceptions
+ * that are not thrown by its ancestor classes.
+ *
+ * <p> It is crucial for a programmer using this class not to use
+ * methods that are not defined or overriden in this class (such as a
+ * new method or constructor that is later added to one of the super
+ * classes), because the design and implementation of those methods
+ * are unlikely to have considered security impact with regard to
+ * CipherOutputStream.
+ *
+ * @author  Li Gong
+ * @see     java.io.OutputStream
+ * @see     java.io.FilterOutputStream
+ * @see     javax.crypto.Cipher
+ * @see     javax.crypto.CipherInputStream
+ *
+ * @since 1.4
+ */
+
+public class CipherOutputStream extends FilterOutputStream {
+
+    // the cipher engine to use to process stream data
+    private Cipher cipher;
+
+    // the underlying output stream
+    private OutputStream output;
+
+    /* the buffer holding one byte of incoming data */
+    private byte[] ibuffer = new byte[1];
+
+    // the buffer holding data ready to be written out
+    private byte[] obuffer;
+
+    // stream status
+    private boolean closed = false;
+
+    /**
+     *
+     * Constructs a CipherOutputStream from an OutputStream and a
+     * Cipher.
+     * <br>Note: if the specified output stream or cipher is
+     * null, a NullPointerException may be thrown later when
+     * they are used.
+     *
+     * @param os  the OutputStream object
+     * @param c   an initialized Cipher object
+     */
+    public CipherOutputStream(OutputStream os, Cipher c) {
+        super(os);
+        output = os;
+        cipher = c;
+    };
+
+    /**
+     * Constructs a CipherOutputStream from an OutputStream without
+     * specifying a Cipher. This has the effect of constructing a
+     * CipherOutputStream using a NullCipher.
+     * <br>Note: if the specified output stream is null, a
+     * NullPointerException may be thrown later when it is used.
+     *
+     * @param os  the OutputStream object
+     */
+    protected CipherOutputStream(OutputStream os) {
+        super(os);
+        output = os;
+        cipher = new NullCipher();
+    }
+
+    /**
+     * Writes the specified byte to this output stream.
+     *
+     * @param      b   the <code>byte</code>.
+     * @exception  IOException  if an I/O error occurs.
+     * @since      JCE1.2
+     */
+    public void write(int b) throws IOException {
+        ibuffer[0] = (byte) b;
+        obuffer = cipher.update(ibuffer, 0, 1);
+        if (obuffer != null) {
+            output.write(obuffer);
+            obuffer = null;
+        }
+    };
+
+    /**
+     * Writes <code>b.length</code> bytes from the specified byte array
+     * to this output stream.
+     * <p>
+     * The <code>write</code> method of
+     * <code>CipherOutputStream</code> calls the <code>write</code>
+     * method of three arguments with the three arguments
+     * <code>b</code>, <code>0</code>, and <code>b.length</code>.
+     *
+     * @param      b   the data.
+     * @exception  NullPointerException if <code>b</code> is null.
+     * @exception  IOException  if an I/O error occurs.
+     * @see        javax.crypto.CipherOutputStream#write(byte[], int, int)
+     * @since JCE1.2
+     */
+    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.
+     *
+     * @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.
+     * @since      JCE1.2
+     */
+    public void write(byte b[], int off, int len) throws IOException {
+        obuffer = cipher.update(b, off, len);
+        if (obuffer != null) {
+            output.write(obuffer);
+            obuffer = null;
+        }
+    }
+
+    /**
+     * Flushes this output stream by forcing any buffered output bytes
+     * that have already been processed by the encapsulated cipher object
+     * to be written out.
+     *
+     * <p>Any bytes buffered by the encapsulated cipher
+     * and waiting to be processed by it will not be written out. For example,
+     * if the encapsulated cipher is a block cipher, and the total number of
+     * bytes written using one of the <code>write</code> methods is less than
+     * the cipher's block size, no bytes will be written out.
+     *
+     * @exception  IOException  if an I/O error occurs.
+     * @since      JCE1.2
+     */
+    public void flush() throws IOException {
+        if (obuffer != null) {
+            output.write(obuffer);
+            obuffer = null;
+        }
+        output.flush();
+    }
+
+    /**
+     * Closes this output stream and releases any system resources
+     * associated with this stream.
+     * <p>
+     * This method invokes the <code>doFinal</code> method of the encapsulated
+     * cipher object, which causes any bytes buffered by the encapsulated
+     * cipher to be processed. The result is written out by calling the
+     * <code>flush</code> method of this output stream.
+     * <p>
+     * This method resets the encapsulated cipher object to its initial state
+     * and calls the <code>close</code> method of the underlying output
+     * stream.
+     *
+     * @exception  IOException  if an I/O error occurs.
+     * @since      JCE1.2
+     */
+    public void close() throws IOException {
+        if (closed) {
+            return;
+        }
+
+        closed = true;
+        try {
+            obuffer = cipher.doFinal();
+        } catch (IllegalBlockSizeException | BadPaddingException e) {
+            obuffer = null;
+            // Android-added: Throw an exception when the underlying cipher does.  http://b/36636576
+            throw new IOException(e);
+        }
+        try {
+            flush();
+        } catch (IOException ignored) {}
+        out.close();
+    }
+}
diff --git a/javax/crypto/CipherSpi.java b/javax/crypto/CipherSpi.java
new file mode 100644
index 0000000..ce72581
--- /dev/null
+++ b/javax/crypto/CipherSpi.java
@@ -0,0 +1,1011 @@
+/*
+ * 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 javax.crypto;
+
+import java.util.StringTokenizer;
+import java.util.NoSuchElementException;
+import java.security.AlgorithmParameters;
+import java.security.Provider;
+import java.security.Key;
+import java.security.SecureRandom;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.InvalidKeyException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.ProviderException;
+import java.security.spec.AlgorithmParameterSpec;
+
+import java.nio.ByteBuffer;
+
+/**
+ * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>)
+ * for the <code>Cipher</code> class.
+ * All the abstract methods in this class must be implemented by each
+ * cryptographic service provider who wishes to supply the implementation
+ * of a particular cipher algorithm.
+ *
+ * <p>In order to create an instance of <code>Cipher</code>, which
+ * encapsulates an instance of this <code>CipherSpi</code> class, an
+ * application calls one of the
+ * {@link Cipher#getInstance(java.lang.String) getInstance}
+ * factory methods of the
+ * {@link Cipher Cipher} engine class and specifies the requested
+ * <i>transformation</i>.
+ * Optionally, the application may also specify the name of a provider.
+ *
+ * <p>A <i>transformation</i> is a string that describes the operation (or
+ * set of operations) to be performed on the given input, to produce some
+ * output. A transformation always includes the name of a cryptographic
+ * algorithm (e.g., <i>DES</i>), and may be followed by a feedback mode and
+ * padding scheme.
+ *
+ * <p> A transformation is of the form:
+ *
+ * <ul>
+ * <li>"<i>algorithm/mode/padding</i>" or
+ *
+ * <li>"<i>algorithm</i>"
+ * </ul>
+ *
+ * <P> (in the latter case,
+ * provider-specific default values for the mode and padding scheme are used).
+ * For example, the following is a valid transformation:
+ *
+ * <pre>
+ *     Cipher c = Cipher.getInstance("<i>DES/CBC/PKCS5Padding</i>");
+ * </pre>
+ *
+ * <p>A provider may supply a separate class for each combination
+ * of <i>algorithm/mode/padding</i>, or may decide to provide more generic
+ * classes representing sub-transformations corresponding to
+ * <i>algorithm</i> or <i>algorithm/mode</i> or <i>algorithm//padding</i>
+ * (note the double slashes),
+ * in which case the requested mode and/or padding are set automatically by
+ * the <code>getInstance</code> methods of <code>Cipher</code>, which invoke
+ * the {@link #engineSetMode(java.lang.String) engineSetMode} and
+ * {@link #engineSetPadding(java.lang.String) engineSetPadding}
+ * methods of the provider's subclass of <code>CipherSpi</code>.
+ *
+ * <p>A <code>Cipher</code> property in a provider master class may have one of
+ * the following formats:
+ *
+ * <ul>
+ *
+ * <li>
+ * <pre>
+ *     // provider's subclass of "CipherSpi" implements "algName" with
+ *     // pluggable mode and padding
+ *     <code>Cipher.</code><i>algName</i>
+ * </pre>
+ *
+ * <li>
+ * <pre>
+ *     // provider's subclass of "CipherSpi" implements "algName" in the
+ *     // specified "mode", with pluggable padding
+ *     <code>Cipher.</code><i>algName/mode</i>
+ * </pre>
+ *
+ * <li>
+ * <pre>
+ *     // provider's subclass of "CipherSpi" implements "algName" with the
+ *     // specified "padding", with pluggable mode
+ *     <code>Cipher.</code><i>algName//padding</i>
+ * </pre>
+ *
+ * <li>
+ * <pre>
+ *     // provider's subclass of "CipherSpi" implements "algName" with the
+ *     // specified "mode" and "padding"
+ *     <code>Cipher.</code><i>algName/mode/padding</i>
+ * </pre>
+ *
+ * </ul>
+ *
+ * <p>For example, a provider may supply a subclass of <code>CipherSpi</code>
+ * that implements <i>DES/ECB/PKCS5Padding</i>, one that implements
+ * <i>DES/CBC/PKCS5Padding</i>, one that implements
+ * <i>DES/CFB/PKCS5Padding</i>, and yet another one that implements
+ * <i>DES/OFB/PKCS5Padding</i>. That provider would have the following
+ * <code>Cipher</code> properties in its master class:
+ *
+ * <ul>
+ *
+ * <li>
+ * <pre>
+ *     <code>Cipher.</code><i>DES/ECB/PKCS5Padding</i>
+ * </pre>
+ *
+ * <li>
+ * <pre>
+ *     <code>Cipher.</code><i>DES/CBC/PKCS5Padding</i>
+ * </pre>
+ *
+ * <li>
+ * <pre>
+ *     <code>Cipher.</code><i>DES/CFB/PKCS5Padding</i>
+ * </pre>
+ *
+ * <li>
+ * <pre>
+ *     <code>Cipher.</code><i>DES/OFB/PKCS5Padding</i>
+ * </pre>
+ *
+ * </ul>
+ *
+ * <p>Another provider may implement a class for each of the above modes
+ * (i.e., one class for <i>ECB</i>, one for <i>CBC</i>, one for <i>CFB</i>,
+ * and one for <i>OFB</i>), one class for <i>PKCS5Padding</i>,
+ * and a generic <i>DES</i> class that subclasses from <code>CipherSpi</code>.
+ * That provider would have the following
+ * <code>Cipher</code> properties in its master class:
+ *
+ * <ul>
+ *
+ * <li>
+ * <pre>
+ *     <code>Cipher.</code><i>DES</i>
+ * </pre>
+ *
+ * </ul>
+ *
+ * <p>The <code>getInstance</code> factory method of the <code>Cipher</code>
+ * engine class follows these rules in order to instantiate a provider's
+ * implementation of <code>CipherSpi</code> for a
+ * transformation of the form "<i>algorithm</i>":
+ *
+ * <ol>
+ * <li>
+ * Check if the provider has registered a subclass of <code>CipherSpi</code>
+ * for the specified "<i>algorithm</i>".
+ * <p>If the answer is YES, instantiate this
+ * class, for whose mode and padding scheme default values (as supplied by
+ * the provider) are used.
+ * <p>If the answer is NO, throw a <code>NoSuchAlgorithmException</code>
+ * exception.
+ * </ol>
+ *
+ * <p>The <code>getInstance</code> factory method of the <code>Cipher</code>
+ * engine class follows these rules in order to instantiate a provider's
+ * implementation of <code>CipherSpi</code> for a
+ * transformation of the form "<i>algorithm/mode/padding</i>":
+ *
+ * <ol>
+ * <li>
+ * Check if the provider has registered a subclass of <code>CipherSpi</code>
+ * for the specified "<i>algorithm/mode/padding</i>" transformation.
+ * <p>If the answer is YES, instantiate it.
+ * <p>If the answer is NO, go to the next step.
+ * <li>
+ * Check if the provider has registered a subclass of <code>CipherSpi</code>
+ * for the sub-transformation "<i>algorithm/mode</i>".
+ * <p>If the answer is YES, instantiate it, and call
+ * <code>engineSetPadding(<i>padding</i>)</code> on the new instance.
+ * <p>If the answer is NO, go to the next step.
+ * <li>
+ * Check if the provider has registered a subclass of <code>CipherSpi</code>
+ * for the sub-transformation "<i>algorithm//padding</i>" (note the double
+ * slashes).
+ * <p>If the answer is YES, instantiate it, and call
+ * <code>engineSetMode(<i>mode</i>)</code> on the new instance.
+ * <p>If the answer is NO, go to the next step.
+ * <li>
+ * Check if the provider has registered a subclass of <code>CipherSpi</code>
+ * for the sub-transformation "<i>algorithm</i>".
+ * <p>If the answer is YES, instantiate it, and call
+ * <code>engineSetMode(<i>mode</i>)</code> and
+ * <code>engineSetPadding(<i>padding</i>)</code> on the new instance.
+ * <p>If the answer is NO, throw a <code>NoSuchAlgorithmException</code>
+ * exception.
+ * </ol>
+ *
+ * @author Jan Luehe
+ * @see KeyGenerator
+ * @see SecretKey
+ * @since 1.4
+ */
+
+public abstract class CipherSpi {
+
+    /**
+     * Sets the mode of this cipher.
+     *
+     * @param mode the cipher mode
+     *
+     * @exception NoSuchAlgorithmException if the requested cipher mode does
+     * not exist
+     */
+    protected abstract void engineSetMode(String mode)
+        throws NoSuchAlgorithmException;
+
+    /**
+     * Sets the padding mechanism of this cipher.
+     *
+     * @param padding the padding mechanism
+     *
+     * @exception NoSuchPaddingException if the requested padding mechanism
+     * does not exist
+     */
+    protected abstract void engineSetPadding(String padding)
+        throws NoSuchPaddingException;
+
+    /**
+     * Returns the block size (in bytes).
+     *
+     * @return the block size (in bytes), or 0 if the underlying algorithm is
+     * not a block cipher
+     */
+    protected abstract int engineGetBlockSize();
+
+    /**
+     * Returns the length in bytes that an output buffer would
+     * need to be in order to hold the result of the next <code>update</code>
+     * or <code>doFinal</code> operation, given the input length
+     * <code>inputLen</code> (in bytes).
+     *
+     * <p>This call takes into account any unprocessed (buffered) data from a
+     * previous <code>update</code> call, padding, and AEAD tagging.
+     *
+     * <p>The actual output length of the next <code>update</code> or
+     * <code>doFinal</code> call may be smaller than the length returned by
+     * this method.
+     *
+     * @param inputLen the input length (in bytes)
+     *
+     * @return the required output buffer size (in bytes)
+     */
+    protected abstract int engineGetOutputSize(int inputLen);
+
+    /**
+     * Returns the initialization vector (IV) in a new buffer.
+     *
+     * <p> This is useful in the context of password-based encryption or
+     * decryption, where the IV is derived from a user-provided passphrase.
+     *
+     * @return the initialization vector in a new buffer, or null if the
+     * underlying algorithm does not use an IV, or if the IV has not yet
+     * been set.
+     */
+    protected abstract byte[] engineGetIV();
+
+    /**
+     * Returns the parameters used with this cipher.
+     *
+     * <p>The returned parameters may be the same that were used to initialize
+     * this cipher, or may contain a combination of default and random
+     * parameter values used by the underlying cipher implementation if this
+     * cipher requires algorithm parameters but was not initialized with any.
+     *
+     * @return the parameters used with this cipher, or null if this cipher
+     * does not use any parameters.
+     */
+    protected abstract AlgorithmParameters engineGetParameters();
+
+    /**
+     * Initializes this cipher with a key and a source
+     * of randomness.
+     *
+     * <p>The cipher is initialized for one of the following four operations:
+     * encryption, decryption, key wrapping or key unwrapping, depending on
+     * the value of <code>opmode</code>.
+     *
+     * <p>If this cipher requires any algorithm parameters that cannot be
+     * derived from the given <code>key</code>, the underlying cipher
+     * implementation is supposed to generate the required parameters itself
+     * (using provider-specific default or random values) if it is being
+     * initialized for encryption or key wrapping, and raise an
+     * <code>InvalidKeyException</code> if it is being
+     * initialized for decryption or key unwrapping.
+     * The generated parameters can be retrieved using
+     * {@link #engineGetParameters() engineGetParameters} or
+     * {@link #engineGetIV() engineGetIV} (if the parameter is an IV).
+     *
+     * <p>If this cipher requires algorithm parameters that cannot be
+     * derived from the input parameters, and there are no reasonable
+     * provider-specific default values, initialization will
+     * necessarily fail.
+     *
+     * <p>If this cipher (including its underlying feedback or padding scheme)
+     * requires any random bytes (e.g., for parameter generation), it will get
+     * them from <code>random</code>.
+     *
+     * <p>Note that when a Cipher object is initialized, it loses all
+     * previously-acquired state. In other words, initializing a Cipher is
+     * equivalent to creating a new instance of that Cipher and initializing
+     * it.
+     *
+     * @param opmode the operation mode of this cipher (this is one of
+     * the following:
+     * <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,
+     * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)
+     * @param key the encryption key
+     * @param random the source of randomness
+     *
+     * @exception InvalidKeyException if the given key is inappropriate for
+     * initializing this cipher, or requires
+     * algorithm parameters that cannot be
+     * determined from the given key.
+     * @throws UnsupportedOperationException if {@code opmode} is
+     * {@code WRAP_MODE} or {@code UNWRAP_MODE} is not implemented
+     * by the cipher.
+     */
+    protected abstract void engineInit(int opmode, Key key,
+                                       SecureRandom random)
+        throws InvalidKeyException;
+
+    /**
+     * Initializes this cipher with a key, a set of
+     * algorithm parameters, and a source of randomness.
+     *
+     * <p>The cipher is initialized for one of the following four operations:
+     * encryption, decryption, key wrapping or key unwrapping, depending on
+     * the value of <code>opmode</code>.
+     *
+     * <p>If this cipher requires any algorithm parameters and
+     * <code>params</code> is null, the underlying cipher implementation is
+     * supposed to generate the required parameters itself (using
+     * provider-specific default or random values) if it is being
+     * initialized for encryption or key wrapping, and raise an
+     * <code>InvalidAlgorithmParameterException</code> if it is being
+     * initialized for decryption or key unwrapping.
+     * The generated parameters can be retrieved using
+     * {@link #engineGetParameters() engineGetParameters} or
+     * {@link #engineGetIV() engineGetIV} (if the parameter is an IV).
+     *
+     * <p>If this cipher requires algorithm parameters that cannot be
+     * derived from the input parameters, and there are no reasonable
+     * provider-specific default values, initialization will
+     * necessarily fail.
+     *
+     * <p>If this cipher (including its underlying feedback or padding scheme)
+     * requires any random bytes (e.g., for parameter generation), it will get
+     * them from <code>random</code>.
+     *
+     * <p>Note that when a Cipher object is initialized, it loses all
+     * previously-acquired state. In other words, initializing a Cipher is
+     * equivalent to creating a new instance of that Cipher and initializing
+     * it.
+     *
+     * @param opmode the operation mode of this cipher (this is one of
+     * the following:
+     * <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,
+     * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)
+     * @param key the encryption key
+     * @param params the algorithm parameters
+     * @param random the source of randomness
+     *
+     * @exception InvalidKeyException if the given key is inappropriate for
+     * initializing this cipher
+     * @exception InvalidAlgorithmParameterException if the given algorithm
+     * parameters are inappropriate for this cipher,
+     * or if this cipher requires
+     * algorithm parameters and <code>params</code> is null.
+     * @throws UnsupportedOperationException if {@code opmode} is
+     * {@code WRAP_MODE} or {@code UNWRAP_MODE} is not implemented
+     * by the cipher.
+     */
+    protected abstract void engineInit(int opmode, Key key,
+                                       AlgorithmParameterSpec params,
+                                       SecureRandom random)
+        throws InvalidKeyException, InvalidAlgorithmParameterException;
+
+    /**
+     * Initializes this cipher with a key, a set of
+     * algorithm parameters, and a source of randomness.
+     *
+     * <p>The cipher is initialized for one of the following four operations:
+     * encryption, decryption, key wrapping or key unwrapping, depending on
+     * the value of <code>opmode</code>.
+     *
+     * <p>If this cipher requires any algorithm parameters and
+     * <code>params</code> is null, the underlying cipher implementation is
+     * supposed to generate the required parameters itself (using
+     * provider-specific default or random values) if it is being
+     * initialized for encryption or key wrapping, and raise an
+     * <code>InvalidAlgorithmParameterException</code> if it is being
+     * initialized for decryption or key unwrapping.
+     * The generated parameters can be retrieved using
+     * {@link #engineGetParameters() engineGetParameters} or
+     * {@link #engineGetIV() engineGetIV} (if the parameter is an IV).
+     *
+     * <p>If this cipher requires algorithm parameters that cannot be
+     * derived from the input parameters, and there are no reasonable
+     * provider-specific default values, initialization will
+     * necessarily fail.
+     *
+     * <p>If this cipher (including its underlying feedback or padding scheme)
+     * requires any random bytes (e.g., for parameter generation), it will get
+     * them from <code>random</code>.
+     *
+     * <p>Note that when a Cipher object is initialized, it loses all
+     * previously-acquired state. In other words, initializing a Cipher is
+     * equivalent to creating a new instance of that Cipher and initializing
+     * it.
+     *
+     * @param opmode the operation mode of this cipher (this is one of
+     * the following:
+     * <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,
+     * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)
+     * @param key the encryption key
+     * @param params the algorithm parameters
+     * @param random the source of randomness
+     *
+     * @exception InvalidKeyException if the given key is inappropriate for
+     * initializing this cipher
+     * @exception InvalidAlgorithmParameterException if the given algorithm
+     * parameters are inappropriate for this cipher,
+     * or if this cipher requires
+     * algorithm parameters and <code>params</code> is null.
+     * @throws UnsupportedOperationException if {@code opmode} is
+     * {@code WRAP_MODE} or {@code UNWRAP_MODE} is not implemented
+     * by the cipher.
+     */
+    protected abstract void engineInit(int opmode, Key key,
+                                       AlgorithmParameters params,
+                                       SecureRandom random)
+        throws InvalidKeyException, InvalidAlgorithmParameterException;
+
+    /**
+     * Continues a multiple-part encryption or decryption operation
+     * (depending on how this cipher was initialized), processing another data
+     * part.
+     *
+     * <p>The first <code>inputLen</code> bytes in the <code>input</code>
+     * buffer, starting at <code>inputOffset</code> inclusive, are processed,
+     * and the result is stored in a new buffer.
+     *
+     * @param input the input buffer
+     * @param inputOffset the offset in <code>input</code> where the input
+     * starts
+     * @param inputLen the input length
+     *
+     * @return the new buffer with the result, or null if the underlying
+     * cipher is a block cipher and the input data is too short to result in a
+     * new block.
+     */
+    protected abstract byte[] engineUpdate(byte[] input, int inputOffset,
+                                           int inputLen);
+
+    /**
+     * Continues a multiple-part encryption or decryption operation
+     * (depending on how this cipher was initialized), processing another data
+     * part.
+     *
+     * <p>The first <code>inputLen</code> bytes in the <code>input</code>
+     * buffer, starting at <code>inputOffset</code> inclusive, are processed,
+     * and the result is stored in the <code>output</code> buffer, starting at
+     * <code>outputOffset</code> inclusive.
+     *
+     * <p>If the <code>output</code> buffer is too small to hold the result,
+     * a <code>ShortBufferException</code> is thrown.
+     *
+     * @param input the input buffer
+     * @param inputOffset the offset in <code>input</code> where the input
+     * starts
+     * @param inputLen the input length
+     * @param output the buffer for the result
+     * @param outputOffset the offset in <code>output</code> where the result
+     * is stored
+     *
+     * @return the number of bytes stored in <code>output</code>
+     *
+     * @exception ShortBufferException if the given output buffer is too small
+     * to hold the result
+     */
+    protected abstract int engineUpdate(byte[] input, int inputOffset,
+                                        int inputLen, byte[] output,
+                                        int outputOffset)
+        throws ShortBufferException;
+
+    /**
+     * Continues a multiple-part encryption or decryption operation
+     * (depending on how this cipher was initialized), processing another data
+     * part.
+     *
+     * <p>All <code>input.remaining()</code> bytes starting at
+     * <code>input.position()</code> are processed. The result is stored
+     * in the output buffer.
+     * Upon return, the input buffer's position will be equal
+     * to its limit; its limit will not have changed. The output buffer's
+     * position will have advanced by n, where n is the value returned
+     * by this method; the output buffer's limit will not have changed.
+     *
+     * <p>If <code>output.remaining()</code> bytes are insufficient to
+     * hold the result, a <code>ShortBufferException</code> is thrown.
+     *
+     * <p>Subclasses should consider overriding this method if they can
+     * process ByteBuffers more efficiently than byte arrays.
+     *
+     * @param input the input ByteBuffer
+     * @param output the output ByteByffer
+     *
+     * @return the number of bytes stored in <code>output</code>
+     *
+     * @exception ShortBufferException if there is insufficient space in the
+     * output buffer
+     *
+     * @throws NullPointerException if either parameter is <CODE>null</CODE>
+     * @since 1.5
+     */
+    protected int engineUpdate(ByteBuffer input, ByteBuffer output)
+            throws ShortBufferException {
+        try {
+            return bufferCrypt(input, output, true);
+        } catch (IllegalBlockSizeException e) {
+            // never thrown for engineUpdate()
+            throw new ProviderException("Internal error in update()");
+        } catch (BadPaddingException e) {
+            // never thrown for engineUpdate()
+            throw new ProviderException("Internal error in update()");
+        }
+    }
+
+    /**
+     * Encrypts or decrypts data in a single-part operation,
+     * or finishes a multiple-part operation.
+     * The data is encrypted or decrypted, depending on how this cipher was
+     * initialized.
+     *
+     * <p>The first <code>inputLen</code> bytes in the <code>input</code>
+     * buffer, starting at <code>inputOffset</code> inclusive, and any input
+     * bytes that may have been buffered during a previous <code>update</code>
+     * operation, are processed, with padding (if requested) being applied.
+     * If an AEAD mode such as GCM/CCM is being used, the authentication
+     * tag is appended in the case of encryption, or verified in the
+     * case of decryption.
+     * The result is stored in a new buffer.
+     *
+     * <p>Upon finishing, this method resets this cipher object to the state
+     * it was in when previously initialized via a call to
+     * <code>engineInit</code>.
+     * That is, the object is reset and available to encrypt or decrypt
+     * (depending on the operation mode that was specified in the call to
+     * <code>engineInit</code>) more data.
+     *
+     * <p>Note: if any exception is thrown, this cipher object may need to
+     * be reset before it can be used again.
+     *
+     * @param input the input buffer
+     * @param inputOffset the offset in <code>input</code> where the input
+     * starts
+     * @param inputLen the input length
+     *
+     * @return the new buffer with the result
+     *
+     * @exception IllegalBlockSizeException if this cipher is a block cipher,
+     * no padding has been requested (only in encryption mode), and the total
+     * input length of the data processed by this cipher is not a multiple of
+     * block size; or if this encryption algorithm is unable to
+     * process the input data provided.
+     * @exception BadPaddingException if this cipher is in decryption mode,
+     * and (un)padding has been requested, but the decrypted data is not
+     * bounded by the appropriate padding bytes
+     * @exception AEADBadTagException if this cipher is decrypting in an
+     * AEAD mode (such as GCM/CCM), and the received authentication tag
+     * does not match the calculated value
+     */
+    protected abstract byte[] engineDoFinal(byte[] input, int inputOffset,
+                                            int inputLen)
+        throws IllegalBlockSizeException, BadPaddingException;
+
+    /**
+     * Encrypts or decrypts data in a single-part operation,
+     * or finishes a multiple-part operation.
+     * The data is encrypted or decrypted, depending on how this cipher was
+     * initialized.
+     *
+     * <p>The first <code>inputLen</code> bytes in the <code>input</code>
+     * buffer, starting at <code>inputOffset</code> inclusive, and any input
+     * bytes that may have been buffered during a previous <code>update</code>
+     * operation, are processed, with padding (if requested) being applied.
+     * If an AEAD mode such as GCM/CCM is being used, the authentication
+     * tag is appended in the case of encryption, or verified in the
+     * case of decryption.
+     * The result is stored in the <code>output</code> buffer, starting at
+     * <code>outputOffset</code> inclusive.
+     *
+     * <p>If the <code>output</code> buffer is too small to hold the result,
+     * a <code>ShortBufferException</code> is thrown.
+     *
+     * <p>Upon finishing, this method resets this cipher object to the state
+     * it was in when previously initialized via a call to
+     * <code>engineInit</code>.
+     * That is, the object is reset and available to encrypt or decrypt
+     * (depending on the operation mode that was specified in the call to
+     * <code>engineInit</code>) more data.
+     *
+     * <p>Note: if any exception is thrown, this cipher object may need to
+     * be reset before it can be used again.
+     *
+     * @param input the input buffer
+     * @param inputOffset the offset in <code>input</code> where the input
+     * starts
+     * @param inputLen the input length
+     * @param output the buffer for the result
+     * @param outputOffset the offset in <code>output</code> where the result
+     * is stored
+     *
+     * @return the number of bytes stored in <code>output</code>
+     *
+     * @exception IllegalBlockSizeException if this cipher is a block cipher,
+     * no padding has been requested (only in encryption mode), and the total
+     * input length of the data processed by this cipher is not a multiple of
+     * block size; or if this encryption algorithm is unable to
+     * process the input data provided.
+     * @exception ShortBufferException if the given output buffer is too small
+     * to hold the result
+     * @exception BadPaddingException if this cipher is in decryption mode,
+     * and (un)padding has been requested, but the decrypted data is not
+     * bounded by the appropriate padding bytes
+     * @exception AEADBadTagException if this cipher is decrypting in an
+     * AEAD mode (such as GCM/CCM), and the received authentication tag
+     * does not match the calculated value
+     */
+    protected abstract int engineDoFinal(byte[] input, int inputOffset,
+                                         int inputLen, byte[] output,
+                                         int outputOffset)
+        throws ShortBufferException, IllegalBlockSizeException,
+               BadPaddingException;
+
+    /**
+     * Encrypts or decrypts data in a single-part operation,
+     * or finishes a multiple-part operation.
+     * The data is encrypted or decrypted, depending on how this cipher was
+     * initialized.
+     *
+     * <p>All <code>input.remaining()</code> bytes starting at
+     * <code>input.position()</code> are processed.
+     * If an AEAD mode such as GCM/CCM is being used, the authentication
+     * tag is appended in the case of encryption, or verified in the
+     * case of decryption.
+     * The result is stored in the output buffer.
+     * Upon return, the input buffer's position will be equal
+     * to its limit; its limit will not have changed. The output buffer's
+     * position will have advanced by n, where n is the value returned
+     * by this method; the output buffer's limit will not have changed.
+     *
+     * <p>If <code>output.remaining()</code> bytes are insufficient to
+     * hold the result, a <code>ShortBufferException</code> is thrown.
+     *
+     * <p>Upon finishing, this method resets this cipher object to the state
+     * it was in when previously initialized via a call to
+     * <code>engineInit</code>.
+     * That is, the object is reset and available to encrypt or decrypt
+     * (depending on the operation mode that was specified in the call to
+     * <code>engineInit</code>) more data.
+     *
+     * <p>Note: if any exception is thrown, this cipher object may need to
+     * be reset before it can be used again.
+     *
+     * <p>Subclasses should consider overriding this method if they can
+     * process ByteBuffers more efficiently than byte arrays.
+     *
+     * @param input the input ByteBuffer
+     * @param output the output ByteByffer
+     *
+     * @return the number of bytes stored in <code>output</code>
+     *
+     * @exception IllegalBlockSizeException if this cipher is a block cipher,
+     * no padding has been requested (only in encryption mode), and the total
+     * input length of the data processed by this cipher is not a multiple of
+     * block size; or if this encryption algorithm is unable to
+     * process the input data provided.
+     * @exception ShortBufferException if there is insufficient space in the
+     * output buffer
+     * @exception BadPaddingException if this cipher is in decryption mode,
+     * and (un)padding has been requested, but the decrypted data is not
+     * bounded by the appropriate padding bytes
+     * @exception AEADBadTagException if this cipher is decrypting in an
+     * AEAD mode (such as GCM/CCM), and the received authentication tag
+     * does not match the calculated value
+     *
+     * @throws NullPointerException if either parameter is <CODE>null</CODE>
+     * @since 1.5
+     */
+    protected int engineDoFinal(ByteBuffer input, ByteBuffer output)
+            throws ShortBufferException, IllegalBlockSizeException,
+            BadPaddingException {
+        return bufferCrypt(input, output, false);
+    }
+
+    // copied from sun.security.jca.JCAUtil
+    // will be changed to reference that method once that code has been
+    // integrated and promoted
+    static int getTempArraySize(int totalSize) {
+        return Math.min(4096, totalSize);
+    }
+
+    /**
+     * Implementation for encryption using ByteBuffers. Used for both
+     * engineUpdate() and engineDoFinal().
+     */
+    private int bufferCrypt(ByteBuffer input, ByteBuffer output,
+            boolean isUpdate) throws ShortBufferException,
+            IllegalBlockSizeException, BadPaddingException {
+        if ((input == null) || (output == null)) {
+            throw new NullPointerException
+                ("Input and output buffers must not be null");
+        }
+        int inPos = input.position();
+        int inLimit = input.limit();
+        int inLen = inLimit - inPos;
+        if (isUpdate && (inLen == 0)) {
+            return 0;
+        }
+        int outLenNeeded = engineGetOutputSize(inLen);
+        if (output.remaining() < outLenNeeded) {
+            throw new ShortBufferException("Need at least " + outLenNeeded
+                + " bytes of space in output buffer");
+        }
+
+        boolean a1 = input.hasArray();
+        boolean a2 = output.hasArray();
+
+        if (a1 && a2) {
+            byte[] inArray = input.array();
+            int inOfs = input.arrayOffset() + inPos;
+            byte[] outArray = output.array();
+            int outPos = output.position();
+            int outOfs = output.arrayOffset() + outPos;
+            int n;
+            if (isUpdate) {
+                n = engineUpdate(inArray, inOfs, inLen, outArray, outOfs);
+            } else {
+                n = engineDoFinal(inArray, inOfs, inLen, outArray, outOfs);
+            }
+            input.position(inLimit);
+            output.position(outPos + n);
+            return n;
+        } else if (!a1 && a2) {
+            int outPos = output.position();
+            byte[] outArray = output.array();
+            int outOfs = output.arrayOffset() + outPos;
+            byte[] inArray = new byte[getTempArraySize(inLen)];
+            int total = 0;
+            do {
+                int chunk = Math.min(inLen, inArray.length);
+                if (chunk > 0) {
+                    input.get(inArray, 0, chunk);
+                }
+                int n;
+                if (isUpdate || (inLen != chunk)) {
+                    n = engineUpdate(inArray, 0, chunk, outArray, outOfs);
+                } else {
+                    n = engineDoFinal(inArray, 0, chunk, outArray, outOfs);
+                }
+                total += n;
+                outOfs += n;
+                inLen -= chunk;
+            } while (inLen > 0);
+            output.position(outPos + total);
+            return total;
+        } else { // output is not backed by an accessible byte[]
+            byte[] inArray;
+            int inOfs;
+            if (a1) {
+                inArray = input.array();
+                inOfs = input.arrayOffset() + inPos;
+            } else {
+                inArray = new byte[getTempArraySize(inLen)];
+                inOfs = 0;
+            }
+            byte[] outArray = new byte[getTempArraySize(outLenNeeded)];
+            int outSize = outArray.length;
+            int total = 0;
+            boolean resized = false;
+            do {
+                int chunk =
+                    Math.min(inLen, (outSize == 0? inArray.length : outSize));
+                if (!a1 && !resized && chunk > 0) {
+                    input.get(inArray, 0, chunk);
+                    inOfs = 0;
+                }
+                try {
+                    int n;
+                    if (isUpdate || (inLen != chunk)) {
+                        n = engineUpdate(inArray, inOfs, chunk, outArray, 0);
+                    } else {
+                        n = engineDoFinal(inArray, inOfs, chunk, outArray, 0);
+                    }
+                    resized = false;
+                    inOfs += chunk;
+                    inLen -= chunk;
+                    if (n > 0) {
+                        output.put(outArray, 0, n);
+                        total += n;
+                    }
+                } catch (ShortBufferException e) {
+                    if (resized) {
+                        // we just resized the output buffer, but it still
+                        // did not work. Bug in the provider, abort
+                        throw (ProviderException)new ProviderException
+                            ("Could not determine buffer size").initCause(e);
+                    }
+                    // output buffer is too small, realloc and try again
+                    resized = true;
+                    outSize = engineGetOutputSize(chunk);
+                    outArray = new byte[outSize];
+                }
+            } while (inLen > 0);
+            if (a1) {
+                input.position(inLimit);
+            }
+            return total;
+        }
+    }
+
+    /**
+     * Wrap a key.
+     *
+     * <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 wrap a key.
+     * Such an override is expected to throw an IllegalBlockSizeException or
+     * InvalidKeyException (under the specified circumstances),
+     * if the given key cannot be wrapped.
+     * If this method is not overridden, it always throws an
+     * UnsupportedOperationException.
+     *
+     * @param key the key to be wrapped.
+     *
+     * @return the wrapped key.
+     *
+     * @exception IllegalBlockSizeException if this cipher is a block cipher,
+     * no padding has been requested, and the length of the encoding of the
+     * key to be wrapped is not a multiple of the block size.
+     *
+     * @exception InvalidKeyException if it is impossible or unsafe to
+     * wrap the key with this cipher (e.g., a hardware protected key is
+     * being passed to a software-only cipher).
+     *
+     * @throws UnsupportedOperationException if this method is not supported.
+     */
+    protected byte[] engineWrap(Key key)
+        throws IllegalBlockSizeException, InvalidKeyException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Unwrap a previously wrapped key.
+     *
+     * <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 unwrap a previously wrapped key.
+     * Such an override is expected to throw an InvalidKeyException if
+     * the given wrapped key cannot be unwrapped.
+     * If this method is not overridden, it always throws an
+     * UnsupportedOperationException.
+     *
+     * @param wrappedKey the key to be unwrapped.
+     *
+     * @param wrappedKeyAlgorithm the algorithm associated with the wrapped
+     * key.
+     *
+     * @param wrappedKeyType the type of the wrapped key. This is one of
+     * <code>SECRET_KEY</code>, <code>PRIVATE_KEY</code>, or
+     * <code>PUBLIC_KEY</code>.
+     *
+     * @return the unwrapped key.
+     *
+     * @exception NoSuchAlgorithmException if no installed providers
+     * can create keys of type <code>wrappedKeyType</code> for the
+     * <code>wrappedKeyAlgorithm</code>.
+     *
+     * @exception InvalidKeyException if <code>wrappedKey</code> does not
+     * represent a wrapped key of type <code>wrappedKeyType</code> for
+     * the <code>wrappedKeyAlgorithm</code>.
+     *
+     * @throws UnsupportedOperationException if this method is not supported.
+     */
+    protected Key engineUnwrap(byte[] wrappedKey,
+                               String wrappedKeyAlgorithm,
+                               int wrappedKeyType)
+        throws InvalidKeyException, NoSuchAlgorithmException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Returns the key size of the given key object in bits.
+     * <p>This concrete method has been added to this previously-defined
+     * abstract class. It throws an <code>UnsupportedOperationException</code>
+     * if it is not overridden by the provider.
+     *
+     * @param key the key object.
+     *
+     * @return the key size of the given key object.
+     *
+     * @exception InvalidKeyException if <code>key</code> is invalid.
+     */
+    protected int engineGetKeySize(Key key)
+        throws InvalidKeyException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Continues a multi-part update of the Additional Authentication
+     * Data (AAD), using a subset of the provided buffer.
+     * <p>
+     * Calls to this method provide AAD to the cipher when operating in
+     * modes such as AEAD (GCM/CCM).  If this cipher is operating in
+     * either GCM or CCM mode, all AAD must be supplied before beginning
+     * operations on the ciphertext (via the {@code update} and {@code
+     * doFinal} methods).
+     *
+     * @param src the buffer containing the AAD
+     * @param offset the offset in {@code src} where the AAD input starts
+     * @param len the number of AAD bytes
+     *
+     * @throws IllegalStateException if this cipher is in a wrong state
+     * (e.g., has not been initialized), does not accept AAD, or if
+     * operating in either GCM or CCM mode and one of the {@code update}
+     * methods has already been called for the active
+     * encryption/decryption operation
+     * @throws UnsupportedOperationException if this method
+     * has not been overridden by an implementation
+     *
+     * @since 1.7
+     */
+    protected void engineUpdateAAD(byte[] src, int offset, int len) {
+        throw new UnsupportedOperationException(
+            "The underlying Cipher implementation "
+            +  "does not support this method");
+    }
+
+    /**
+     * Continues a multi-part update of the Additional Authentication
+     * Data (AAD).
+     * <p>
+     * Calls to this method provide AAD to the cipher when operating in
+     * modes such as AEAD (GCM/CCM).  If this cipher is operating in
+     * either GCM or CCM mode, all AAD must be supplied before beginning
+     * operations on the ciphertext (via the {@code update} and {@code
+     * doFinal} methods).
+     * <p>
+     * All {@code src.remaining()} bytes starting at
+     * {@code src.position()} are processed.
+     * Upon return, the input buffer's position will be equal
+     * to its limit; its limit will not have changed.
+     *
+     * @param src the buffer containing the AAD
+     *
+     * @throws IllegalStateException if this cipher is in a wrong state
+     * (e.g., has not been initialized), does not accept AAD, or if
+     * operating in either GCM or CCM mode and one of the {@code update}
+     * methods has already been called for the active
+     * encryption/decryption operation
+     * @throws UnsupportedOperationException if this method
+     * has not been overridden by an implementation
+     *
+     * @since 1.7
+     */
+    protected void engineUpdateAAD(ByteBuffer src) {
+        throw new UnsupportedOperationException(
+            "The underlying Cipher implementation "
+            +  "does not support this method");
+    }
+}
diff --git a/javax/crypto/CryptoAllPermission.java b/javax/crypto/CryptoAllPermission.java
new file mode 100644
index 0000000..8a973fc
--- /dev/null
+++ b/javax/crypto/CryptoAllPermission.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 1999, 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 javax.crypto;
+
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
+/**
+ * Legacy security code; do not use.
+ */
+
+final class CryptoAllPermission extends CryptoPermission {
+
+    static final String ALG_NAME = null;
+    static final CryptoAllPermission INSTANCE = null;
+
+    private CryptoAllPermission() { super(""); }
+}
diff --git a/javax/crypto/CryptoPermission.java b/javax/crypto/CryptoPermission.java
new file mode 100644
index 0000000..56973b6
--- /dev/null
+++ b/javax/crypto/CryptoPermission.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 1999, 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 javax.crypto;
+
+import java.security.*;
+import java.security.spec.AlgorithmParameterSpec;
+
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
+/**
+ * Legacy security code; do not use.
+ */
+class CryptoPermission extends java.security.Permission {
+
+    static final String ALG_NAME_WILDCARD = null;
+
+    CryptoPermission(String alg) { super(""); }
+
+    CryptoPermission(String alg, int maxKeySize) { super(""); }
+
+    CryptoPermission(String alg,
+                     int maxKeySize,
+                     AlgorithmParameterSpec algParamSpec) { super(""); }
+
+    CryptoPermission(String alg,
+                     String exemptionMechanism) { super(""); }
+
+    CryptoPermission(String alg,
+                     int maxKeySize,
+                     String exemptionMechanism) { super(""); }
+
+    CryptoPermission(String alg,
+                     int maxKeySize,
+                     AlgorithmParameterSpec algParamSpec,
+                     String exemptionMechanism) { super(""); }
+
+    public boolean implies(Permission p) { return true; }
+
+    public String getActions()
+    {
+        return null;
+    }
+
+    final String getAlgorithm() {
+        return null;
+    }
+
+    final String getExemptionMechanism() {
+        return null;
+    }
+
+
+    final int getMaxKeySize() {
+        return Integer.MAX_VALUE;
+    }
+
+    final boolean getCheckParam() {
+        return false;
+    }
+
+    final AlgorithmParameterSpec getAlgorithmParameterSpec() {
+        return null;
+    }
+}
diff --git a/javax/crypto/CryptoPermissions.java b/javax/crypto/CryptoPermissions.java
new file mode 100644
index 0000000..eef08b7
--- /dev/null
+++ b/javax/crypto/CryptoPermissions.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 1999, 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 javax.crypto;
+
+import java.security.*;
+import java.util.Enumeration;
+import java.io.Serializable;
+import java.io.InputStream;
+import java.io.IOException;
+
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
+/**
+ * Legacy security code; do not use.
+ */
+final class CryptoPermissions extends PermissionCollection
+implements Serializable {
+
+    CryptoPermissions() { }
+
+    void load(InputStream in)
+        throws IOException, CryptoPolicyParser.ParsingException { }
+
+    boolean isEmpty() {
+        return true;
+    }
+
+    public void add(Permission permission) { }
+
+    public boolean implies(Permission permission) { return true; }
+
+    public Enumeration elements() { return null; }
+
+    CryptoPermissions getMinimum(CryptoPermissions other) { return null; }
+
+    PermissionCollection getPermissionCollection(String alg) { return null; }
+}
diff --git a/javax/crypto/CryptoPolicyParser.java b/javax/crypto/CryptoPolicyParser.java
new file mode 100644
index 0000000..10bdc55
--- /dev/null
+++ b/javax/crypto/CryptoPolicyParser.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1999, 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 javax.crypto;
+
+import java.io.*;
+
+import java.security.GeneralSecurityException;
+
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
+/**
+ * Legacy security code; do not use.
+ */
+
+final class CryptoPolicyParser {
+
+    CryptoPolicyParser() { }
+
+    void read(Reader policy)
+        throws ParsingException, IOException { }
+
+    CryptoPermission[] getPermissions() { return null; }
+
+    static final class ParsingException extends GeneralSecurityException {
+
+        ParsingException(String msg) {
+            super("");
+        }
+
+        ParsingException(int line, String msg) {
+            super("");
+        }
+
+        ParsingException(int line, String expect, String actual) {
+            super("");
+        }
+    }
+}
diff --git a/javax/crypto/EncryptedPrivateKeyInfo.java b/javax/crypto/EncryptedPrivateKeyInfo.java
new file mode 100644
index 0000000..5eeb481
--- /dev/null
+++ b/javax/crypto/EncryptedPrivateKeyInfo.java
@@ -0,0 +1,430 @@
+/*
+ * Copyright (c) 2001, 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 javax.crypto;
+
+import java.io.*;
+import java.security.*;
+import java.security.spec.*;
+import sun.security.x509.AlgorithmId;
+import sun.security.util.DerValue;
+import sun.security.util.DerInputStream;
+import sun.security.util.DerOutputStream;
+
+/**
+ * This class implements the <code>EncryptedPrivateKeyInfo</code> type
+ * as defined in PKCS #8.
+ * <p>Its ASN.1 definition is as follows:
+ *
+ * <pre>
+ * EncryptedPrivateKeyInfo ::=  SEQUENCE {
+ *     encryptionAlgorithm   AlgorithmIdentifier,
+ *     encryptedData   OCTET STRING }
+ *
+ * AlgorithmIdentifier  ::=  SEQUENCE  {
+ *     algorithm              OBJECT IDENTIFIER,
+ *     parameters             ANY DEFINED BY algorithm OPTIONAL  }
+ * </pre>
+ *
+ * @author Valerie Peng
+ *
+ * @see java.security.spec.PKCS8EncodedKeySpec
+ *
+ * @since 1.4
+ */
+
+public class EncryptedPrivateKeyInfo {
+
+    // the "encryptionAlgorithm" field
+    private AlgorithmId algid;
+
+    // the "encryptedData" field
+    private byte[] encryptedData;
+
+    // the ASN.1 encoded contents of this class
+    private byte[] encoded = null;
+
+    /**
+     * Constructs (i.e., parses) an <code>EncryptedPrivateKeyInfo</code> from
+     * its ASN.1 encoding.
+     * @param encoded the ASN.1 encoding of this object. The contents of
+     * the array are copied to protect against subsequent modification.
+     * @exception NullPointerException if the <code>encoded</code> is null.
+     * @exception IOException if error occurs when parsing the ASN.1 encoding.
+     */
+    public EncryptedPrivateKeyInfo(byte[] encoded)
+        throws IOException {
+        if (encoded == null) {
+            throw new NullPointerException("the encoded parameter " +
+                                           "must be non-null");
+        }
+        this.encoded = encoded.clone();
+        DerValue val = new DerValue(this.encoded);
+
+        DerValue[] seq = new DerValue[2];
+
+        seq[0] = val.data.getDerValue();
+        seq[1] = val.data.getDerValue();
+
+        if (val.data.available() != 0) {
+            throw new IOException("overrun, bytes = " + val.data.available());
+        }
+
+        this.algid = AlgorithmId.parse(seq[0]);
+        if (seq[0].data.available() != 0) {
+            throw new IOException("encryptionAlgorithm field overrun");
+        }
+
+        this.encryptedData = seq[1].getOctetString();
+        if (seq[1].data.available() != 0) {
+            throw new IOException("encryptedData field overrun");
+        }
+    }
+
+    /**
+     * Constructs an <code>EncryptedPrivateKeyInfo</code> from the
+     * encryption algorithm name and the encrypted data.
+     *
+     * <p>Note: This constructor will use null as the value of the
+     * algorithm parameters. If the encryption algorithm has
+     * parameters whose value is not null, a different constructor,
+     * e.g. EncryptedPrivateKeyInfo(AlgorithmParameters, byte[]),
+     * should be used.
+     *
+     * @param algName encryption algorithm name. See Appendix A in the
+     * <a href=
+     *   "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
+     * Java Cryptography Architecture Reference Guide</a>
+     * for information about standard Cipher algorithm names.
+     * @param encryptedData encrypted data. The contents of
+     * <code>encrypedData</code> are copied to protect against subsequent
+     * modification when constructing this object.
+     * @exception NullPointerException if <code>algName</code> or
+     * <code>encryptedData</code> is null.
+     * @exception IllegalArgumentException if <code>encryptedData</code>
+     * is empty, i.e. 0-length.
+     * @exception NoSuchAlgorithmException if the specified algName is
+     * not supported.
+     */
+    public EncryptedPrivateKeyInfo(String algName, byte[] encryptedData)
+        throws NoSuchAlgorithmException {
+
+        if (algName == null)
+                throw new NullPointerException("the algName parameter " +
+                                               "must be non-null");
+        this.algid = AlgorithmId.get(algName);
+
+        if (encryptedData == null) {
+            throw new NullPointerException("the encryptedData " +
+                                           "parameter must be non-null");
+        } else if (encryptedData.length == 0) {
+            throw new IllegalArgumentException("the encryptedData " +
+                                                "parameter must not be empty");
+        } else {
+            this.encryptedData = encryptedData.clone();
+        }
+        // delay the generation of ASN.1 encoding until
+        // getEncoded() is called
+        this.encoded = null;
+    }
+
+    /**
+     * Constructs an <code>EncryptedPrivateKeyInfo</code> from the
+     * encryption algorithm parameters and the encrypted data.
+     *
+     * @param algParams the algorithm parameters for the encryption
+     * algorithm. <code>algParams.getEncoded()</code> should return
+     * the ASN.1 encoded bytes of the <code>parameters</code> field
+     * of the <code>AlgorithmIdentifer</code> component of the
+     * <code>EncryptedPrivateKeyInfo</code> type.
+     * @param encryptedData encrypted data. The contents of
+     * <code>encrypedData</code> are copied to protect against
+     * subsequent modification when constructing this object.
+     * @exception NullPointerException if <code>algParams</code> or
+     * <code>encryptedData</code> is null.
+     * @exception IllegalArgumentException if <code>encryptedData</code>
+     * is empty, i.e. 0-length.
+     * @exception NoSuchAlgorithmException if the specified algName of
+     * the specified <code>algParams</code> parameter is not supported.
+     */
+    public EncryptedPrivateKeyInfo(AlgorithmParameters algParams,
+        byte[] encryptedData) throws NoSuchAlgorithmException {
+
+        if (algParams == null) {
+            throw new NullPointerException("algParams must be non-null");
+        }
+        this.algid = AlgorithmId.get(algParams);
+
+        if (encryptedData == null) {
+            throw new NullPointerException("encryptedData must be non-null");
+        } else if (encryptedData.length == 0) {
+            throw new IllegalArgumentException("the encryptedData " +
+                                                "parameter must not be empty");
+        } else {
+            this.encryptedData = encryptedData.clone();
+        }
+
+        // delay the generation of ASN.1 encoding until
+        // getEncoded() is called
+        this.encoded = null;
+    }
+
+
+    /**
+     * Returns the encryption algorithm.
+     * <p>Note: Standard name is returned instead of the specified one
+     * in the constructor when such mapping is available.
+     * See Appendix A in the
+     * <a href=
+     *   "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
+     * Java Cryptography Architecture Reference Guide</a>
+     * for information about standard Cipher algorithm names.
+     *
+     * @return the encryption algorithm name.
+     */
+    public String getAlgName() {
+        return this.algid.getName();
+    }
+
+    /**
+     * Returns the algorithm parameters used by the encryption algorithm.
+     * @return the algorithm parameters.
+     */
+    public AlgorithmParameters getAlgParameters() {
+        return this.algid.getParameters();
+    }
+
+    /**
+     * Returns the encrypted data.
+     * @return the encrypted data. Returns a new array
+     * each time this method is called.
+     */
+    public byte[] getEncryptedData() {
+        return this.encryptedData.clone();
+    }
+
+    /**
+     * Extract the enclosed PKCS8EncodedKeySpec object from the
+     * encrypted data and return it.
+     * <br>Note: In order to successfully retrieve the enclosed
+     * PKCS8EncodedKeySpec object, <code>cipher</code> needs
+     * to be initialized to either Cipher.DECRYPT_MODE or
+     * Cipher.UNWRAP_MODE, with the same key and parameters used
+     * for generating the encrypted data.
+     *
+     * @param cipher the initialized cipher object which will be
+     * used for decrypting the encrypted data.
+     * @return the PKCS8EncodedKeySpec object.
+     * @exception NullPointerException if <code>cipher</code>
+     * is null.
+     * @exception InvalidKeySpecException if the given cipher is
+     * inappropriate for the encrypted data or the encrypted
+     * data is corrupted and cannot be decrypted.
+     */
+    public PKCS8EncodedKeySpec getKeySpec(Cipher cipher)
+        throws InvalidKeySpecException {
+        byte[] encoded = null;
+        try {
+            encoded = cipher.doFinal(encryptedData);
+            checkPKCS8Encoding(encoded);
+        } catch (GeneralSecurityException |
+                 IOException |
+                 IllegalStateException ex) {
+            throw new InvalidKeySpecException(
+                    "Cannot retrieve the PKCS8EncodedKeySpec", ex);
+        }
+        return new PKCS8EncodedKeySpec(encoded);
+    }
+
+    private PKCS8EncodedKeySpec getKeySpecImpl(Key decryptKey,
+        Provider provider) throws NoSuchAlgorithmException,
+        InvalidKeyException {
+        byte[] encoded = null;
+        Cipher c;
+        try {
+            if (provider == null) {
+                // use the most preferred one
+                c = Cipher.getInstance(algid.getName());
+            } else {
+                c = Cipher.getInstance(algid.getName(), provider);
+            }
+            c.init(Cipher.DECRYPT_MODE, decryptKey, algid.getParameters());
+            encoded = c.doFinal(encryptedData);
+            checkPKCS8Encoding(encoded);
+        } catch (NoSuchAlgorithmException nsae) {
+            // rethrow
+            throw nsae;
+        } catch (GeneralSecurityException | IOException ex) {
+            throw new InvalidKeyException(
+                    "Cannot retrieve the PKCS8EncodedKeySpec", ex);
+        }
+        return new PKCS8EncodedKeySpec(encoded);
+    }
+
+    /**
+     * Extract the enclosed PKCS8EncodedKeySpec object from the
+     * encrypted data and return it.
+     * @param decryptKey key used for decrypting the encrypted data.
+     * @return the PKCS8EncodedKeySpec object.
+     * @exception NullPointerException if <code>decryptKey</code>
+     * is null.
+     * @exception NoSuchAlgorithmException if cannot find appropriate
+     * cipher to decrypt the encrypted data.
+     * @exception InvalidKeyException if <code>decryptKey</code>
+     * cannot be used to decrypt the encrypted data or the decryption
+     * result is not a valid PKCS8KeySpec.
+     *
+     * @since 1.5
+     */
+    public PKCS8EncodedKeySpec getKeySpec(Key decryptKey)
+        throws NoSuchAlgorithmException, InvalidKeyException {
+        if (decryptKey == null) {
+            throw new NullPointerException("decryptKey is null");
+        }
+        return getKeySpecImpl(decryptKey, null);
+    }
+
+    /**
+     * Extract the enclosed PKCS8EncodedKeySpec object from the
+     * encrypted data and return it.
+     * @param decryptKey key used for decrypting the encrypted data.
+     * @param providerName the name of provider whose Cipher
+     * implementation will be used.
+     * @return the PKCS8EncodedKeySpec object.
+     * @exception NullPointerException if <code>decryptKey</code>
+     * or <code>providerName</code> is null.
+     * @exception NoSuchProviderException if no provider
+     * <code>providerName</code> is registered.
+     * @exception NoSuchAlgorithmException if cannot find appropriate
+     * cipher to decrypt the encrypted data.
+     * @exception InvalidKeyException if <code>decryptKey</code>
+     * cannot be used to decrypt the encrypted data or the decryption
+     * result is not a valid PKCS8KeySpec.
+     *
+     * @since 1.5
+     */
+    public PKCS8EncodedKeySpec getKeySpec(Key decryptKey,
+        String providerName) throws NoSuchProviderException,
+        NoSuchAlgorithmException, InvalidKeyException {
+        if (decryptKey == null) {
+            throw new NullPointerException("decryptKey is null");
+        }
+        if (providerName == null) {
+            throw new NullPointerException("provider is null");
+        }
+        Provider provider = Security.getProvider(providerName);
+        if (provider == null) {
+            throw new NoSuchProviderException("provider " +
+                providerName + " not found");
+        }
+        return getKeySpecImpl(decryptKey, provider);
+    }
+
+    /**
+     * Extract the enclosed PKCS8EncodedKeySpec object from the
+     * encrypted data and return it.
+     * @param decryptKey key used for decrypting the encrypted data.
+     * @param provider the name of provider whose Cipher implementation
+     * will be used.
+     * @return the PKCS8EncodedKeySpec object.
+     * @exception NullPointerException if <code>decryptKey</code>
+     * or <code>provider</code> is null.
+     * @exception NoSuchAlgorithmException if cannot find appropriate
+     * cipher to decrypt the encrypted data in <code>provider</code>.
+     * @exception InvalidKeyException if <code>decryptKey</code>
+     * cannot be used to decrypt the encrypted data or the decryption
+     * result is not a valid PKCS8KeySpec.
+     *
+     * @since 1.5
+     */
+    public PKCS8EncodedKeySpec getKeySpec(Key decryptKey,
+        Provider provider) throws NoSuchAlgorithmException,
+        InvalidKeyException {
+        if (decryptKey == null) {
+            throw new NullPointerException("decryptKey is null");
+        }
+        if (provider == null) {
+            throw new NullPointerException("provider is null");
+        }
+        return getKeySpecImpl(decryptKey, provider);
+    }
+
+    /**
+     * Returns the ASN.1 encoding of this object.
+     * @return the ASN.1 encoding. Returns a new array
+     * each time this method is called.
+     * @exception IOException if error occurs when constructing its
+     * ASN.1 encoding.
+     */
+    public byte[] getEncoded() throws IOException {
+        if (this.encoded == null) {
+            DerOutputStream out = new DerOutputStream();
+            DerOutputStream tmp = new DerOutputStream();
+
+            // encode encryption algorithm
+            algid.encode(tmp);
+
+            // encode encrypted data
+            tmp.putOctetString(encryptedData);
+
+            // wrap everything into a SEQUENCE
+            out.write(DerValue.tag_Sequence, tmp);
+            this.encoded = out.toByteArray();
+        }
+        return this.encoded.clone();
+    }
+
+    private static void checkTag(DerValue val, byte tag, String valName)
+        throws IOException {
+        if (val.getTag() != tag) {
+            throw new IOException("invalid key encoding - wrong tag for " +
+                                  valName);
+        }
+    }
+
+    @SuppressWarnings("fallthrough")
+    private static void checkPKCS8Encoding(byte[] encodedKey)
+        throws IOException {
+        DerInputStream in = new DerInputStream(encodedKey);
+        DerValue[] values = in.getSequence(3);
+
+        switch (values.length) {
+        case 4:
+            checkTag(values[3], DerValue.TAG_CONTEXT, "attributes");
+            /* fall through */
+        case 3:
+            checkTag(values[0], DerValue.tag_Integer, "version");
+            DerInputStream algid = values[1].toDerInputStream();
+            algid.getOID();
+            if (algid.available() != 0) {
+                algid.getDerValue();
+            }
+            checkTag(values[2], DerValue.tag_OctetString, "privateKey");
+            break;
+        default:
+            throw new IOException("invalid key encoding");
+        }
+    }
+}
diff --git a/javax/crypto/ExemptionMechanism.java b/javax/crypto/ExemptionMechanism.java
new file mode 100644
index 0000000..b90ab43
--- /dev/null
+++ b/javax/crypto/ExemptionMechanism.java
@@ -0,0 +1,486 @@
+/*
+ * 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 javax.crypto;
+
+import java.security.AlgorithmParameters;
+import java.security.Provider;
+import java.security.Key;
+import java.security.Security;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.InvalidKeyException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.spec.AlgorithmParameterSpec;
+
+import sun.security.jca.GetInstance.Instance;
+
+/**
+ * This class provides the functionality of an exemption mechanism, examples
+ * of which are <i>key recovery</i>, <i>key weakening</i>, and
+ * <i>key escrow</i>.
+ *
+ * <p>Applications or applets that use an exemption mechanism may be granted
+ * stronger encryption capabilities than those which don't.
+ *
+ * @since 1.4
+ */
+
+public class ExemptionMechanism {
+
+    // The provider
+    private Provider provider;
+
+    // The provider implementation (delegate)
+    private ExemptionMechanismSpi exmechSpi;
+
+    // The name of the exemption mechanism.
+    private String mechanism;
+
+    // Flag which indicates whether this ExemptionMechanism
+    // result is generated successfully.
+    private boolean done = false;
+
+    // State information
+    private boolean initialized = false;
+
+    // Store away the key at init() time for later comparison.
+    private Key keyStored = null;
+
+    /**
+     * Creates a ExemptionMechanism object.
+     *
+     * @param exmechSpi the delegate
+     * @param provider the provider
+     * @param mechanism the exemption mechanism
+     */
+    protected ExemptionMechanism(ExemptionMechanismSpi exmechSpi,
+                                 Provider provider,
+                                 String mechanism) {
+        this.exmechSpi = exmechSpi;
+        this.provider = provider;
+        this.mechanism = mechanism;
+    }
+
+    /**
+     * Returns the exemption mechanism name of this
+     * <code>ExemptionMechanism</code> object.
+     *
+     * <p>This is the same name that was specified in one of the
+     * <code>getInstance</code> calls that created this
+     * <code>ExemptionMechanism</code> object.
+     *
+     * @return the exemption mechanism name of this
+     * <code>ExemptionMechanism</code> object.
+     */
+    public final String getName() {
+        return this.mechanism;
+    }
+
+    /**
+     * Returns an <code>ExemptionMechanism</code> object that implements the
+     * specified exemption mechanism algorithm.
+     *
+     * <p> This method traverses the list of registered security Providers,
+     * starting with the most preferred Provider.
+     * A new ExemptionMechanism object encapsulating the
+     * ExemptionMechanismSpi 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 requested exemption
+     * mechanism.
+     * See the ExemptionMechanism section in the
+     * <a href=
+     *   "{@docRoot}/../technotes/guides/security/StandardNames.html#Exemption">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard exemption mechanism names.
+     *
+     * @return the new <code>ExemptionMechanism</code> object.
+     *
+     * @exception NullPointerException if <code>algorithm</code>
+     *          is null.
+     *
+     * @exception NoSuchAlgorithmException if no Provider supports an
+     *          ExemptionMechanismSpi implementation for the
+     *          specified algorithm.
+     *
+     * @see java.security.Provider
+     */
+    public static final ExemptionMechanism getInstance(String algorithm)
+            throws NoSuchAlgorithmException {
+        Instance instance = JceSecurity.getInstance("ExemptionMechanism",
+                ExemptionMechanismSpi.class, algorithm);
+        return new ExemptionMechanism((ExemptionMechanismSpi)instance.impl,
+                instance.provider, algorithm);
+    }
+
+
+    /**
+     * Returns an <code>ExemptionMechanism</code> object that implements the
+     * specified exemption mechanism algorithm.
+     *
+     * <p> A new ExemptionMechanism object encapsulating the
+     * ExemptionMechanismSpi 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 name of the requested exemption mechanism.
+     * See the ExemptionMechanism section in the
+     * <a href=
+     *   "{@docRoot}/../technotes/guides/security/StandardNames.html#Exemption">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard exemption mechanism names.
+     *
+     * @param provider the name of the provider.
+     *
+     * @return the new <code>ExemptionMechanism</code> object.
+     *
+     * @exception NullPointerException if <code>algorithm</code>
+     *          is null.
+     *
+     * @exception NoSuchAlgorithmException if an ExemptionMechanismSpi
+     *          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</code>
+     *          is null or empty.
+     *
+     * @see java.security.Provider
+     */
+    public static final ExemptionMechanism getInstance(String algorithm,
+            String provider) throws NoSuchAlgorithmException,
+            NoSuchProviderException {
+        Instance instance = JceSecurity.getInstance("ExemptionMechanism",
+                ExemptionMechanismSpi.class, algorithm, provider);
+        return new ExemptionMechanism((ExemptionMechanismSpi)instance.impl,
+                instance.provider, algorithm);
+    }
+
+    /**
+     * Returns an <code>ExemptionMechanism</code> object that implements the
+     * specified exemption mechanism algorithm.
+     *
+     * <p> A new ExemptionMechanism object encapsulating the
+     * ExemptionMechanismSpi 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 name of the requested exemption mechanism.
+     * See the ExemptionMechanism section in the
+     * <a href=
+     *   "{@docRoot}/../technotes/guides/security/StandardNames.html#Exemption">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard exemption mechanism names.
+     *
+     * @param provider the provider.
+     *
+     * @return the new <code>ExemptionMechanism</code> object.
+     *
+     * @exception NullPointerException if <code>algorithm</code>
+     *          is null.
+     *
+     * @exception NoSuchAlgorithmException if an ExemptionMechanismSpi
+     *          implementation for the specified algorithm is not available
+     *          from the specified Provider object.
+     *
+     * @exception IllegalArgumentException if the <code>provider</code>
+     *          is null.
+     *
+     * @see java.security.Provider
+     */
+    public static final ExemptionMechanism getInstance(String algorithm,
+            Provider provider) throws NoSuchAlgorithmException {
+        Instance instance = JceSecurity.getInstance("ExemptionMechanism",
+                ExemptionMechanismSpi.class, algorithm, provider);
+        return new ExemptionMechanism((ExemptionMechanismSpi)instance.impl,
+                instance.provider, algorithm);
+    }
+
+    /**
+     * Returns the provider of this <code>ExemptionMechanism</code> object.
+     *
+     * @return the provider of this <code>ExemptionMechanism</code> object.
+     */
+    public final Provider getProvider() {
+        return this.provider;
+    }
+
+    /**
+     * Returns whether the result blob has been generated successfully by this
+     * exemption mechanism.
+     *
+     * <p>The method also makes sure that the key passed in is the same as
+     * the one this exemption mechanism used in initializing and generating
+     * phases.
+     *
+     * @param key the key the crypto is going to use.
+     *
+     * @return whether the result blob of the same key has been generated
+     * successfully by this exemption mechanism; false if <code>key</code>
+     * is null.
+     *
+     * @exception ExemptionMechanismException if problem(s) encountered
+     * while determining whether the result blob has been generated successfully
+     * by this exemption mechanism object.
+     */
+    public final boolean isCryptoAllowed(Key key)
+            throws ExemptionMechanismException {
+        boolean ret = false;
+        if (done && (key != null)) {
+            // Check if the key passed in is the same as the one
+            // this exemption mechanism used.
+            ret = keyStored.equals(key);
+        }
+        return ret;
+     }
+
+    /**
+     * Returns the length in bytes that an output buffer would need to be in
+     * order to hold the result of the next
+     * {@link #genExemptionBlob(byte[]) genExemptionBlob}
+     * operation, given the input length <code>inputLen</code> (in bytes).
+     *
+     * <p>The actual output length of the next
+     * {@link #genExemptionBlob(byte[]) genExemptionBlob}
+     * call may be smaller than the length returned by this method.
+     *
+     * @param inputLen the input length (in bytes)
+     *
+     * @return the required output buffer size (in bytes)
+     *
+     * @exception IllegalStateException if this exemption mechanism is in a
+     * wrong state (e.g., has not yet been initialized)
+     */
+    public final int getOutputSize(int inputLen) throws IllegalStateException {
+        if (!initialized) {
+            throw new IllegalStateException(
+                "ExemptionMechanism not initialized");
+        }
+        if (inputLen < 0) {
+            throw new IllegalArgumentException(
+                "Input size must be equal to " + "or greater than zero");
+        }
+        return exmechSpi.engineGetOutputSize(inputLen);
+    }
+
+    /**
+     * Initializes this exemption mechanism with a key.
+     *
+     * <p>If this exemption mechanism requires any algorithm parameters
+     * that cannot be derived from the given <code>key</code>, the
+     * underlying exemption mechanism implementation is supposed to
+     * generate the required parameters itself (using provider-specific
+     * default values); in the case that algorithm parameters must be
+     * specified by the caller, an <code>InvalidKeyException</code> is raised.
+     *
+     * @param key the key for this exemption mechanism
+     *
+     * @exception InvalidKeyException if the given key is inappropriate for
+     * this exemption mechanism.
+     * @exception ExemptionMechanismException if problem(s) encountered in the
+     * process of initializing.
+     */
+    public final void init(Key key)
+            throws InvalidKeyException, ExemptionMechanismException {
+        done = false;
+        initialized = false;
+
+        keyStored = key;
+        exmechSpi.engineInit(key);
+        initialized = true;
+    }
+
+    /**
+     * Initializes this exemption mechanism with a key and a set of algorithm
+     * parameters.
+     *
+     * <p>If this exemption mechanism requires any algorithm parameters
+     * and <code>params</code> is null, the underlying exemption
+     * mechanism implementation is supposed to generate the required
+     * parameters itself (using provider-specific default values); in the case
+     * that algorithm parameters must be specified by the caller, an
+     * <code>InvalidAlgorithmParameterException</code> is raised.
+     *
+     * @param key the key for this exemption mechanism
+     * @param params the algorithm parameters
+     *
+     * @exception InvalidKeyException if the given key is inappropriate for
+     * this exemption mechanism.
+     * @exception InvalidAlgorithmParameterException if the given algorithm
+     * parameters are inappropriate for this exemption mechanism.
+     * @exception ExemptionMechanismException if problem(s) encountered in the
+     * process of initializing.
+     */
+    public final void init(Key key, AlgorithmParameterSpec params)
+            throws InvalidKeyException, InvalidAlgorithmParameterException,
+            ExemptionMechanismException {
+        done = false;
+        initialized = false;
+
+        keyStored = key;
+        exmechSpi.engineInit(key, params);
+        initialized = true;
+    }
+
+    /**
+     * Initializes this exemption mechanism with a key and a set of algorithm
+     * parameters.
+     *
+     * <p>If this exemption mechanism requires any algorithm parameters
+     * and <code>params</code> is null, the underlying exemption mechanism
+     * implementation is supposed to generate the required parameters itself
+     * (using provider-specific default values); in the case that algorithm
+     * parameters must be specified by the caller, an
+     * <code>InvalidAlgorithmParameterException</code> is raised.
+     *
+     * @param key the key for this exemption mechanism
+     * @param params the algorithm parameters
+     *
+     * @exception InvalidKeyException if the given key is inappropriate for
+     * this exemption mechanism.
+     * @exception InvalidAlgorithmParameterException if the given algorithm
+     * parameters are inappropriate for this exemption mechanism.
+     * @exception ExemptionMechanismException if problem(s) encountered in the
+     * process of initializing.
+     */
+    public final void init(Key key, AlgorithmParameters params)
+            throws InvalidKeyException, InvalidAlgorithmParameterException,
+            ExemptionMechanismException {
+        done = false;
+        initialized = false;
+
+        keyStored = key;
+        exmechSpi.engineInit(key, params);
+        initialized = true;
+    }
+
+    /**
+     * Generates the exemption mechanism key blob.
+     *
+     * @return the new buffer with the result key blob.
+     *
+     * @exception IllegalStateException if this exemption mechanism is in
+     * a wrong state (e.g., has not been initialized).
+     * @exception ExemptionMechanismException if problem(s) encountered in the
+     * process of generating.
+     */
+    public final byte[] genExemptionBlob() throws IllegalStateException,
+            ExemptionMechanismException {
+        if (!initialized) {
+            throw new IllegalStateException(
+                "ExemptionMechanism not initialized");
+        }
+        byte[] blob = exmechSpi.engineGenExemptionBlob();
+        done = true;
+        return blob;
+    }
+
+    /**
+     * Generates the exemption mechanism key blob, and stores the result in
+     * the <code>output</code> buffer.
+     *
+     * <p>If the <code>output</code> buffer is too small to hold the result,
+     * a <code>ShortBufferException</code> is thrown. In this case, repeat this
+     * call with a larger output buffer. Use
+     * {@link #getOutputSize(int) getOutputSize} to determine how big
+     * the output buffer should be.
+     *
+     * @param output the buffer for the result
+     *
+     * @return the number of bytes stored in <code>output</code>
+     *
+     * @exception IllegalStateException if this exemption mechanism is in
+     * a wrong state (e.g., has not been initialized).
+     * @exception ShortBufferException if the given output buffer is too small
+     * to hold the result.
+     * @exception ExemptionMechanismException if problem(s) encountered in the
+     * process of generating.
+     */
+    public final int genExemptionBlob(byte[] output)
+            throws IllegalStateException, ShortBufferException,
+            ExemptionMechanismException {
+        if (!initialized) {
+            throw new IllegalStateException
+            ("ExemptionMechanism not initialized");
+        }
+        int n = exmechSpi.engineGenExemptionBlob(output, 0);
+        done = true;
+        return n;
+    }
+
+    /**
+     * Generates the exemption mechanism key blob, and stores the result in
+     * the <code>output</code> buffer, starting at <code>outputOffset</code>
+     * inclusive.
+     *
+     * <p>If the <code>output</code> buffer is too small to hold the result,
+     * a <code>ShortBufferException</code> is thrown. In this case, repeat this
+     * call with a larger output buffer. Use
+     * {@link #getOutputSize(int) getOutputSize} to determine how big
+     * the output buffer should be.
+     *
+     * @param output the buffer for the result
+     * @param outputOffset the offset in <code>output</code> where the result
+     * is stored
+     *
+     * @return the number of bytes stored in <code>output</code>
+     *
+     * @exception IllegalStateException if this exemption mechanism is in
+     * a wrong state (e.g., has not been initialized).
+     * @exception ShortBufferException if the given output buffer is too small
+     * to hold the result.
+     * @exception ExemptionMechanismException if problem(s) encountered in the
+     * process of generating.
+     */
+    public final int genExemptionBlob(byte[] output, int outputOffset)
+            throws IllegalStateException, ShortBufferException,
+            ExemptionMechanismException {
+        if (!initialized) {
+            throw new IllegalStateException
+            ("ExemptionMechanism not initialized");
+        }
+        int n = exmechSpi.engineGenExemptionBlob(output, outputOffset);
+        done = true;
+        return n;
+    }
+
+    // Android-removed: Unnecessary finalize() method.
+    // OpenJDK 9 also removed the method.
+    /*
+    protected void finalize() {
+        keyStored = null;
+        // Are there anything else we could do?
+    }
+    */
+}
diff --git a/javax/crypto/ExemptionMechanismException.java b/javax/crypto/ExemptionMechanismException.java
new file mode 100644
index 0000000..2fdc885
--- /dev/null
+++ b/javax/crypto/ExemptionMechanismException.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1999, 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 javax.crypto;
+
+import java.security.GeneralSecurityException;
+
+/**
+ * This is the generic ExemptionMechanism exception.
+ *
+ * @since 1.4
+ */
+
+public class ExemptionMechanismException extends GeneralSecurityException {
+
+    private static final long serialVersionUID = 1572699429277957109L;
+
+    /**
+     * Constructs a ExemptionMechanismException with no detailed message.
+     * (A detailed message is a String that describes this particular
+     * exception.)
+     */
+    public ExemptionMechanismException() {
+        super();
+    }
+
+    /**
+     * Constructs a ExemptionMechanismException with the specified
+     * detailed message. (A detailed message is a String that describes
+     * this particular exception.)
+     *
+     * @param msg the detailed message.
+     */
+   public ExemptionMechanismException(String msg) {
+       super(msg);
+    }
+}
diff --git a/javax/crypto/ExemptionMechanismSpi.java b/javax/crypto/ExemptionMechanismSpi.java
new file mode 100644
index 0000000..9a6d524
--- /dev/null
+++ b/javax/crypto/ExemptionMechanismSpi.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 1999, 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 javax.crypto;
+
+import java.security.Key;
+import java.security.AlgorithmParameters;
+import java.security.InvalidKeyException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>)
+ * for the <code>ExemptionMechanism</code> class.
+ * All the abstract methods in this class must be implemented by each
+ * cryptographic service provider who wishes to supply the implementation
+ * of a particular exemption mechanism.
+ *
+ * @author Sharon Liu
+ *
+ * @since 1.4
+ */
+
+public abstract class ExemptionMechanismSpi {
+
+    /**
+     * Returns the length in bytes that an output buffer would need to be in
+     * order to hold the result of the next
+     * {@link #engineGenExemptionBlob(byte[], int) engineGenExemptionBlob}
+     * operation, given the input length <code>inputLen</code> (in bytes).
+     *
+     * <p>The actual output length of the next
+     * {@link #engineGenExemptionBlob(byte[], int) engineGenExemptionBlob}
+     * call may be smaller than the length returned by this method.
+     *
+     * @param inputLen the input length (in bytes)
+     *
+     * @return the required output buffer size (in bytes)
+     */
+    protected abstract int engineGetOutputSize(int inputLen);
+
+    /**
+     * Initializes this exemption mechanism with a key.
+     *
+     * <p>If this exemption mechanism requires any algorithm parameters
+     * that cannot be derived from the given <code>key</code>, the underlying
+     * exemption mechanism implementation is supposed to generate the required
+     * parameters itself (using provider-specific default values); in the case
+     * that algorithm parameters must be specified by the caller, an
+     * <code>InvalidKeyException</code> is raised.
+     *
+     * @param key the key for this exemption mechanism
+     *
+     * @exception InvalidKeyException if the given key is inappropriate for
+     * this exemption mechanism.
+     * @exception ExemptionMechanismException if problem(s) encountered in the
+     * process of initializing.
+     */
+    protected abstract void engineInit(Key key)
+    throws InvalidKeyException, ExemptionMechanismException;
+
+    /**
+     * Initializes this exemption mechanism with a key and a set of algorithm
+     * parameters.
+     *
+     * <p>If this exemption mechanism requires any algorithm parameters and
+     * <code>params</code> is null, the underlying exemption mechanism
+     * implementation is supposed to generate the required parameters
+     * itself (using provider-specific default values); in the case that
+     * algorithm parameters must be specified by the caller, an
+     * <code>InvalidAlgorithmParameterException</code> is raised.
+     *
+     * @param key the key for this exemption mechanism
+     * @param params the algorithm parameters
+     *
+     * @exception InvalidKeyException if the given key is inappropriate for
+     * this exemption mechanism.
+     * @exception InvalidAlgorithmParameterException if the given algorithm
+     * parameters are inappropriate for this exemption mechanism.
+     * @exception ExemptionMechanismException if problem(s) encountered in the
+     * process of initializing.
+     */
+    protected abstract void engineInit(Key key, AlgorithmParameterSpec params)
+    throws InvalidKeyException, InvalidAlgorithmParameterException,
+    ExemptionMechanismException;
+
+    /**
+     * Initializes this exemption mechanism with a key and a set of algorithm
+     * parameters.
+     *
+     * <p>If this exemption mechanism requires any algorithm parameters
+     * and <code>params</code> is null, the underlying exemption mechanism
+     * implementation is supposed to generate the required parameters
+     * itself (using provider-specific default values); in the case that
+     * algorithm parameters must be specified by the caller, an
+     * <code>InvalidAlgorithmParameterException</code> is raised.
+     *
+     * @param key the key for this exemption mechanism
+     * @param params the algorithm parameters
+     *
+     * @exception InvalidKeyException if the given key is inappropriate for
+     * this exemption mechanism.
+     * @exception InvalidAlgorithmParameterException if the given algorithm
+     * parameters are inappropriate for this exemption mechanism.
+     * @exception ExemptionMechanismException if problem(s) encountered in the
+     * process of initializing.
+     */
+    protected abstract void engineInit(Key key, AlgorithmParameters params)
+    throws InvalidKeyException, InvalidAlgorithmParameterException,
+    ExemptionMechanismException;
+
+    /**
+     * Generates the exemption mechanism key blob.
+     *
+     * @return the new buffer with the result key blob.
+     *
+     * @exception ExemptionMechanismException if problem(s) encountered in the
+     * process of generating.
+     */
+    protected abstract byte[] engineGenExemptionBlob()
+        throws ExemptionMechanismException;
+
+    /**
+     * Generates the exemption mechanism key blob, and stores the result in
+     * the <code>output</code> buffer, starting at <code>outputOffset</code>
+     * inclusive.
+     *
+     * <p>If the <code>output</code> buffer is too small to hold the result,
+     * a <code>ShortBufferException</code> is thrown. In this case, repeat this
+     * call with a larger output buffer. Use
+     * {@link #engineGetOutputSize(int) engineGetOutputSize} to determine
+     * how big the output buffer should be.
+     *
+     * @param output the buffer for the result
+     * @param outputOffset the offset in <code>output</code> where the result
+     * is stored
+     *
+     * @return the number of bytes stored in <code>output</code>
+     *
+     * @exception ShortBufferException if the given output buffer is too small
+     * to hold the result.
+     * @exception ExemptionMechanismException if problem(s) encountered in the
+     * process of generating.
+     */
+    protected abstract int engineGenExemptionBlob
+    (byte[] output, int outputOffset)
+        throws ShortBufferException, ExemptionMechanismException;
+}
diff --git a/javax/crypto/IllegalBlockSizeException.java b/javax/crypto/IllegalBlockSizeException.java
new file mode 100644
index 0000000..01e7215
--- /dev/null
+++ b/javax/crypto/IllegalBlockSizeException.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 1997, 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 javax.crypto;
+
+/**
+ * This exception is thrown when the length of data provided to a block
+ * cipher is incorrect, i.e., does not match the block size of the cipher.
+ *
+ * @author Jan Luehe
+ *
+ * @since 1.4
+ */
+
+public class IllegalBlockSizeException
+    extends java.security.GeneralSecurityException {
+
+    private static final long serialVersionUID = -1965144811953540392L;
+
+    /**
+     * Constructs an IllegalBlockSizeException with no detail message.
+     * A detail message is a String that describes this particular
+     * exception.
+     */
+    public IllegalBlockSizeException() {
+        super();
+    }
+
+    /**
+     * Constructs an IllegalBlockSizeException with the specified
+     * detail message.
+     *
+     * @param msg the detail message.
+     */
+    public IllegalBlockSizeException(String msg) {
+        super(msg);
+    }
+}
diff --git a/javax/crypto/JarVerifier.java b/javax/crypto/JarVerifier.java
new file mode 100644
index 0000000..c56a0d1
--- /dev/null
+++ b/javax/crypto/JarVerifier.java
@@ -0,0 +1,153 @@
+/*
+ * 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 javax.crypto;
+
+import java.io.*;
+import java.net.*;
+import java.security.*;
+import java.util.jar.*;
+
+/**
+ * This class verifies JAR files (and any supporting JAR files), and
+ * determines whether they may be used in this implementation.
+ *
+ * The JCE in OpenJDK has an open cryptographic interface, meaning it
+ * does not restrict which providers can be used.  Compliance with
+ * United States export controls and with local law governing the
+ * import/export of products incorporating the JCE in the OpenJDK is
+ * the responsibility of the licensee.
+ *
+ * @since 1.7
+ */
+final class JarVerifier {
+
+    // The URL for the JAR file we want to verify.
+    private URL jarURL;
+    private boolean savePerms;
+    private CryptoPermissions appPerms = null;
+
+    /**
+     * Creates a JarVerifier object to verify the given URL.
+     *
+     * @param jarURL the JAR file to be verified.
+     * @param savePerms if true, save the permissions allowed by the
+     *          exemption mechanism
+     */
+    JarVerifier(URL jarURL, boolean savePerms) {
+        this.jarURL = jarURL;
+        this.savePerms = savePerms;
+    }
+
+    /**
+     * Verify the JAR file is signed by an entity which has a certificate
+     * issued by a trusted CA.
+     *
+     * In OpenJDK, we just need to examine the "cryptoperms" file to see
+     * if any permissions were bundled together with this jar file.
+     */
+    void verify() throws JarException, IOException {
+
+        // Short-circuit.  If we weren't asked to save any, we're done.
+        if (!savePerms) {
+            return;
+        }
+
+        // If the protocol of jarURL isn't "jar", we should
+        // construct a JAR URL so we can open a JarURLConnection
+        // for verifying this provider.
+        final URL url = jarURL.getProtocol().equalsIgnoreCase("jar")?
+                        jarURL : new URL("jar:" + jarURL.toString() + "!/");
+
+        JarFile jf = null;
+        try {
+
+            // Get a link to the Jarfile to search.
+            try {
+                jf = AccessController.doPrivileged(
+                         new PrivilegedExceptionAction<JarFile>() {
+                             public JarFile run() throws Exception {
+                                 JarURLConnection conn =
+                                     (JarURLConnection) url.openConnection();
+                                 // You could do some caching here as
+                                 // an optimization.
+                                 conn.setUseCaches(false);
+                                 return conn.getJarFile();
+                             }
+                         });
+            } catch (java.security.PrivilegedActionException pae) {
+                throw new SecurityException("Cannot load " + url.toString(), pae);
+            }
+
+            if (jf != null) {
+                JarEntry je = jf.getJarEntry("cryptoPerms");
+                if (je == null) {
+                    throw new JarException(
+                        "Can not find cryptoPerms");
+                }
+                try {
+                    appPerms = new CryptoPermissions();
+                    appPerms.load(jf.getInputStream(je));
+                } catch (Exception ex) {
+                    JarException jex =
+                        new JarException("Cannot load/parse" +
+                            jarURL.toString());
+                    jex.initCause(ex);
+                    throw jex;
+                }
+            }
+        } finally {
+            // Only call close() when caching is not enabled.
+            // Otherwise, exceptions will be thrown for all
+            // subsequent accesses of this cached jar.
+            if (jf != null) {
+                jf.close();
+            }
+        }
+    }
+
+    /**
+     * Verify that the provided certs include the
+     * framework signing certificate.
+     *
+     * @param certs the list of certs to be checked.
+     * @throws Exception if the list of certs did not contain
+     *          the framework signing certificate
+     */
+    static void verifyPolicySigned(java.security.cert.Certificate[] certs)
+            throws Exception {
+    }
+
+    /**
+     * Returns the permissions which are bundled with the JAR file,
+     * aka the "cryptoperms" file.
+     *
+     * NOTE: if this JarVerifier instance is constructed with "savePerms"
+     * equal to false, then this method would always return null.
+     */
+    CryptoPermissions getPermissions() {
+        return appPerms;
+    }
+}
diff --git a/javax/crypto/JceSecurity.java b/javax/crypto/JceSecurity.java
new file mode 100644
index 0000000..b0ae07e
--- /dev/null
+++ b/javax/crypto/JceSecurity.java
@@ -0,0 +1,354 @@
+/*
+ * 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 javax.crypto;
+
+import java.util.*;
+import java.util.jar.*;
+import java.io.*;
+import java.net.URL;
+import java.security.*;
+
+import java.security.Provider.Service;
+
+import sun.security.jca.*;
+import sun.security.jca.GetInstance.Instance;
+
+/**
+ * This class instantiates implementations of JCE engine classes from
+ * providers registered with the java.security.Security object.
+ *
+ * @author Jan Luehe
+ * @author Sharon Liu
+ * @since 1.4
+ */
+
+final class JceSecurity {
+
+    static final SecureRandom RANDOM = new SecureRandom();
+
+    // The defaultPolicy and exemptPolicy will be set up
+    // in the static initializer.
+    private static CryptoPermissions defaultPolicy = null;
+    private static CryptoPermissions exemptPolicy = null;
+
+    // Map<Provider,?> of the providers we already have verified
+    // value == PROVIDER_VERIFIED is successfully verified
+    // value is failure cause Exception in error case
+    private final static Map<Provider, Object> verificationResults =
+            new IdentityHashMap<>();
+
+    // Map<Provider,?> of the providers currently being verified
+    private final static Map<Provider, Object> verifyingProviders =
+            new IdentityHashMap<>();
+
+    // Android-removed: JCE crypto strength restrictions are never in place on Android.
+    // private static final boolean isRestricted = true;
+
+    // Android-removed: This debugging mechanism is not used in Android.
+    /*
+    private static final Debug debug =
+                        Debug.getInstance("jca", "Cipher");
+    */
+
+    /*
+     * Don't let anyone instantiate this.
+     */
+    private JceSecurity() {
+    }
+
+    // BEGIN Android-removed: JCE crypto strength restrictions are never in place on Android.
+    /*
+    static {
+        try {
+            AccessController.doPrivileged(
+                new PrivilegedExceptionAction<Object>() {
+                    public Object run() throws Exception {
+                        setupJurisdictionPolicies();
+                        return null;
+                    }
+                });
+
+            isRestricted = defaultPolicy.implies(
+                CryptoAllPermission.INSTANCE) ? false : true;
+        } catch (Exception e) {
+            throw new SecurityException(
+                    "Can not initialize cryptographic mechanism", e);
+        }
+    }
+    */
+    // END Android-removed: JCE crypto strength restrictions are never in place on Android.
+
+    static Instance getInstance(String type, Class<?> clazz, String algorithm,
+            String provider) throws NoSuchAlgorithmException,
+            NoSuchProviderException {
+        Service s = GetInstance.getService(type, algorithm, provider);
+        Exception ve = getVerificationResult(s.getProvider());
+        if (ve != null) {
+            String msg = "JCE cannot authenticate the provider " + provider;
+            throw (NoSuchProviderException)
+                                new NoSuchProviderException(msg).initCause(ve);
+        }
+        return GetInstance.getInstance(s, clazz);
+    }
+
+    static Instance getInstance(String type, Class<?> clazz, String algorithm,
+            Provider provider) throws NoSuchAlgorithmException {
+        Service s = GetInstance.getService(type, algorithm, provider);
+        Exception ve = JceSecurity.getVerificationResult(provider);
+        if (ve != null) {
+            String msg = "JCE cannot authenticate the provider "
+                + provider.getName();
+            throw new SecurityException(msg, ve);
+        }
+        return GetInstance.getInstance(s, clazz);
+    }
+
+    static Instance getInstance(String type, Class<?> clazz, String algorithm)
+            throws NoSuchAlgorithmException {
+        List<Service> services = GetInstance.getServices(type, algorithm);
+        NoSuchAlgorithmException failure = null;
+        for (Service s : services) {
+            if (canUseProvider(s.getProvider()) == false) {
+                // allow only signed providers
+                continue;
+            }
+            try {
+                Instance instance = GetInstance.getInstance(s, clazz);
+                return instance;
+            } catch (NoSuchAlgorithmException e) {
+                failure = e;
+            }
+        }
+        throw new NoSuchAlgorithmException("Algorithm " + algorithm
+                + " not available", failure);
+    }
+
+    /**
+     * Verify if the JAR at URL codeBase is a signed exempt application
+     * JAR file and returns the permissions bundled with the JAR.
+     *
+     * @throws Exception on error
+     */
+    static CryptoPermissions verifyExemptJar(URL codeBase) throws Exception {
+        JarVerifier jv = new JarVerifier(codeBase, true);
+        jv.verify();
+        return jv.getPermissions();
+    }
+
+    /**
+     * Verify if the JAR at URL codeBase is a signed provider JAR file.
+     *
+     * @throws Exception on error
+     */
+    static void verifyProviderJar(URL codeBase) throws Exception {
+        // Verify the provider JAR file and all
+        // supporting JAR files if there are any.
+        JarVerifier jv = new JarVerifier(codeBase, false);
+        jv.verify();
+    }
+
+    private final static Object PROVIDER_VERIFIED = Boolean.TRUE;
+
+    /*
+     * Verify that the provider JAR files are signed properly, which
+     * means the signer's certificate can be traced back to a
+     * JCE trusted CA.
+     * Return null if ok, failure Exception if verification failed.
+     */
+    static synchronized Exception getVerificationResult(Provider p) {
+        Object o = verificationResults.get(p);
+        if (o == PROVIDER_VERIFIED) {
+            return null;
+        } else if (o != null) {
+            return (Exception)o;
+        }
+        if (verifyingProviders.get(p) != null) {
+            // this method is static synchronized, must be recursion
+            // return failure now but do not save the result
+            return new NoSuchProviderException("Recursion during verification");
+        }
+        try {
+            verifyingProviders.put(p, Boolean.FALSE);
+            URL providerURL = getCodeBase(p.getClass());
+            verifyProviderJar(providerURL);
+            // Verified ok, cache result
+            verificationResults.put(p, PROVIDER_VERIFIED);
+            return null;
+        } catch (Exception e) {
+            verificationResults.put(p, e);
+            return e;
+        } finally {
+            verifyingProviders.remove(p);
+        }
+    }
+
+    // return whether this provider is properly signed and can be used by JCE
+    static boolean canUseProvider(Provider p) {
+        // BEGIN Android-changed: All providers are available.
+        // return getVerificationResult(p) == null;
+        return true;
+        // END Android-changed: All providers are available.
+    }
+
+    // dummy object to represent null
+    private static final URL NULL_URL;
+
+    static {
+        try {
+            NULL_URL = new URL("http://null.sun.com/");
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    // reference to a Map we use as a cache for codebases
+    private static final Map<Class<?>, URL> codeBaseCacheRef =
+            new WeakHashMap<>();
+
+    /*
+     * Returns the CodeBase for the given class.
+     */
+    static URL getCodeBase(final Class<?> clazz) {
+        synchronized (codeBaseCacheRef) {
+            URL url = codeBaseCacheRef.get(clazz);
+            if (url == null) {
+                url = AccessController.doPrivileged(new PrivilegedAction<URL>() {
+                    public URL run() {
+                        ProtectionDomain pd = clazz.getProtectionDomain();
+                        if (pd != null) {
+                            CodeSource cs = pd.getCodeSource();
+                            if (cs != null) {
+                                return cs.getLocation();
+                            }
+                        }
+                        return NULL_URL;
+                    }
+                });
+                codeBaseCacheRef.put(clazz, url);
+            }
+            return (url == NULL_URL) ? null : url;
+        }
+    }
+
+    // BEGIN Android-removed: JCE crypto strength restrictions are never in place on Android.
+    /*
+    private static void setupJurisdictionPolicies() throws Exception {
+        String javaHomeDir = System.getProperty("java.home");
+        String sep = File.separator;
+        String pathToPolicyJar = javaHomeDir + sep + "lib" + sep +
+            "security" + sep;
+
+        File exportJar = new File(pathToPolicyJar, "US_export_policy.jar");
+        File importJar = new File(pathToPolicyJar, "local_policy.jar");
+        URL jceCipherURL = ClassLoader.getSystemResource
+                ("javax/crypto/Cipher.class");
+
+        if ((jceCipherURL == null) ||
+                !exportJar.exists() || !importJar.exists()) {
+            throw new SecurityException
+                                ("Cannot locate policy or framework files!");
+        }
+
+        // Read jurisdiction policies.
+        CryptoPermissions defaultExport = new CryptoPermissions();
+        CryptoPermissions exemptExport = new CryptoPermissions();
+        loadPolicies(exportJar, defaultExport, exemptExport);
+
+        CryptoPermissions defaultImport = new CryptoPermissions();
+        CryptoPermissions exemptImport = new CryptoPermissions();
+        loadPolicies(importJar, defaultImport, exemptImport);
+
+        // Merge the export and import policies for default applications.
+        if (defaultExport.isEmpty() || defaultImport.isEmpty()) {
+            throw new SecurityException("Missing mandatory jurisdiction " +
+                                        "policy files");
+        }
+        defaultPolicy = defaultExport.getMinimum(defaultImport);
+
+        // Merge the export and import policies for exempt applications.
+        if (exemptExport.isEmpty())  {
+            exemptPolicy = exemptImport.isEmpty() ? null : exemptImport;
+        } else {
+            exemptPolicy = exemptExport.getMinimum(exemptImport);
+        }
+    }
+    */
+    // END Android-removed: JCE crypto strength restrictions are never in place on Android.
+
+    /**
+     * Load the policies from the specified file. Also checks that the
+     * policies are correctly signed.
+     */
+    private static void loadPolicies(File jarPathName,
+                                     CryptoPermissions defaultPolicy,
+                                     CryptoPermissions exemptPolicy)
+        throws Exception {
+
+        JarFile jf = new JarFile(jarPathName);
+
+        Enumeration<JarEntry> entries = jf.entries();
+        while (entries.hasMoreElements()) {
+            JarEntry je = entries.nextElement();
+            InputStream is = null;
+            try {
+                if (je.getName().startsWith("default_")) {
+                    is = jf.getInputStream(je);
+                    defaultPolicy.load(is);
+                } else if (je.getName().startsWith("exempt_")) {
+                    is = jf.getInputStream(je);
+                    exemptPolicy.load(is);
+                } else {
+                    continue;
+                }
+            } finally {
+                if (is != null) {
+                    is.close();
+                }
+            }
+
+            // Enforce the signer restraint, i.e. signer of JCE framework
+            // jar should also be the signer of the two jurisdiction policy
+            // jar files.
+            JarVerifier.verifyPolicySigned(je.getCertificates());
+        }
+        // Close and nullify the JarFile reference to help GC.
+        jf.close();
+        jf = null;
+    }
+
+    static CryptoPermissions getDefaultPolicy() {
+        return defaultPolicy;
+    }
+
+    static CryptoPermissions getExemptPolicy() {
+        return exemptPolicy;
+    }
+
+    // Android-removed: JCE crypto strength restrictions are never in place on Android.
+    // static boolean isRestricted() {
+    //     return isRestricted;
+    // }
+}
diff --git a/javax/crypto/JceSecurityManager.java b/javax/crypto/JceSecurityManager.java
new file mode 100644
index 0000000..aafaa58
--- /dev/null
+++ b/javax/crypto/JceSecurityManager.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 1999, 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 javax.crypto;
+
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
+/**
+ * Legacy security code; do not use.
+ */
+
+final class JceSecurityManager extends SecurityManager {
+
+    // singleton instance
+    static final JceSecurityManager INSTANCE = null;
+
+    private JceSecurityManager() {
+        // empty
+    }
+
+    CryptoPermission getCryptoPermission(String alg) { return null; }
+}
diff --git a/javax/crypto/KeyAgreement.java b/javax/crypto/KeyAgreement.java
new file mode 100644
index 0000000..fd79680
--- /dev/null
+++ b/javax/crypto/KeyAgreement.java
@@ -0,0 +1,687 @@
+/*
+ * 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 javax.crypto;
+
+import java.util.*;
+
+import java.security.*;
+import java.security.Provider.Service;
+import java.security.spec.*;
+
+import sun.security.jca.*;
+import sun.security.jca.GetInstance.Instance;
+
+/**
+ * This class provides the functionality of a key agreement (or key
+ * exchange) protocol.
+ * <p>
+ * The keys involved in establishing a shared secret are created by one of the
+ * key generators (<code>KeyPairGenerator</code> or
+ * <code>KeyGenerator</code>), a <code>KeyFactory</code>, or as a result from
+ * an intermediate phase of the key agreement protocol.
+ *
+ * <p> For each of the correspondents in the key exchange, <code>doPhase</code>
+ * needs to be called. For example, if this key exchange is with one other
+ * party, <code>doPhase</code> needs to be called once, with the
+ * <code>lastPhase</code> flag set to <code>true</code>.
+ * If this key exchange is
+ * with two other parties, <code>doPhase</code> needs to be called twice,
+ * the first time setting the <code>lastPhase</code> flag to
+ * <code>false</code>, and the second time setting it to <code>true</code>.
+ * There may be any number of parties involved in a key exchange.
+ *
+ * <p> Android provides the following <code>KeyAgreement</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>ECDH</td>
+ *       <td>11+</td>
+ *     </tr>
+ *   </tbody>
+ * </table>
+ *
+ * This algorithm is described in the <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyAgreement">
+ * KeyAgreement section</a> of the
+ * Java Cryptography Architecture Standard Algorithm Name Documentation.
+ *
+ * @author Jan Luehe
+ *
+ * @see KeyGenerator
+ * @see SecretKey
+ * @since 1.4
+ */
+
+public class KeyAgreement {
+
+    // Android-removed: this debugging mechanism is not used in Android.
+    /*
+    private static final Debug debug =
+                        Debug.getInstance("jca", "KeyAgreement");
+
+    private static final Debug pdebug =
+                        Debug.getInstance("provider", "Provider");
+    private static final boolean skipDebug =
+        Debug.isOn("engine=") && !Debug.isOn("keyagreement");
+    */
+
+    // The provider
+    private Provider provider;
+
+    // The provider implementation (delegate)
+    private KeyAgreementSpi spi;
+
+    // The name of the key agreement algorithm.
+    private final String algorithm;
+
+    // BEGIN Android-removed: Redo the provider selection logic to allow reselecting provider.
+    // When only the algorithm is specified, we want to allow the KeyAgreement 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.
+
+    private final Object lock;
+
+    /**
+     * Creates a KeyAgreement object.
+     *
+     * @param keyAgreeSpi the delegate
+     * @param provider the provider
+     * @param algorithm the algorithm
+     */
+    protected KeyAgreement(KeyAgreementSpi keyAgreeSpi, Provider provider,
+                           String algorithm) {
+        this.spi = keyAgreeSpi;
+        this.provider = provider;
+        this.algorithm = algorithm;
+        lock = null;
+    }
+
+    // Android-changed: Remove Service and Iterator from constructor args.
+    private KeyAgreement(String algorithm) {
+        this.algorithm = algorithm;
+        lock = new Object();
+    }
+
+    /**
+     * Returns the algorithm name of this <code>KeyAgreement</code> object.
+     *
+     * <p>This is the same name that was specified in one of the
+     * <code>getInstance</code> calls that created this
+     * <code>KeyAgreement</code> object.
+     *
+     * @return the algorithm name of this <code>KeyAgreement</code> object.
+     */
+    public final String getAlgorithm() {
+        return this.algorithm;
+    }
+
+    /**
+     * Returns a <code>KeyAgreement</code> object that implements the
+     * specified key agreement algorithm.
+     *
+     * <p> This method traverses the list of registered security Providers,
+     * starting with the most preferred Provider.
+     * A new KeyAgreement object encapsulating the
+     * KeyAgreementSpi 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 requested key agreement
+     * algorithm.
+     * See the KeyAgreement section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyAgreement">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard algorithm names.
+     *
+     * @return the new <code>KeyAgreement</code> object.
+     *
+     * @exception NullPointerException if the specified algorithm
+     *          is null.
+     *
+     * @exception NoSuchAlgorithmException if no Provider supports a
+     *          KeyAgreementSpi implementation for the
+     *          specified algorithm.
+     *
+     * @see java.security.Provider
+     */
+    public static final KeyAgreement getInstance(String algorithm)
+            throws NoSuchAlgorithmException {
+        List<Service> services =
+                GetInstance.getServices("KeyAgreement", algorithm);
+        // make sure there is at least one service from a signed provider
+        Iterator<Service> t = services.iterator();
+        while (t.hasNext()) {
+            Service s = t.next();
+            if (JceSecurity.canUseProvider(s.getProvider()) == false) {
+                continue;
+            }
+            // Android-changed: Remove Service and Iterator from constructor args.
+            // return new KeyAgreement(s, t, algorithm);
+            return new KeyAgreement(algorithm);
+        }
+        throw new NoSuchAlgorithmException
+                                ("Algorithm " + algorithm + " not available");
+    }
+
+    /**
+     * Returns a <code>KeyAgreement</code> object that implements the
+     * specified key agreement algorithm.
+     *
+     * <p> A new KeyAgreement object encapsulating the
+     * KeyAgreementSpi 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 name of the requested key agreement
+     * algorithm.
+     * See the KeyAgreement section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyAgreement">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard algorithm names.
+     *
+     * @param provider the name of the provider.
+     *
+     * @return the new <code>KeyAgreement</code> object.
+     *
+     * @exception NullPointerException if the specified algorithm
+     *          is null.
+     *
+     * @exception NoSuchAlgorithmException if a KeyAgreementSpi
+     *          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</code>
+     *          is null or empty.
+     *
+     * @see java.security.Provider
+     */
+    public static final KeyAgreement getInstance(String algorithm,
+            String provider) throws NoSuchAlgorithmException,
+            NoSuchProviderException {
+        // Android-added: Check for Bouncy Castle deprecation
+        Providers.checkBouncyCastleDeprecation(provider, "KeyAgreement", algorithm);
+        Instance instance = JceSecurity.getInstance
+                ("KeyAgreement", KeyAgreementSpi.class, algorithm, provider);
+        return new KeyAgreement((KeyAgreementSpi)instance.impl,
+                instance.provider, algorithm);
+    }
+
+    /**
+     * Returns a <code>KeyAgreement</code> object that implements the
+     * specified key agreement algorithm.
+     *
+     * <p> A new KeyAgreement object encapsulating the
+     * KeyAgreementSpi 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 name of the requested key agreement
+     * algorithm.
+     * See the KeyAgreement section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyAgreement">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard algorithm names.
+     *
+     * @param provider the provider.
+     *
+     * @return the new <code>KeyAgreement</code> object.
+     *
+     * @exception NullPointerException if the specified algorithm
+     *          is null.
+     *
+     * @exception NoSuchAlgorithmException if a KeyAgreementSpi
+     *          implementation for the specified algorithm is not available
+     *          from the specified Provider object.
+     *
+     * @exception IllegalArgumentException if the <code>provider</code>
+     *          is null.
+     *
+     * @see java.security.Provider
+     */
+    public static final KeyAgreement getInstance(String algorithm,
+            Provider provider) throws NoSuchAlgorithmException {
+        // Android-added: Check for Bouncy Castle deprecation
+        Providers.checkBouncyCastleDeprecation(provider, "KeyAgreement", algorithm);
+        Instance instance = JceSecurity.getInstance
+                ("KeyAgreement", KeyAgreementSpi.class, algorithm, provider);
+        return new KeyAgreement((KeyAgreementSpi)instance.impl,
+                instance.provider, algorithm);
+    }
+
+    // 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 init()
+     * is not the first method called.
+     */
+    void chooseFirstProvider() {
+        if (spi != null) {
+            return;
+        }
+        synchronized (lock) {
+            if (spi != null) {
+                return;
+            }
+            // Android-removed: this debugging mechanism is not used in Android.
+            /*
+            if (debug != null) {
+                int w = --warnCount;
+                if (w >= 0) {
+                    debug.println("KeyAgreement.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();
+                }
+            }
+            */
+            Exception lastException = null;
+            // Android-changed: Provider selection; loop over a new list each time.
+            for (Service s : GetInstance.getServices("KeyAgreement", algorithm)) {
+                if (JceSecurity.canUseProvider(s.getProvider()) == false) {
+                    continue;
+                }
+                try {
+                    Object obj = s.newInstance(null);
+                    if (obj instanceof KeyAgreementSpi == false) {
+                        continue;
+                    }
+                    spi = (KeyAgreementSpi)obj;
+                    provider = s.getProvider();
+                    // Android-removed: Provider selection; loop over a new list each time.
+                    /*
+                    // not needed any more
+                    firstService = null;
+                    serviceIterator = null;
+                    */
+                    return;
+                } catch (Exception e) {
+                    lastException = e;
+                }
+            }
+            ProviderException e = new ProviderException
+                    ("Could not construct KeyAgreementSpi instance");
+            if (lastException != null) {
+                e.initCause(lastException);
+            }
+            throw e;
+        }
+    }
+
+    private final static int I_NO_PARAMS = 1;
+    private final static int I_PARAMS    = 2;
+
+    private void implInit(KeyAgreementSpi spi, int type, Key key,
+            AlgorithmParameterSpec params, SecureRandom random)
+            throws InvalidKeyException, InvalidAlgorithmParameterException {
+        if (type == I_NO_PARAMS) {
+            spi.engineInit(key, random);
+        } else { // I_PARAMS
+            spi.engineInit(key, params, random);
+        }
+    }
+
+    private void chooseProvider(int initType, Key key,
+            AlgorithmParameterSpec params, SecureRandom random)
+            throws InvalidKeyException, InvalidAlgorithmParameterException {
+        synchronized (lock) {
+            // Android-changed: Use the currently-selected provider only if no key was provided.
+            // if (spi != null) {
+            if (spi != null && key == null) {
+                implInit(spi, initType, key, params, random);
+                return;
+            }
+            Exception lastException = null;
+            // Android-changed: Provider selection; loop over a new list each time.
+            for (Service s : GetInstance.getServices("KeyAgreement", algorithm)) {
+                // if provider says it does not support this key, ignore it
+                if (s.supportsParameter(key) == false) {
+                    continue;
+                }
+                if (JceSecurity.canUseProvider(s.getProvider()) == false) {
+                    continue;
+                }
+                try {
+                    KeyAgreementSpi spi = (KeyAgreementSpi)s.newInstance(null);
+                    implInit(spi, initType, key, params, random);
+                    provider = s.getProvider();
+                    this.spi = 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;
+                    }
+                }
+            }
+            // no working provider found, fail
+            if (lastException instanceof InvalidKeyException) {
+                throw (InvalidKeyException)lastException;
+            }
+            if (lastException instanceof InvalidAlgorithmParameterException) {
+                throw (InvalidAlgorithmParameterException)lastException;
+            }
+            if (lastException instanceof RuntimeException) {
+                throw (RuntimeException)lastException;
+            }
+            String kName = (key != null) ? key.getClass().getName() : "(null)";
+            throw new InvalidKeyException
+                ("No installed provider supports this key: "
+                + kName, lastException);
+        }
+    }
+
+    /**
+     * Returns the provider of this <code>KeyAgreement</code> object.
+     *
+     * @return the provider of this <code>KeyAgreement</code> object
+     */
+    public final Provider getProvider() {
+        chooseFirstProvider();
+        return this.provider;
+    }
+
+    /**
+     * Initializes this key agreement with the given key, which is required to
+     * contain all the algorithm parameters required for this key agreement.
+     *
+     * <p> If this key agreement requires any random bytes, it will get
+     * them using the
+     * {@link java.security.SecureRandom}
+     * implementation of the highest-priority
+     * installed provider as the source of randomness.
+     * (If none of the installed providers supply an implementation of
+     * SecureRandom, a system-provided source of randomness will be used.)
+     *
+     * @param key the party's private information. For example, in the case
+     * of the Diffie-Hellman key agreement, this would be the party's own
+     * Diffie-Hellman private key.
+     *
+     * @exception InvalidKeyException if the given key is
+     * inappropriate for this key agreement, e.g., is of the wrong type or
+     * has an incompatible algorithm type.
+     */
+    public final void init(Key key) throws InvalidKeyException {
+        init(key, JceSecurity.RANDOM);
+    }
+
+    /**
+     * Initializes this key agreement with the given key and source of
+     * randomness. The given key is required to contain all the algorithm
+     * parameters required for this key agreement.
+     *
+     * <p> If the key agreement algorithm requires random bytes, it gets them
+     * from the given source of randomness, <code>random</code>.
+     * However, if the underlying
+     * algorithm implementation does not require any random bytes,
+     * <code>random</code> is ignored.
+     *
+     * @param key the party's private information. For example, in the case
+     * of the Diffie-Hellman key agreement, this would be the party's own
+     * Diffie-Hellman private key.
+     * @param random the source of randomness
+     *
+     * @exception InvalidKeyException if the given key is
+     * inappropriate for this key agreement, e.g., is of the wrong type or
+     * has an incompatible algorithm type.
+     */
+    public final void init(Key key, SecureRandom random)
+            throws InvalidKeyException {
+        // Android-changed: Use the currently-selected provider only if no key was provided.
+        // if (spi != null) {
+        if (spi != null && (key == null || lock == null)) {
+            spi.engineInit(key, random);
+        } else {
+            try {
+                chooseProvider(I_NO_PARAMS, key, null, random);
+            } catch (InvalidAlgorithmParameterException e) {
+                // should never occur
+                throw new InvalidKeyException(e);
+            }
+        }
+
+        // Android-removed: this debugging mechanism is not used in Android.
+        /*
+        if (!skipDebug && pdebug != null) {
+            pdebug.println("KeyAgreement." + algorithm + " algorithm from: " +
+                this.provider.getName());
+        }
+        */
+    }
+
+    /**
+     * Initializes this key agreement with the given key and set of
+     * algorithm parameters.
+     *
+     * <p> If this key agreement requires any random bytes, it will get
+     * them using the
+     * {@link java.security.SecureRandom}
+     * implementation of the highest-priority
+     * installed provider as the source of randomness.
+     * (If none of the installed providers supply an implementation of
+     * SecureRandom, a system-provided source of randomness will be used.)
+     *
+     * @param key the party's private information. For example, in the case
+     * of the Diffie-Hellman key agreement, this would be the party's own
+     * Diffie-Hellman private key.
+     * @param params the key agreement parameters
+     *
+     * @exception InvalidKeyException if the given key is
+     * inappropriate for this key agreement, e.g., is of the wrong type or
+     * has an incompatible algorithm type.
+     * @exception InvalidAlgorithmParameterException if the given parameters
+     * are inappropriate for this key agreement.
+     */
+    public final void init(Key key, AlgorithmParameterSpec params)
+        throws InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        init(key, params, JceSecurity.RANDOM);
+    }
+
+    /**
+     * Initializes this key agreement with the given key, set of
+     * algorithm parameters, and source of randomness.
+     *
+     * @param key the party's private information. For example, in the case
+     * of the Diffie-Hellman key agreement, this would be the party's own
+     * Diffie-Hellman private key.
+     * @param params the key agreement parameters
+     * @param random the source of randomness
+     *
+     * @exception InvalidKeyException if the given key is
+     * inappropriate for this key agreement, e.g., is of the wrong type or
+     * has an incompatible algorithm type.
+     * @exception InvalidAlgorithmParameterException if the given parameters
+     * are inappropriate for this key agreement.
+     */
+    public final void init(Key key, AlgorithmParameterSpec params,
+                           SecureRandom random)
+        throws InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        if (spi != null) {
+            spi.engineInit(key, params, random);
+        } else {
+            chooseProvider(I_PARAMS, key, params, random);
+        }
+
+        // Android-removed: this debugging mechanism is not used in Android.
+        /*
+        if (!skipDebug && pdebug != null) {
+            pdebug.println("KeyAgreement." + algorithm + " algorithm from: " +
+                this.provider.getName());
+        }
+        */
+    }
+
+    /**
+     * Executes the next phase of this key agreement with the given
+     * key that was received from one of the other parties involved in this key
+     * agreement.
+     *
+     * @param key the key for this phase. For example, in the case of
+     * Diffie-Hellman between 2 parties, this would be the other party's
+     * Diffie-Hellman public key.
+     * @param lastPhase flag which indicates whether or not this is the last
+     * phase of this key agreement.
+     *
+     * @return the (intermediate) key resulting from this phase, or null
+     * if this phase does not yield a key
+     *
+     * @exception InvalidKeyException if the given key is inappropriate for
+     * this phase.
+     * @exception IllegalStateException if this key agreement has not been
+     * initialized.
+     */
+    public final Key doPhase(Key key, boolean lastPhase)
+        throws InvalidKeyException, IllegalStateException
+    {
+        chooseFirstProvider();
+        return spi.engineDoPhase(key, lastPhase);
+    }
+
+    /**
+     * Generates the shared secret and returns it in a new buffer.
+     *
+     * <p>This method resets this <code>KeyAgreement</code> object, so that it
+     * can be reused for further key agreements. Unless this key agreement is
+     * reinitialized with one of the <code>init</code> methods, the same
+     * private information and algorithm parameters will be used for
+     * subsequent key agreements.
+     *
+     * @return the new buffer with the shared secret
+     *
+     * @exception IllegalStateException if this key agreement has not been
+     * completed yet
+     */
+    public final byte[] generateSecret() throws IllegalStateException {
+        chooseFirstProvider();
+        return spi.engineGenerateSecret();
+    }
+
+    /**
+     * Generates the shared secret, and places it into the buffer
+     * <code>sharedSecret</code>, beginning at <code>offset</code> inclusive.
+     *
+     * <p>If the <code>sharedSecret</code> buffer is too small to hold the
+     * result, a <code>ShortBufferException</code> is thrown.
+     * In this case, this call should be repeated with a larger output buffer.
+     *
+     * <p>This method resets this <code>KeyAgreement</code> object, so that it
+     * can be reused for further key agreements. Unless this key agreement is
+     * reinitialized with one of the <code>init</code> methods, the same
+     * private information and algorithm parameters will be used for
+     * subsequent key agreements.
+     *
+     * @param sharedSecret the buffer for the shared secret
+     * @param offset the offset in <code>sharedSecret</code> where the
+     * shared secret will be stored
+     *
+     * @return the number of bytes placed into <code>sharedSecret</code>
+     *
+     * @exception IllegalStateException if this key agreement has not been
+     * completed yet
+     * @exception ShortBufferException if the given output buffer is too small
+     * to hold the secret
+     */
+    public final int generateSecret(byte[] sharedSecret, int offset)
+        throws IllegalStateException, ShortBufferException
+    {
+        chooseFirstProvider();
+        return spi.engineGenerateSecret(sharedSecret, offset);
+    }
+
+    /**
+     * Creates the shared secret and returns it as a <code>SecretKey</code>
+     * object of the specified algorithm.
+     *
+     * <p>This method resets this <code>KeyAgreement</code> object, so that it
+     * can be reused for further key agreements. Unless this key agreement is
+     * reinitialized with one of the <code>init</code> methods, the same
+     * private information and algorithm parameters will be used for
+     * subsequent key agreements.
+     *
+     * @param algorithm the requested secret-key algorithm
+     *
+     * @return the shared secret key
+     *
+     * @exception IllegalStateException if this key agreement has not been
+     * completed yet
+     * @exception NoSuchAlgorithmException if the specified secret-key
+     * algorithm is not available
+     * @exception InvalidKeyException if the shared secret-key material cannot
+     * be used to generate a secret key of the specified algorithm (e.g.,
+     * the key material is too short)
+     */
+    public final SecretKey generateSecret(String algorithm)
+        throws IllegalStateException, NoSuchAlgorithmException,
+            InvalidKeyException
+    {
+        chooseFirstProvider();
+        return spi.engineGenerateSecret(algorithm);
+    }
+}
diff --git a/javax/crypto/KeyAgreementSpi.java b/javax/crypto/KeyAgreementSpi.java
new file mode 100644
index 0000000..51c8307
--- /dev/null
+++ b/javax/crypto/KeyAgreementSpi.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 1997, 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 javax.crypto;
+
+import java.security.*;
+import java.security.spec.*;
+
+/**
+ * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>)
+ * for the <code>KeyAgreement</code> class.
+ * All the abstract methods in this class must be implemented by each
+ * cryptographic service provider who wishes to supply the implementation
+ * of a particular key agreement algorithm.
+ *
+ * <p> The keys involved in establishing a shared secret are created by one
+ * of the
+ * key generators (<code>KeyPairGenerator</code> or
+ * <code>KeyGenerator</code>), a <code>KeyFactory</code>, or as a result from
+ * an intermediate phase of the key agreement protocol
+ * ({@link #engineDoPhase(java.security.Key, boolean) engineDoPhase}).
+ *
+ * <p> For each of the correspondents in the key exchange,
+ * <code>engineDoPhase</code>
+ * needs to be called. For example, if the key exchange is with one other
+ * party, <code>engineDoPhase</code> needs to be called once, with the
+ * <code>lastPhase</code> flag set to <code>true</code>.
+ * If the key exchange is
+ * with two other parties, <code>engineDoPhase</code> needs to be called twice,
+ * the first time setting the <code>lastPhase</code> flag to
+ * <code>false</code>, and the second time setting it to <code>true</code>.
+ * There may be any number of parties involved in a key exchange.
+ *
+ * @author Jan Luehe
+ *
+ * @see KeyGenerator
+ * @see SecretKey
+ * @since 1.4
+ */
+
+public abstract class KeyAgreementSpi {
+
+    /**
+     * Initializes this key agreement with the given key and source of
+     * randomness. The given key is required to contain all the algorithm
+     * parameters required for this key agreement.
+     *
+     * <p> If the key agreement algorithm requires random bytes, it gets them
+     * from the given source of randomness, <code>random</code>.
+     * However, if the underlying
+     * algorithm implementation does not require any random bytes,
+     * <code>random</code> is ignored.
+     *
+     * @param key the party's private information. For example, in the case
+     * of the Diffie-Hellman key agreement, this would be the party's own
+     * Diffie-Hellman private key.
+     * @param random the source of randomness
+     *
+     * @exception InvalidKeyException if the given key is
+     * inappropriate for this key agreement, e.g., is of the wrong type or
+     * has an incompatible algorithm type.
+     */
+    protected abstract void engineInit(Key key, SecureRandom random)
+        throws InvalidKeyException;
+
+    /**
+     * Initializes this key agreement with the given key, set of
+     * algorithm parameters, and source of randomness.
+     *
+     * @param key the party's private information. For example, in the case
+     * of the Diffie-Hellman key agreement, this would be the party's own
+     * Diffie-Hellman private key.
+     * @param params the key agreement parameters
+     * @param random the source of randomness
+     *
+     * @exception InvalidKeyException if the given key is
+     * inappropriate for this key agreement, e.g., is of the wrong type or
+     * has an incompatible algorithm type.
+     * @exception InvalidAlgorithmParameterException if the given parameters
+     * are inappropriate for this key agreement.
+     */
+    protected abstract void engineInit(Key key, AlgorithmParameterSpec params,
+                                       SecureRandom random)
+        throws InvalidKeyException, InvalidAlgorithmParameterException;
+
+    /**
+     * Executes the next phase of this key agreement with the given
+     * key that was received from one of the other parties involved in this key
+     * agreement.
+     *
+     * @param key the key for this phase. For example, in the case of
+     * Diffie-Hellman between 2 parties, this would be the other party's
+     * Diffie-Hellman public key.
+     * @param lastPhase flag which indicates whether or not this is the last
+     * phase of this key agreement.
+     *
+     * @return the (intermediate) key resulting from this phase, or null if
+     * this phase does not yield a key
+     *
+     * @exception InvalidKeyException if the given key is inappropriate for
+     * this phase.
+     * @exception IllegalStateException if this key agreement has not been
+     * initialized.
+     */
+    protected abstract Key engineDoPhase(Key key, boolean lastPhase)
+        throws InvalidKeyException, IllegalStateException;
+
+    /**
+     * Generates the shared secret and returns it in a new buffer.
+     *
+     * <p>This method resets this <code>KeyAgreementSpi</code> object,
+     * so that it
+     * can be reused for further key agreements. Unless this key agreement is
+     * reinitialized with one of the <code>engineInit</code> methods, the same
+     * private information and algorithm parameters will be used for
+     * subsequent key agreements.
+     *
+     * @return the new buffer with the shared secret
+     *
+     * @exception IllegalStateException if this key agreement has not been
+     * completed yet
+     */
+    protected abstract byte[] engineGenerateSecret()
+        throws IllegalStateException;
+
+    /**
+     * Generates the shared secret, and places it into the buffer
+     * <code>sharedSecret</code>, beginning at <code>offset</code> inclusive.
+     *
+     * <p>If the <code>sharedSecret</code> buffer is too small to hold the
+     * result, a <code>ShortBufferException</code> is thrown.
+     * In this case, this call should be repeated with a larger output buffer.
+     *
+     * <p>This method resets this <code>KeyAgreementSpi</code> object,
+     * so that it
+     * can be reused for further key agreements. Unless this key agreement is
+     * reinitialized with one of the <code>engineInit</code> methods, the same
+     * private information and algorithm parameters will be used for
+     * subsequent key agreements.
+     *
+     * @param sharedSecret the buffer for the shared secret
+     * @param offset the offset in <code>sharedSecret</code> where the
+     * shared secret will be stored
+     *
+     * @return the number of bytes placed into <code>sharedSecret</code>
+     *
+     * @exception IllegalStateException if this key agreement has not been
+     * completed yet
+     * @exception ShortBufferException if the given output buffer is too small
+     * to hold the secret
+     */
+    protected abstract int engineGenerateSecret(byte[] sharedSecret,
+                                                int offset)
+        throws IllegalStateException, ShortBufferException;
+
+    /**
+     * Creates the shared secret and returns it as a secret key object
+     * of the requested algorithm type.
+     *
+     * <p>This method resets this <code>KeyAgreementSpi</code> object,
+     * so that it
+     * can be reused for further key agreements. Unless this key agreement is
+     * reinitialized with one of the <code>engineInit</code> methods, the same
+     * private information and algorithm parameters will be used for
+     * subsequent key agreements.
+     *
+     * @param algorithm the requested secret key algorithm
+     *
+     * @return the shared secret key
+     *
+     * @exception IllegalStateException if this key agreement has not been
+     * completed yet
+     * @exception NoSuchAlgorithmException if the requested secret key
+     * algorithm is not available
+     * @exception InvalidKeyException if the shared secret key material cannot
+     * be used to generate a secret key of the requested algorithm type (e.g.,
+     * the key material is too short)
+     */
+    protected abstract SecretKey engineGenerateSecret(String algorithm)
+        throws IllegalStateException, NoSuchAlgorithmException,
+            InvalidKeyException;
+}
diff --git a/javax/crypto/KeyGenerator.java b/javax/crypto/KeyGenerator.java
new file mode 100644
index 0000000..5951eef
--- /dev/null
+++ b/javax/crypto/KeyGenerator.java
@@ -0,0 +1,628 @@
+/*
+ * 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 javax.crypto;
+
+import java.util.*;
+
+import java.security.*;
+import java.security.Provider.Service;
+import java.security.spec.*;
+
+import sun.security.jca.*;
+import sun.security.jca.GetInstance.Instance;
+
+/**
+ * This class provides the functionality of a secret (symmetric) key generator.
+ *
+ * <p>Key generators are constructed using one of the <code>getInstance</code>
+ * class methods of this class.
+ *
+ * <p>KeyGenerator objects are reusable, i.e., after a key has been
+ * generated, the same KeyGenerator object can be re-used to generate further
+ * keys.
+ *
+ * <p>There are two ways to generate a key: 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 generators share the concepts of a <i>keysize</i> and a
+ * <i>source of randomness</i>.
+ * There is an
+ * {@link #init(int, java.security.SecureRandom) init}
+ * method in this KeyGenerator class that takes these two universally
+ * shared types of arguments. There is also one that takes just a
+ * <code>keysize</code> argument, and uses the SecureRandom implementation
+ * of the highest-priority installed provider as the source of randomness
+ * (or a system-provided source of randomness if none of the installed
+ * providers supply a SecureRandom implementation), and one that takes just a
+ * source of randomness.
+ *
+ * <p>Since no other parameters are specified when you call the above
+ * algorithm-independent <code>init</code> 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.
+ *
+ * <li><b>Algorithm-Specific Initialization</b>
+ * <p>For situations where a set of algorithm-specific parameters already
+ * exists, there are two
+ * {@link #init(java.security.spec.AlgorithmParameterSpec) init}
+ * methods that have an <code>AlgorithmParameterSpec</code>
+ * argument. One also has a <code>SecureRandom</code> argument, while the
+ * other uses the SecureRandom implementation
+ * of the highest-priority installed provider as the source of randomness
+ * (or a system-provided source of randomness if none of the installed
+ * providers supply a SecureRandom implementation).
+ * </ul>
+ *
+ * <p>In case the client does not explicitly initialize the KeyGenerator
+ * (via a call to an <code>init</code> method), each provider must
+ * supply (and document) a default initialization.
+ *
+ * <p> Android provides the following <code>KeyGenerator</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 class="deprecated">
+ *       <td>AESWRAP</td>
+ *       <td>1-8</td>
+ *     </tr>
+ *     <tr>
+ *       <td>ARC4</td>
+ *       <td>14+</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 class="deprecated">
+ *       <td>DESedeWRAP</td>
+ *       <td>1-8</td>
+ *     </tr>
+ *     <tr>
+ *       <td>HmacMD5</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>HmacSHA1</td>
+ *       <td>11+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>HmacSHA224</td>
+ *       <td>1-8,22+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>HmacSHA256</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>HmacSHA384</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>HmacSHA512</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>RC4</td>
+ *       <td>10-13</td>
+ *     </tr>
+ *   </tbody>
+ * </table>
+ *
+ * These algorithms are described in the <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyGenerator">
+ * KeyGenerator section</a> of the
+ * Java Cryptography Architecture Standard Algorithm Name Documentation.
+ *
+ * @author Jan Luehe
+ *
+ * @see SecretKey
+ * @since 1.4
+ */
+
+public class KeyGenerator {
+
+    // 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("keygenerator");
+    */
+
+    // see java.security.KeyPairGenerator for failover notes
+
+    private final static int I_NONE   = 1;
+    private final static int I_RANDOM = 2;
+    private final static int I_PARAMS = 3;
+    private final static int I_SIZE   = 4;
+
+    // The provider
+    private Provider provider;
+
+    // The provider implementation (delegate)
+    private volatile KeyGeneratorSpi spi;
+
+    // The algorithm
+    private final String algorithm;
+
+    private final Object lock = new Object();
+
+    private Iterator<Service> serviceIterator;
+
+    private int initType;
+    private int initKeySize;
+    private AlgorithmParameterSpec initParams;
+    private SecureRandom initRandom;
+
+    /**
+     * Creates a KeyGenerator object.
+     *
+     * @param keyGenSpi the delegate
+     * @param provider the provider
+     * @param algorithm the algorithm
+     */
+    protected KeyGenerator(KeyGeneratorSpi keyGenSpi, Provider provider,
+                           String algorithm) {
+        this.spi = keyGenSpi;
+        this.provider = provider;
+        this.algorithm = algorithm;
+
+        // Android-removed: this debugging mechanism is not used in Android.
+        /*
+        if (!skipDebug && pdebug != null) {
+            pdebug.println("KeyGenerator." + algorithm + " algorithm from: " +
+                this.provider.getName());
+        }
+        */
+    }
+
+    private KeyGenerator(String algorithm) throws NoSuchAlgorithmException {
+        this.algorithm = algorithm;
+        List<Service> list =
+                GetInstance.getServices("KeyGenerator", algorithm);
+        serviceIterator = list.iterator();
+        initType = I_NONE;
+        // fetch and instantiate initial spi
+        if (nextSpi(null, false) == null) {
+            throw new NoSuchAlgorithmException
+                (algorithm + " KeyGenerator not available");
+        }
+
+        // Android-removed: this debugging mechanism is not used in Android.
+        /*
+        if (!skipDebug && pdebug != null) {
+            pdebug.println("KeyGenerator." + algorithm + " algorithm from: " +
+                this.provider.getName());
+        }
+        */
+    }
+
+    /**
+     * Returns the algorithm name of this <code>KeyGenerator</code> object.
+     *
+     * <p>This is the same name that was specified in one of the
+     * <code>getInstance</code> calls that created this
+     * <code>KeyGenerator</code> object.
+     *
+     * @return the algorithm name of this <code>KeyGenerator</code> object.
+     */
+    public final String getAlgorithm() {
+        return this.algorithm;
+    }
+
+    /**
+     * Returns a <code>KeyGenerator</code> object that generates secret keys
+     * for the specified algorithm.
+     *
+     * <p> This method traverses the list of registered security Providers,
+     * starting with the most preferred Provider.
+     * A new KeyGenerator object encapsulating the
+     * KeyGeneratorSpi 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 requested key algorithm.
+     * See the KeyGenerator section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyGenerator">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard algorithm names.
+     *
+     * @return the new <code>KeyGenerator</code> object.
+     *
+     * @exception NullPointerException if the specified algorithm is null.
+     *
+     * @exception NoSuchAlgorithmException if no Provider supports a
+     *          KeyGeneratorSpi implementation for the
+     *          specified algorithm.
+     *
+     * @see java.security.Provider
+     */
+    public static final KeyGenerator getInstance(String algorithm)
+            throws NoSuchAlgorithmException {
+        return new KeyGenerator(algorithm);
+    }
+
+    /**
+     * Returns a <code>KeyGenerator</code> object that generates secret keys
+     * for the specified algorithm.
+     *
+     * <p> A new KeyGenerator object encapsulating the
+     * KeyGeneratorSpi 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 name of the requested key algorithm.
+     * See the KeyGenerator section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyGenerator">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard algorithm names.
+     *
+     * @param provider the name of the provider.
+     *
+     * @return the new <code>KeyGenerator</code> object.
+     *
+     * @exception NullPointerException if the specified algorithm is null.
+     *
+     * @exception NoSuchAlgorithmException if a KeyGeneratorSpi
+     *          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</code>
+     *          is null or empty.
+     *
+     * @see java.security.Provider
+     */
+    public static final KeyGenerator getInstance(String algorithm,
+            String provider) throws NoSuchAlgorithmException,
+            NoSuchProviderException {
+        // Android-added: Check for Bouncy Castle deprecation
+        Providers.checkBouncyCastleDeprecation(provider, "KeyGenerator", algorithm);
+        Instance instance = JceSecurity.getInstance("KeyGenerator",
+                KeyGeneratorSpi.class, algorithm, provider);
+        return new KeyGenerator((KeyGeneratorSpi)instance.impl,
+                instance.provider, algorithm);
+    }
+
+    /**
+     * Returns a <code>KeyGenerator</code> object that generates secret keys
+     * for the specified algorithm.
+     *
+     * <p> A new KeyGenerator object encapsulating the
+     * KeyGeneratorSpi 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 name of the requested key algorithm.
+     * See the KeyGenerator section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyGenerator">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard algorithm names.
+     *
+     * @param provider the provider.
+     *
+     * @return the new <code>KeyGenerator</code> object.
+     *
+     * @exception NullPointerException if the specified algorithm is null.
+     *
+     * @exception NoSuchAlgorithmException if a KeyGeneratorSpi
+     *          implementation for the specified algorithm is not available
+     *          from the specified Provider object.
+     *
+     * @exception IllegalArgumentException if the <code>provider</code>
+     *          is null.
+     *
+     * @see java.security.Provider
+     */
+    public static final KeyGenerator getInstance(String algorithm,
+            Provider provider) throws NoSuchAlgorithmException {
+        // Android-added: Check for Bouncy Castle deprecation
+        Providers.checkBouncyCastleDeprecation(provider, "KeyGenerator", algorithm);
+        Instance instance = JceSecurity.getInstance("KeyGenerator",
+                KeyGeneratorSpi.class, algorithm, provider);
+        return new KeyGenerator((KeyGeneratorSpi)instance.impl,
+                instance.provider, algorithm);
+    }
+
+    /**
+     * Returns the provider of this <code>KeyGenerator</code> object.
+     *
+     * @return the provider of this <code>KeyGenerator</code> object
+     */
+    public final Provider getProvider() {
+        synchronized (lock) {
+            disableFailover();
+            return provider;
+        }
+    }
+
+    /**
+     * 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 KeyGeneratorSpi nextSpi(KeyGeneratorSpi 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();
+                if (JceSecurity.canUseProvider(s.getProvider()) == false) {
+                    continue;
+                }
+                try {
+                    Object inst = s.newInstance(null);
+                    // ignore non-spis
+                    if (inst instanceof KeyGeneratorSpi == false) {
+                        continue;
+                    }
+                    KeyGeneratorSpi spi = (KeyGeneratorSpi)inst;
+                    if (reinit) {
+                        if (initType == I_SIZE) {
+                            spi.engineInit(initKeySize, initRandom);
+                        } else if (initType == I_PARAMS) {
+                            spi.engineInit(initParams, initRandom);
+                        } else if (initType == I_RANDOM) {
+                            spi.engineInit(initRandom);
+                        } else if (initType != I_NONE) {
+                            throw new AssertionError
+                                ("KeyGenerator 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;
+    }
+
+    /**
+     * Initializes this key generator.
+     *
+     * @param random the source of randomness for this generator
+     */
+    public final void init(SecureRandom random) {
+        if (serviceIterator == null) {
+            spi.engineInit(random);
+            return;
+        }
+        RuntimeException failure = null;
+        KeyGeneratorSpi mySpi = spi;
+        do {
+            try {
+                mySpi.engineInit(random);
+                initType = I_RANDOM;
+                initKeySize = 0;
+                initParams = null;
+                initRandom = random;
+                return;
+            } catch (RuntimeException e) {
+                if (failure == null) {
+                    failure = e;
+                }
+                mySpi = nextSpi(mySpi, false);
+            }
+        } while (mySpi != null);
+        throw failure;
+    }
+
+    /**
+     * Initializes this key generator with the specified parameter set.
+     *
+     * <p> If this key generator requires any random bytes, it will get them
+     * using the
+     * {@link java.security.SecureRandom}
+     * implementation of the highest-priority installed
+     * provider as the source of randomness.
+     * (If none of the installed providers supply an implementation of
+     * SecureRandom, a system-provided source of randomness will be used.)
+     *
+     * @param params the key generation parameters
+     *
+     * @exception InvalidAlgorithmParameterException if the given parameters
+     * are inappropriate for this key generator
+     */
+    public final void init(AlgorithmParameterSpec params)
+        throws InvalidAlgorithmParameterException
+    {
+        init(params, JceSecurity.RANDOM);
+    }
+
+    /**
+     * Initializes this key generator with the specified parameter
+     * set and a user-provided source of randomness.
+     *
+     * @param params the key generation parameters
+     * @param random the source of randomness for this key generator
+     *
+     * @exception InvalidAlgorithmParameterException if <code>params</code> is
+     * inappropriate for this key generator
+     */
+    public final void init(AlgorithmParameterSpec params, SecureRandom random)
+        throws InvalidAlgorithmParameterException
+    {
+        if (serviceIterator == null) {
+            spi.engineInit(params, random);
+            return;
+        }
+        Exception failure = null;
+        KeyGeneratorSpi mySpi = spi;
+        do {
+            try {
+                mySpi.engineInit(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 InvalidAlgorithmParameterException) {
+            throw (InvalidAlgorithmParameterException)failure;
+        }
+        if (failure instanceof RuntimeException) {
+            throw (RuntimeException)failure;
+        }
+        throw new InvalidAlgorithmParameterException("init() failed", failure);
+    }
+
+    /**
+     * Initializes this key generator for a certain keysize.
+     *
+     * <p> If this key generator requires any random bytes, it will get them
+     * using the
+     * {@link java.security.SecureRandom}
+     * implementation of the highest-priority installed
+     * provider as the source of randomness.
+     * (If none of the installed providers supply an implementation of
+     * SecureRandom, a system-provided source of randomness will be used.)
+     *
+     * @param keysize the keysize. This is an algorithm-specific metric,
+     * specified in number of bits.
+     *
+     * @exception InvalidParameterException if the keysize is wrong or not
+     * supported.
+     */
+    public final void init(int keysize) {
+        init(keysize, JceSecurity.RANDOM);
+    }
+
+    /**
+     * Initializes this key generator for a certain keysize, using a
+     * user-provided source of randomness.
+     *
+     * @param keysize the keysize. This is an algorithm-specific metric,
+     * specified in number of bits.
+     * @param random the source of randomness for this key generator
+     *
+     * @exception InvalidParameterException if the keysize is wrong or not
+     * supported.
+     */
+    public final void init(int keysize, SecureRandom random) {
+        if (serviceIterator == null) {
+            spi.engineInit(keysize, random);
+            return;
+        }
+        RuntimeException failure = null;
+        KeyGeneratorSpi mySpi = spi;
+        do {
+            try {
+                mySpi.engineInit(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;
+    }
+
+    /**
+     * Generates a secret key.
+     *
+     * @return the new key
+     */
+    public final SecretKey generateKey() {
+        if (serviceIterator == null) {
+            return spi.engineGenerateKey();
+        }
+        RuntimeException failure = null;
+        KeyGeneratorSpi mySpi = spi;
+        do {
+            try {
+                return mySpi.engineGenerateKey();
+            } catch (RuntimeException e) {
+                if (failure == null) {
+                    failure = e;
+                }
+                mySpi = nextSpi(mySpi, true);
+            }
+        } while (mySpi != null);
+        throw failure;
+   }
+}
diff --git a/javax/crypto/KeyGeneratorSpi.java b/javax/crypto/KeyGeneratorSpi.java
new file mode 100644
index 0000000..f271e41
--- /dev/null
+++ b/javax/crypto/KeyGeneratorSpi.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 1997, 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 javax.crypto;
+
+import java.security.*;
+import java.security.spec.*;
+
+/**
+ * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>)
+ * for the <code>KeyGenerator</code> 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 generator for a particular algorithm.
+ *
+ * @author Jan Luehe
+ *
+ * @see SecretKey
+ * @since 1.4
+ */
+
+public abstract class KeyGeneratorSpi {
+
+    /**
+     * Initializes the key generator.
+     *
+     * @param random the source of randomness for this generator
+     */
+    protected abstract void engineInit(SecureRandom random);
+
+    /**
+     * Initializes the key generator with the specified parameter
+     * set and a user-provided source of randomness.
+     *
+     * @param params the key generation parameters
+     * @param random the source of randomness for this key generator
+     *
+     * @exception InvalidAlgorithmParameterException if <code>params</code> is
+     * inappropriate for this key generator
+     */
+    protected abstract void engineInit(AlgorithmParameterSpec params,
+                                       SecureRandom random)
+        throws InvalidAlgorithmParameterException;
+
+    /**
+     * Initializes this key generator for a certain keysize, using the given
+     * source of randomness.
+     *
+     * @param keysize the keysize. This is an algorithm-specific metric,
+     * specified in number of bits.
+     * @param random the source of randomness for this key generator
+     *
+     * @exception InvalidParameterException if the keysize is wrong or not
+     * supported.
+     */
+    protected abstract void engineInit(int keysize, SecureRandom random);
+
+    /**
+     * Generates a secret key.
+     *
+     * @return the new key
+     */
+    protected abstract SecretKey engineGenerateKey();
+}
diff --git a/javax/crypto/Mac.annotated.java b/javax/crypto/Mac.annotated.java
new file mode 100644
index 0000000..a7e1995
--- /dev/null
+++ b/javax/crypto/Mac.annotated.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1998, 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 javax.crypto;
+
+import java.util.*;
+import java.security.*;
+import sun.security.jca.*;
+import java.nio.ByteBuffer;
+import java.security.spec.AlgorithmParameterSpec;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class Mac implements java.lang.Cloneable {
+
+protected Mac(javax.crypto.MacSpi macSpi, java.security.Provider provider, java.lang.String algorithm) { throw new RuntimeException("Stub!"); }
+
+public final java.lang.String getAlgorithm() { throw new RuntimeException("Stub!"); }
+
+public static final javax.crypto.Mac getInstance(java.lang.String algorithm) throws java.security.NoSuchAlgorithmException { throw new RuntimeException("Stub!"); }
+
+public static final javax.crypto.Mac getInstance(java.lang.String algorithm, java.lang.String provider) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException { throw new RuntimeException("Stub!"); }
+
+public static final javax.crypto.Mac 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 int getMacLength() { throw new RuntimeException("Stub!"); }
+
+public final void init(java.security.Key key) throws java.security.InvalidKeyException { throw new RuntimeException("Stub!"); }
+
+public final void init(java.security.Key key, java.security.spec.AlgorithmParameterSpec params) throws java.security.InvalidAlgorithmParameterException, java.security.InvalidKeyException { throw new RuntimeException("Stub!"); }
+
+public final void update(byte input) throws java.lang.IllegalStateException { throw new RuntimeException("Stub!"); }
+
+public final void update(byte[] input) throws java.lang.IllegalStateException { throw new RuntimeException("Stub!"); }
+
+public final void update(byte[] input, int offset, int len) throws java.lang.IllegalStateException { throw new RuntimeException("Stub!"); }
+
+public final void update(java.nio.ByteBuffer input) { throw new RuntimeException("Stub!"); }
+
+public final byte[] doFinal() throws java.lang.IllegalStateException { throw new RuntimeException("Stub!"); }
+
+public final void doFinal(byte[] output, int outOffset) throws java.lang.IllegalStateException, javax.crypto.ShortBufferException { throw new RuntimeException("Stub!"); }
+
+public final byte[] doFinal(byte[] input) throws java.lang.IllegalStateException { throw new RuntimeException("Stub!"); }
+
+public final void reset() { throw new RuntimeException("Stub!"); }
+
+public final java.lang.Object clone() throws java.lang.CloneNotSupportedException { throw new RuntimeException("Stub!"); }
+
[email protected]
+public javax.crypto.MacSpi getCurrentSpi() { throw new RuntimeException("Stub!"); }
+}
+
diff --git a/javax/crypto/Mac.java b/javax/crypto/Mac.java
new file mode 100644
index 0000000..f70a697
--- /dev/null
+++ b/javax/crypto/Mac.java
@@ -0,0 +1,790 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1998, 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 javax.crypto;
+
+import java.util.*;
+
+import java.security.*;
+import java.security.Provider.Service;
+import java.security.spec.AlgorithmParameterSpec;
+
+import java.nio.ByteBuffer;
+
+import sun.security.jca.*;
+import sun.security.jca.GetInstance.Instance;
+
+/**
+ * This class provides the functionality of a "Message Authentication Code"
+ * (MAC) algorithm.
+ *
+ * <p> A MAC provides a way to check
+ * the integrity of information transmitted over or stored in an unreliable
+ * medium, based on a secret key. Typically, message
+ * authentication codes are used between two parties that share a secret
+ * key in order to validate information transmitted between these
+ * parties.
+ *
+ * <p> A MAC mechanism that is based on cryptographic hash functions is
+ * referred to as HMAC. HMAC can be used with any cryptographic hash function,
+ * e.g., MD5 or SHA-1, in combination with a secret shared key. HMAC is
+ * specified in RFC 2104.
+ *
+ * <p> Android provides the following <code>Mac</code> algorithms:
+ * <table>
+ *   <thead>
+ *     <tr>
+ *       <th>Algorithm</th>
+ *       <th>Supported API Levels</th>
+ *     </tr>
+ *   </thead>
+ *   <tbody>
+ *     <tr class="deprecated">
+ *       <td>DESMAC</td>
+ *       <td>1-8</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>DESMAC/CFB8</td>
+ *       <td>1-8</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>DESedeMAC</td>
+ *       <td>1-8</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>DESedeMAC/CFB8</td>
+ *       <td>1-8</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>DESedeMAC64</td>
+ *       <td>1-8</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>DESwithISO9797</td>
+ *       <td>1-8</td>
+ *     </tr>
+ *     <tr>
+ *       <td>HmacMD5</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>HmacSHA1</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>HmacSHA224</td>
+ *       <td>1-8,22+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>HmacSHA256</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>HmacSHA384</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>HmacSHA512</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>ISO9797ALG3MAC</td>
+ *       <td>1-8</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PBEwithHmacSHA</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PBEwithHmacSHA1</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PBEwithHmacSHA224</td>
+ *       <td>26+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PBEwithHmacSHA256</td>
+ *       <td>26+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PBEwithHmacSHA384</td>
+ *       <td>26+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PBEwithHmacSHA512</td>
+ *       <td>26+</td>
+ *     </tr>
+ *   </tbody>
+ * </table>
+ *
+ * These algorithms are described in the
+ * <a href="{@docRoot}/../technotes/guides/security/StandardNames.html#Mac">
+ * Mac section</a> of the
+ * Java Cryptography Architecture Standard Algorithm Name Documentation.
+ *
+ * @author Jan Luehe
+ *
+ * @since 1.4
+ */
+
+public class Mac implements Cloneable {
+
+    // Android-removed: this debugging mechanism is not used in Android.
+    /*
+    private static final Debug debug =
+                        Debug.getInstance("jca", "Mac");
+
+    private static final Debug pdebug =
+                        Debug.getInstance("provider", "Provider");
+    private static final boolean skipDebug =
+        Debug.isOn("engine=") && !Debug.isOn("mac");
+    */
+
+    // The provider
+    private Provider provider;
+
+    // The provider implementation (delegate)
+    private MacSpi spi;
+
+    // The name of the MAC algorithm.
+    private final String algorithm;
+
+    // Has this object been initialized?
+    private boolean initialized = false;
+
+    // BEGIN Android-removed: Redo the provider selection logic to allow reselecting provider.
+    // When only the algorithm is specified, we want to allow the Mac 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.
+
+    private final Object lock;
+
+    /**
+     * Creates a MAC object.
+     *
+     * @param macSpi the delegate
+     * @param provider the provider
+     * @param algorithm the algorithm
+     */
+    protected Mac(MacSpi macSpi, Provider provider, String algorithm) {
+        this.spi = macSpi;
+        this.provider = provider;
+        this.algorithm = algorithm;
+        lock = null;
+    }
+
+    // Android-changed: Remove Service and Iterator from constructor args.
+    private Mac(String algorithm) {
+        this.algorithm = algorithm;
+        lock = new Object();
+    }
+
+    /**
+     * Returns the algorithm name of this <code>Mac</code> object.
+     *
+     * <p>This is the same name that was specified in one of the
+     * <code>getInstance</code> calls that created this
+     * <code>Mac</code> object.
+     *
+     * @return the algorithm name of this <code>Mac</code> object.
+     */
+    public final String getAlgorithm() {
+        return this.algorithm;
+    }
+
+    /**
+     * Returns a <code>Mac</code> object that implements the
+     * specified MAC algorithm.
+     *
+     * <p> This method traverses the list of registered security Providers,
+     * starting with the most preferred Provider.
+     * A new Mac object encapsulating the
+     * MacSpi 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 requested MAC algorithm.
+     * See the Mac section in the <a href=
+     *   "{@docRoot}/../technotes/guides/security/StandardNames.html#Mac">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard algorithm names.
+     *
+     * @return the new <code>Mac</code> object.
+     *
+     * @exception NoSuchAlgorithmException if no Provider supports a
+     *          MacSpi implementation for the
+     *          specified algorithm.
+     *
+     * @see java.security.Provider
+     */
+    public static final Mac getInstance(String algorithm)
+            throws NoSuchAlgorithmException {
+        List<Service> services = GetInstance.getServices("Mac", algorithm);
+        // make sure there is at least one service from a signed provider
+        Iterator<Service> t = services.iterator();
+        while (t.hasNext()) {
+            Service s = t.next();
+            if (JceSecurity.canUseProvider(s.getProvider()) == false) {
+                continue;
+            }
+            // Android-changed: Remove Service and Iterator from constructor args.
+            // return new Mac(s, t, algorithm);
+            return new Mac(algorithm);
+        }
+        throw new NoSuchAlgorithmException
+                                ("Algorithm " + algorithm + " not available");
+    }
+
+    /**
+     * Returns a <code>Mac</code> object that implements the
+     * specified MAC algorithm.
+     *
+     * <p> A new Mac object encapsulating the
+     * MacSpi 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 name of the requested MAC algorithm.
+     * See the Mac section in the <a href=
+     *   "{@docRoot}/../technotes/guides/security/StandardNames.html#Mac">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard algorithm names.
+     *
+     * @param provider the name of the provider.
+     *
+     * @return the new <code>Mac</code> object.
+     *
+     * @exception NoSuchAlgorithmException if a MacSpi
+     *          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</code>
+     *          is null or empty.
+     *
+     * @see java.security.Provider
+     */
+    public static final Mac getInstance(String algorithm, String provider)
+            throws NoSuchAlgorithmException, NoSuchProviderException {
+        // Android-added: Check for Bouncy Castle deprecation
+        Providers.checkBouncyCastleDeprecation(provider, "Mac", algorithm);
+        Instance instance = JceSecurity.getInstance
+                ("Mac", MacSpi.class, algorithm, provider);
+        return new Mac((MacSpi)instance.impl, instance.provider, algorithm);
+    }
+
+    /**
+     * Returns a <code>Mac</code> object that implements the
+     * specified MAC algorithm.
+     *
+     * <p> A new Mac object encapsulating the
+     * MacSpi 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 name of the requested MAC algorithm.
+     * See the Mac section in the <a href=
+     *   "{@docRoot}/../technotes/guides/security/StandardNames.html#Mac">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard algorithm names.
+     *
+     * @param provider the provider.
+     *
+     * @return the new <code>Mac</code> object.
+     *
+     * @exception NoSuchAlgorithmException if a MacSpi
+     *          implementation for the specified algorithm is not available
+     *          from the specified Provider object.
+     *
+     * @exception IllegalArgumentException if the <code>provider</code>
+     *          is null.
+     *
+     * @see java.security.Provider
+     */
+    public static final Mac getInstance(String algorithm, Provider provider)
+            throws NoSuchAlgorithmException {
+        // Android-added: Check for Bouncy Castle deprecation
+        Providers.checkBouncyCastleDeprecation(provider, "Mac", algorithm);
+        Instance instance = JceSecurity.getInstance
+                ("Mac", MacSpi.class, algorithm, provider);
+        return new Mac((MacSpi)instance.impl, instance.provider, algorithm);
+    }
+
+    // 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 init()
+     * is not the first method called.
+     */
+    void chooseFirstProvider() {
+        // Android-changed: Check if lock is null rather than removed serviceIterator field.
+        // if ((spi != null) || (serviceIterator == null)) {
+        if (spi != null || lock == null) {
+            return;
+        }
+        synchronized (lock) {
+            if (spi != null) {
+                return;
+            }
+            // Android-removed: this debugging mechanism is not used in Android.
+            /*
+            if (debug != null) {
+                int w = --warnCount;
+                if (w >= 0) {
+                    debug.println("Mac.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();
+                }
+            }
+            */
+            Exception lastException = null;
+            // Android-changed: Provider selection; loop over a new list each time.
+            for (Service s : GetInstance.getServices("Mac", algorithm)) {
+                if (JceSecurity.canUseProvider(s.getProvider()) == false) {
+                    continue;
+                }
+                try {
+                    Object obj = s.newInstance(null);
+                    if (obj instanceof MacSpi == false) {
+                        continue;
+                    }
+                    spi = (MacSpi)obj;
+                    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 MacSpi instance");
+            if (lastException != null) {
+                e.initCause(lastException);
+            }
+            throw e;
+        }
+    }
+
+    private void chooseProvider(Key key, AlgorithmParameterSpec params)
+            throws InvalidKeyException, InvalidAlgorithmParameterException {
+        synchronized (lock) {
+            // Android-changed: Use the currently-selected provider only if no key was provided.
+            // if (spi != null) {
+            if (spi != null && (key == null || lock == null)) {
+                spi.engineInit(key, params);
+                return;
+            }
+            Exception lastException = null;
+            // Android-changed: Provider selection; loop over a new list each time.
+            for (Service s : GetInstance.getServices("Mac", algorithm)) {
+                // if provider says it does not support this key, ignore it
+                if (s.supportsParameter(key) == false) {
+                    continue;
+                }
+                if (JceSecurity.canUseProvider(s.getProvider()) == false) {
+                    continue;
+                }
+                try {
+                    MacSpi spi = (MacSpi)s.newInstance(null);
+                    spi.engineInit(key, params);
+                    provider = s.getProvider();
+                    this.spi = 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;
+                    }
+                }
+            }
+            // no working provider found, fail
+            if (lastException instanceof InvalidKeyException) {
+                throw (InvalidKeyException)lastException;
+            }
+            if (lastException instanceof InvalidAlgorithmParameterException) {
+                throw (InvalidAlgorithmParameterException)lastException;
+            }
+            if (lastException instanceof RuntimeException) {
+                throw (RuntimeException)lastException;
+            }
+            String kName = (key != null) ? key.getClass().getName() : "(null)";
+            throw new InvalidKeyException
+                ("No installed provider supports this key: "
+                + kName, lastException);
+        }
+    }
+
+    /**
+     * Returns the provider of this <code>Mac</code> object.
+     *
+     * @return the provider of this <code>Mac</code> object.
+     */
+    public final Provider getProvider() {
+        chooseFirstProvider();
+        return this.provider;
+    }
+
+    /**
+     * Returns the length of the MAC in bytes.
+     *
+     * @return the MAC length in bytes.
+     */
+    public final int getMacLength() {
+        chooseFirstProvider();
+        return spi.engineGetMacLength();
+    }
+
+    /**
+     * Initializes this <code>Mac</code> object with the given key.
+     *
+     * @param key the key.
+     *
+     * @exception InvalidKeyException if the given key is inappropriate for
+     * initializing this MAC.
+     */
+    public final void init(Key key) throws InvalidKeyException {
+        try {
+            // Android-changed: Use the currently-selected provider only if no key was provided.
+            // if (spi != null) {
+            if (spi != null && (key == null || lock == null)) {
+                spi.engineInit(key, null);
+            } else {
+                chooseProvider(key, null);
+            }
+        } catch (InvalidAlgorithmParameterException e) {
+            throw new InvalidKeyException("init() failed", e);
+        }
+        initialized = true;
+
+        // Android-removed: this debugging mechanism is not used in Android.
+        /*
+        if (!skipDebug && pdebug != null) {
+            pdebug.println("Mac." + algorithm + " algorithm from: " +
+                this.provider.getName());
+        }
+        */
+    }
+
+    /**
+     * Initializes this <code>Mac</code> object with the given key and
+     * algorithm parameters.
+     *
+     * @param key the key.
+     * @param params the algorithm parameters.
+     *
+     * @exception InvalidKeyException if the given key is inappropriate for
+     * initializing this MAC.
+     * @exception InvalidAlgorithmParameterException if the given algorithm
+     * parameters are inappropriate for this MAC.
+     */
+    public final void init(Key key, AlgorithmParameterSpec params)
+            throws InvalidKeyException, InvalidAlgorithmParameterException {
+        // Android-changed: Use the currently-selected provider only if no key was provided.
+        // if (spi != null) {
+        if (spi != null && (key == null || lock == null)) {
+            spi.engineInit(key, params);
+        } else {
+            chooseProvider(key, params);
+        }
+        initialized = true;
+
+        // Android-removed: this debugging mechanism is not used in Android.
+        /*
+        if (!skipDebug && pdebug != null) {
+            pdebug.println("Mac." + algorithm + " algorithm from: " +
+                this.provider.getName());
+        }
+        */
+    }
+
+    /**
+     * Processes the given byte.
+     *
+     * @param input the input byte to be processed.
+     *
+     * @exception IllegalStateException if this <code>Mac</code> has not been
+     * initialized.
+     */
+    public final void update(byte input) throws IllegalStateException {
+        chooseFirstProvider();
+        if (initialized == false) {
+            throw new IllegalStateException("MAC not initialized");
+        }
+        spi.engineUpdate(input);
+    }
+
+    /**
+     * Processes the given array of bytes.
+     *
+     * @param input the array of bytes to be processed.
+     *
+     * @exception IllegalStateException if this <code>Mac</code> has not been
+     * initialized.
+     */
+    public final void update(byte[] input) throws IllegalStateException {
+        chooseFirstProvider();
+        if (initialized == false) {
+            throw new IllegalStateException("MAC not initialized");
+        }
+        if (input != null) {
+            spi.engineUpdate(input, 0, input.length);
+        }
+    }
+
+    /**
+     * Processes the first <code>len</code> bytes in <code>input</code>,
+     * starting at <code>offset</code> inclusive.
+     *
+     * @param input the input buffer.
+     * @param offset the offset in <code>input</code> where the input starts.
+     * @param len the number of bytes to process.
+     *
+     * @exception IllegalStateException if this <code>Mac</code> has not been
+     * initialized.
+     */
+    public final void update(byte[] input, int offset, int len)
+            throws IllegalStateException {
+        chooseFirstProvider();
+        if (initialized == false) {
+            throw new IllegalStateException("MAC not initialized");
+        }
+
+        if (input != null) {
+            if ((offset < 0) || (len > (input.length - offset)) || (len < 0))
+                throw new IllegalArgumentException("Bad arguments");
+            spi.engineUpdate(input, offset, len);
+        }
+    }
+
+    /**
+     * Processes <code>input.remaining()</code> bytes in the ByteBuffer
+     * <code>input</code>, starting at <code>input.position()</code>.
+     * Upon return, the buffer's position will be equal to its limit;
+     * its limit will not have changed.
+     *
+     * @param input the ByteBuffer
+     *
+     * @exception IllegalStateException if this <code>Mac</code> has not been
+     * initialized.
+     * @since 1.5
+     */
+    public final void update(ByteBuffer input) {
+        chooseFirstProvider();
+        if (initialized == false) {
+            throw new IllegalStateException("MAC not initialized");
+        }
+        if (input == null) {
+            throw new IllegalArgumentException("Buffer must not be null");
+        }
+        spi.engineUpdate(input);
+    }
+
+    /**
+     * Finishes the MAC operation.
+     *
+     * <p>A call to this method resets this <code>Mac</code> object to the
+     * state it was in when previously initialized via a call to
+     * <code>init(Key)</code> or
+     * <code>init(Key, AlgorithmParameterSpec)</code>.
+     * That is, the object is reset and available to generate another MAC from
+     * the same key, if desired, via new calls to <code>update</code> and
+     * <code>doFinal</code>.
+     * (In order to reuse this <code>Mac</code> object with a different key,
+     * it must be reinitialized via a call to <code>init(Key)</code> or
+     * <code>init(Key, AlgorithmParameterSpec)</code>.
+     *
+     * @return the MAC result.
+     *
+     * @exception IllegalStateException if this <code>Mac</code> has not been
+     * initialized.
+     */
+    public final byte[] doFinal() throws IllegalStateException {
+        chooseFirstProvider();
+        if (initialized == false) {
+            throw new IllegalStateException("MAC not initialized");
+        }
+        byte[] mac = spi.engineDoFinal();
+        spi.engineReset();
+        return mac;
+    }
+
+    /**
+     * Finishes the MAC operation.
+     *
+     * <p>A call to this method resets this <code>Mac</code> object to the
+     * state it was in when previously initialized via a call to
+     * <code>init(Key)</code> or
+     * <code>init(Key, AlgorithmParameterSpec)</code>.
+     * That is, the object is reset and available to generate another MAC from
+     * the same key, if desired, via new calls to <code>update</code> and
+     * <code>doFinal</code>.
+     * (In order to reuse this <code>Mac</code> object with a different key,
+     * it must be reinitialized via a call to <code>init(Key)</code> or
+     * <code>init(Key, AlgorithmParameterSpec)</code>.
+     *
+     * <p>The MAC result is stored in <code>output</code>, starting at
+     * <code>outOffset</code> inclusive.
+     *
+     * @param output the buffer where the MAC result is stored
+     * @param outOffset the offset in <code>output</code> where the MAC is
+     * stored
+     *
+     * @exception ShortBufferException if the given output buffer is too small
+     * to hold the result
+     * @exception IllegalStateException if this <code>Mac</code> has not been
+     * initialized.
+     */
+    public final void doFinal(byte[] output, int outOffset)
+        throws ShortBufferException, IllegalStateException
+    {
+        chooseFirstProvider();
+        if (initialized == false) {
+            throw new IllegalStateException("MAC not initialized");
+        }
+        int macLen = getMacLength();
+        if (output == null || output.length-outOffset < macLen) {
+            throw new ShortBufferException
+                ("Cannot store MAC in output buffer");
+        }
+        byte[] mac = doFinal();
+        System.arraycopy(mac, 0, output, outOffset, macLen);
+        return;
+    }
+
+    /**
+     * Processes the given array of bytes and finishes the MAC operation.
+     *
+     * <p>A call to this method resets this <code>Mac</code> object to the
+     * state it was in when previously initialized via a call to
+     * <code>init(Key)</code> or
+     * <code>init(Key, AlgorithmParameterSpec)</code>.
+     * That is, the object is reset and available to generate another MAC from
+     * the same key, if desired, via new calls to <code>update</code> and
+     * <code>doFinal</code>.
+     * (In order to reuse this <code>Mac</code> object with a different key,
+     * it must be reinitialized via a call to <code>init(Key)</code> or
+     * <code>init(Key, AlgorithmParameterSpec)</code>.
+     *
+     * @param input data in bytes
+     * @return the MAC result.
+     *
+     * @exception IllegalStateException if this <code>Mac</code> has not been
+     * initialized.
+     */
+    public final byte[] doFinal(byte[] input) throws IllegalStateException
+    {
+        chooseFirstProvider();
+        if (initialized == false) {
+            throw new IllegalStateException("MAC not initialized");
+        }
+        update(input);
+        return doFinal();
+    }
+
+    /**
+     * Resets this <code>Mac</code> object.
+     *
+     * <p>A call to this method resets this <code>Mac</code> object to the
+     * state it was in when previously initialized via a call to
+     * <code>init(Key)</code> or
+     * <code>init(Key, AlgorithmParameterSpec)</code>.
+     * That is, the object is reset and available to generate another MAC from
+     * the same key, if desired, via new calls to <code>update</code> and
+     * <code>doFinal</code>.
+     * (In order to reuse this <code>Mac</code> object with a different key,
+     * it must be reinitialized via a call to <code>init(Key)</code> or
+     * <code>init(Key, AlgorithmParameterSpec)</code>.
+     */
+    public final void reset() {
+        chooseFirstProvider();
+        spi.engineReset();
+    }
+
+    /**
+     * Returns a clone if the provider implementation is cloneable.
+     *
+     * @return a clone if the provider implementation is cloneable.
+     *
+     * @exception CloneNotSupportedException if this is called on a
+     * delegate that does not support <code>Cloneable</code>.
+     */
+    public final Object clone() throws CloneNotSupportedException {
+        chooseFirstProvider();
+        Mac that = (Mac)super.clone();
+        that.spi = (MacSpi)this.spi.clone();
+        return that;
+    }
+
+    // BEGIN Android-added: Allow access to the current SPI for testing purposes.
+    /**
+     * Returns the {@code MacSpi} backing this {@code Mac} or {@code null} if no {@code MacSpi} is
+     * backing this {@code Mac}.
+     *
+     * @hide
+     */
+    public MacSpi getCurrentSpi() {
+        return spi;
+    }
+    // END Android-added: Allow access to the current SPI for testing purposes.
+}
diff --git a/javax/crypto/MacSpi.java b/javax/crypto/MacSpi.java
new file mode 100644
index 0000000..63aef78
--- /dev/null
+++ b/javax/crypto/MacSpi.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 1998, 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 javax.crypto;
+
+import java.security.*;
+import java.security.spec.*;
+
+import java.nio.ByteBuffer;
+
+/**
+ * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>)
+ * for the <code>Mac</code> class.
+ * All the abstract methods in this class must be implemented by each
+ * cryptographic service provider who wishes to supply the implementation
+ * of a particular MAC algorithm.
+ *
+ * <p> Implementations are free to implement the Cloneable interface.
+ *
+ * @author Jan Luehe
+ *
+ * @since 1.4
+ */
+
+public abstract class MacSpi {
+
+    /**
+     * Returns the length of the MAC in bytes.
+     *
+     * @return the MAC length in bytes.
+     */
+    protected abstract int engineGetMacLength();
+
+    /**
+     * Initializes the MAC with the given (secret) key and algorithm
+     * parameters.
+     *
+     * @param key the (secret) key.
+     * @param params the algorithm parameters.
+     *
+     * @exception InvalidKeyException if the given key is inappropriate for
+     * initializing this MAC.
+     * @exception InvalidAlgorithmParameterException if the given algorithm
+     * parameters are inappropriate for this MAC.
+     */
+    protected abstract void engineInit(Key key,
+                                       AlgorithmParameterSpec params)
+        throws InvalidKeyException, InvalidAlgorithmParameterException ;
+
+    /**
+     * Processes the given byte.
+     *
+     * @param input the input byte to be processed.
+     */
+    protected abstract void engineUpdate(byte input);
+
+    /**
+     * Processes the first <code>len</code> bytes in <code>input</code>,
+     * starting at <code>offset</code> inclusive.
+     *
+     * @param input the input buffer.
+     * @param offset the offset in <code>input</code> where the input starts.
+     * @param len the number of bytes to process.
+     */
+    protected abstract void engineUpdate(byte[] input, int offset, int len);
+
+    /**
+     * Processes <code>input.remaining()</code> bytes in the ByteBuffer
+     * <code>input</code>, starting at <code>input.position()</code>.
+     * Upon return, the buffer's position will be equal to its limit;
+     * its limit will not have changed.
+     *
+     * <p>Subclasses should consider overriding this method if they can
+     * process ByteBuffers more efficiently than byte arrays.
+     *
+     * @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();
+            byte[] b = new byte[CipherSpi.getTempArraySize(len)];
+            while (len > 0) {
+                int chunk = Math.min(len, b.length);
+                input.get(b, 0, chunk);
+                engineUpdate(b, 0, chunk);
+                len -= chunk;
+            }
+        }
+    }
+
+    /**
+     * Completes the MAC computation and resets the MAC for further use,
+     * maintaining the secret key that the MAC was initialized with.
+     *
+     * @return the MAC result.
+     */
+    protected abstract byte[] engineDoFinal();
+
+    /**
+     * Resets the MAC for further use, maintaining the secret key that the
+     * MAC was initialized with.
+     */
+    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</code>.
+     */
+    public Object clone() throws CloneNotSupportedException {
+        if (this instanceof Cloneable) {
+            return super.clone();
+        } else {
+            throw new CloneNotSupportedException();
+        }
+    }
+}
diff --git a/javax/crypto/NoSuchPaddingException.java b/javax/crypto/NoSuchPaddingException.java
new file mode 100644
index 0000000..054157f
--- /dev/null
+++ b/javax/crypto/NoSuchPaddingException.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1997, 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 javax.crypto;
+
+import java.security.GeneralSecurityException;
+
+/**
+ * This exception is thrown when a particular padding mechanism is
+ * requested but is not available in the environment.
+ *
+ * @author Jan Luehe
+ *
+ * @since 1.4
+ */
+
+public class NoSuchPaddingException extends GeneralSecurityException {
+
+    private static final long serialVersionUID = -4572885201200175466L;
+
+    /**
+     * Constructs a NoSuchPaddingException with no detail
+     * message. A detail message is a String that describes this
+     * particular exception.
+     */
+    public NoSuchPaddingException() {
+        super();
+    }
+
+    /**
+     * Constructs a NoSuchPaddingException with the specified
+     * detail message.
+     *
+     * @param msg the detail message.
+     */
+    public NoSuchPaddingException(String msg) {
+        super(msg);
+    }
+}
diff --git a/javax/crypto/NullCipher.java b/javax/crypto/NullCipher.java
new file mode 100644
index 0000000..dda9eb4
--- /dev/null
+++ b/javax/crypto/NullCipher.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 javax.crypto;
+
+/**
+ * The NullCipher class is a class that provides an
+ * "identity cipher" -- one that does not transform the plain text.  As
+ * a consequence, the ciphertext is identical to the plaintext.  All
+ * initialization methods do nothing, while the blocksize is set to 1
+ * byte.
+ *
+ * @author  Li Gong
+ * @since 1.4
+ */
+
+public class NullCipher extends Cipher {
+
+    /**
+     * Creates a NullCipher object.
+     */
+    public NullCipher() {
+        super(new NullCipherSpi(), null, null);
+    }
+}
diff --git a/javax/crypto/NullCipherSpi.java b/javax/crypto/NullCipherSpi.java
new file mode 100644
index 0000000..7419f87
--- /dev/null
+++ b/javax/crypto/NullCipherSpi.java
@@ -0,0 +1,113 @@
+/*
+ * 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 javax.crypto;
+
+import java.security.*;
+import java.security.spec.*;
+
+/**
+ * This class provides a delegate for the identity cipher - one that does not
+ * transform the plain text.
+ *
+ * @author  Li Gong
+ * @see NullCipher
+ *
+ * @since 1.4
+ */
+
+final class NullCipherSpi extends CipherSpi {
+
+    /*
+     * Do not let anybody instantiate this directly (protected).
+     */
+    protected NullCipherSpi() {}
+
+    public void engineSetMode(String mode) {}
+
+    public void engineSetPadding(String padding) {}
+
+    protected int engineGetBlockSize() {
+        return 1;
+    }
+
+    protected int engineGetOutputSize(int inputLen) {
+        return inputLen;
+    }
+
+    protected byte[] engineGetIV() {
+        byte[] x = new byte[8];
+        return x;
+    }
+
+    protected AlgorithmParameters engineGetParameters() {
+        return null;
+    }
+
+    protected void engineInit(int mode, Key key, SecureRandom random) {}
+
+    protected void engineInit(int mode, Key key,
+                              AlgorithmParameterSpec params,
+                              SecureRandom random) {}
+
+    protected void engineInit(int mode, Key key,
+                              AlgorithmParameters params,
+                              SecureRandom random) {}
+
+    protected byte[] engineUpdate(byte[] input, int inputOffset,
+                                  int inputLen) {
+        if (input == null) return null;
+        byte[] x = new byte[inputLen];
+        System.arraycopy(input, inputOffset, x, 0, inputLen);
+        return x;
+    }
+
+    protected int engineUpdate(byte[] input, int inputOffset,
+                               int inputLen, byte[] output,
+                               int outputOffset) {
+        if (input == null) return 0;
+        System.arraycopy(input, inputOffset, output, outputOffset, inputLen);
+        return inputLen;
+    }
+
+    protected byte[] engineDoFinal(byte[] input, int inputOffset,
+                                   int inputLen)
+    {
+        return engineUpdate(input, inputOffset, inputLen);
+    }
+
+    protected int engineDoFinal(byte[] input, int inputOffset,
+                                int inputLen, byte[] output,
+                                int outputOffset)
+    {
+        return engineUpdate(input, inputOffset, inputLen,
+                            output, outputOffset);
+    }
+
+    protected int engineGetKeySize(Key key)
+    {
+        return 0;
+    }
+}
diff --git a/javax/crypto/SealedObject.java b/javax/crypto/SealedObject.java
new file mode 100644
index 0000000..9cee4d0
--- /dev/null
+++ b/javax/crypto/SealedObject.java
@@ -0,0 +1,493 @@
+/*
+ * 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 javax.crypto;
+
+import java.io.*;
+import java.security.AlgorithmParameters;
+import java.security.Key;
+import java.security.InvalidKeyException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+
+/**
+ * This class enables a programmer to create an object and protect its
+ * confidentiality with a cryptographic algorithm.
+ *
+ * <p> Given any Serializable object, one can create a SealedObject
+ * that encapsulates the original object, in serialized
+ * format (i.e., a "deep copy"), and seals (encrypts) its serialized contents,
+ * using a cryptographic algorithm such as DES, to protect its
+ * confidentiality.  The encrypted content can later be decrypted (with
+ * the corresponding algorithm using the correct decryption key) and
+ * de-serialized, yielding the original object.
+ *
+ * <p> Note that the Cipher object must be fully initialized with the
+ * correct algorithm, key, padding scheme, etc., before being applied
+ * to a SealedObject.
+ *
+ * <p> The original object that was sealed can be recovered in two different
+ * ways:
+ *
+ * <ul>
+ *
+ * <li>by using the {@link #getObject(javax.crypto.Cipher) getObject}
+ * method that takes a <code>Cipher</code> object.
+ *
+ * <p> This method requires a fully initialized <code>Cipher</code> object,
+ * initialized with the
+ * exact same algorithm, key, padding scheme, etc., that were used to seal the
+ * object.
+ *
+ * <p> This approach has the advantage that the party who unseals the
+ * sealed object does not require knowledge of the decryption key. For example,
+ * after one party has initialized the cipher object with the required
+ * decryption key, it could hand over the cipher object to
+ * another party who then unseals the sealed object.
+ *
+ * <li>by using one of the
+ * {@link #getObject(java.security.Key) getObject} methods
+ * that take a <code>Key</code> object.
+ *
+ * <p> In this approach, the <code>getObject</code> method creates a cipher
+ * object for the appropriate decryption algorithm and initializes it with the
+ * given decryption key and the algorithm parameters (if any) that were stored
+ * in the sealed object.
+ *
+ * <p> This approach has the advantage that the party who
+ * unseals the object does not need to keep track of the parameters (e.g., an
+ * IV) that were used to seal the object.
+ *
+ * </ul>
+ *
+ * @author Li Gong
+ * @author Jan Luehe
+ * @see Cipher
+ * @since 1.4
+ */
+
+public class SealedObject implements Serializable {
+
+    static final long serialVersionUID = 4482838265551344752L;
+
+    /**
+     * The serialized object contents in encrypted format.
+     *
+     * @serial
+     */
+    private byte[] encryptedContent = null;
+
+    /**
+     * The algorithm that was used to seal this object.
+     *
+     * @serial
+     */
+    private String sealAlg = null;
+
+    /**
+     * The algorithm of the parameters used.
+     *
+     * @serial
+     */
+    private String paramsAlg = null;
+
+    /**
+     * The cryptographic parameters used by the sealing Cipher,
+     * encoded in the default format.
+     * <p>
+     * That is, <code>cipher.getParameters().getEncoded()</code>.
+     *
+     * @serial
+     */
+    protected byte[] encodedParams = null;
+
+    /**
+     * Constructs a SealedObject from any Serializable object.
+     *
+     * <p>The given object is serialized, and its serialized contents are
+     * encrypted using the given Cipher, which must be fully initialized.
+     *
+     * <p>Any algorithm parameters that may be used in the encryption
+     * operation are stored inside of the new <code>SealedObject</code>.
+     *
+     * @param object the object to be sealed; can be null.
+     * @param c the cipher used to seal the object.
+     *
+     * @exception NullPointerException if the given cipher is null.
+     * @exception IOException if an error occurs during serialization
+     * @exception IllegalBlockSizeException if the given cipher is a block
+     * cipher, no padding has been requested, and the total input length
+     * (i.e., the length of the serialized object contents) is not a multiple
+     * of the cipher's block size
+     */
+    public SealedObject(Serializable object, Cipher c) throws IOException,
+        IllegalBlockSizeException
+    {
+        /*
+         * Serialize the object
+         */
+
+        // creating a stream pipe-line, from a to b
+        ByteArrayOutputStream b = new ByteArrayOutputStream();
+        ObjectOutput a = new ObjectOutputStream(b);
+        byte[] content;
+        try {
+            // write and flush the object content to byte array
+            a.writeObject(object);
+            a.flush();
+            content = b.toByteArray();
+        } finally {
+            a.close();
+        }
+
+        /*
+         * Seal the object
+         */
+        try {
+            this.encryptedContent = c.doFinal(content);
+        }
+        catch (BadPaddingException ex) {
+            // if sealing is encryption only
+            // Should never happen??
+        }
+
+        // Save the parameters
+        if (c.getParameters() != null) {
+            this.encodedParams = c.getParameters().getEncoded();
+            this.paramsAlg = c.getParameters().getAlgorithm();
+        }
+
+        // Save the encryption algorithm
+        this.sealAlg = c.getAlgorithm();
+    }
+
+    /**
+     * Constructs a SealedObject object from the passed-in SealedObject.
+     *
+     * @param so a SealedObject object
+     * @exception NullPointerException if the given sealed object is null.
+     */
+    protected SealedObject(SealedObject so) {
+        this.encryptedContent = so.encryptedContent.clone();
+        this.sealAlg = so.sealAlg;
+        this.paramsAlg = so.paramsAlg;
+        if (so.encodedParams != null) {
+            this.encodedParams = so.encodedParams.clone();
+        } else {
+            this.encodedParams = null;
+        }
+    }
+
+    /**
+     * Returns the algorithm that was used to seal this object.
+     *
+     * @return the algorithm that was used to seal this object.
+     */
+    public final String getAlgorithm() {
+        return this.sealAlg;
+    }
+
+    /**
+     * Retrieves the original (encapsulated) object.
+     *
+     * <p>This method creates a cipher for the algorithm that had been used in
+     * the sealing operation.
+     * If the default provider package provides an implementation of that
+     * algorithm, an instance of Cipher containing that implementation is used.
+     * If the algorithm is not available in the default package, other
+     * packages are searched.
+     * The Cipher object is initialized for decryption, using the given
+     * <code>key</code> and the parameters (if any) that had been used in the
+     * sealing operation.
+     *
+     * <p>The encapsulated object is unsealed and de-serialized, before it is
+     * returned.
+     *
+     * @param key the key used to unseal the object.
+     *
+     * @return the original object.
+     *
+     * @exception IOException if an error occurs during de-serialiazation.
+     * @exception ClassNotFoundException if an error occurs during
+     * de-serialiazation.
+     * @exception NoSuchAlgorithmException if the algorithm to unseal the
+     * object is not available.
+     * @exception InvalidKeyException if the given key cannot be used to unseal
+     * the object (e.g., it has the wrong algorithm).
+     * @exception NullPointerException if <code>key</code> is null.
+     */
+    public final Object getObject(Key key)
+        throws IOException, ClassNotFoundException, NoSuchAlgorithmException,
+            InvalidKeyException
+    {
+        if (key == null) {
+            throw new NullPointerException("key is null");
+        }
+
+        try {
+            return unseal(key, null);
+        } catch (NoSuchProviderException nspe) {
+            // we've already caught NoSuchProviderException's and converted
+            // them into NoSuchAlgorithmException's with details about
+            // the failing algorithm
+            throw new NoSuchAlgorithmException("algorithm not found");
+        } catch (IllegalBlockSizeException ibse) {
+            throw new InvalidKeyException(ibse.getMessage());
+        } catch (BadPaddingException bpe) {
+            throw new InvalidKeyException(bpe.getMessage());
+        }
+    }
+
+    /**
+     * Retrieves the original (encapsulated) object.
+     *
+     * <p>The encapsulated object is unsealed (using the given Cipher,
+     * assuming that the Cipher is already properly initialized) and
+     * de-serialized, before it is returned.
+     *
+     * @param c the cipher used to unseal the object
+     *
+     * @return the original object.
+     *
+     * @exception NullPointerException if the given cipher is null.
+     * @exception IOException if an error occurs during de-serialiazation
+     * @exception ClassNotFoundException if an error occurs during
+     * de-serialiazation
+     * @exception IllegalBlockSizeException if the given cipher is a block
+     * cipher, no padding has been requested, and the total input length is
+     * not a multiple of the cipher's block size
+     * @exception BadPaddingException if the given cipher has been
+     * initialized for decryption, and padding has been specified, but
+     * the input data does not have proper expected padding bytes
+     */
+    public final Object getObject(Cipher c)
+        throws IOException, ClassNotFoundException, IllegalBlockSizeException,
+            BadPaddingException
+    {
+        /*
+         * Unseal the object
+         */
+        byte[] content = c.doFinal(this.encryptedContent);
+
+        /*
+         * De-serialize it
+         */
+        // creating a stream pipe-line, from b to a
+        ByteArrayInputStream b = new ByteArrayInputStream(content);
+        ObjectInput a = new extObjectInputStream(b);
+        try {
+            Object obj = a.readObject();
+            return obj;
+        } finally {
+            a.close();
+        }
+    }
+
+    /**
+     * Retrieves the original (encapsulated) object.
+     *
+     * <p>This method creates a cipher for the algorithm that had been used in
+     * the sealing operation, using an implementation of that algorithm from
+     * the given <code>provider</code>.
+     * The Cipher object is initialized for decryption, using the given
+     * <code>key</code> and the parameters (if any) that had been used in the
+     * sealing operation.
+     *
+     * <p>The encapsulated object is unsealed and de-serialized, before it is
+     * returned.
+     *
+     * @param key the key used to unseal the object.
+     * @param provider the name of the provider of the algorithm to unseal
+     * the object.
+     *
+     * @return the original object.
+     *
+     * @exception IllegalArgumentException if the given provider is null
+     * or empty.
+     * @exception IOException if an error occurs during de-serialiazation.
+     * @exception ClassNotFoundException if an error occurs during
+     * de-serialiazation.
+     * @exception NoSuchAlgorithmException if the algorithm to unseal the
+     * object is not available.
+     * @exception NoSuchProviderException if the given provider is not
+     * configured.
+     * @exception InvalidKeyException if the given key cannot be used to unseal
+     * the object (e.g., it has the wrong algorithm).
+     * @exception NullPointerException if <code>key</code> is null.
+     */
+    public final Object getObject(Key key, String provider)
+        throws IOException, ClassNotFoundException, NoSuchAlgorithmException,
+            NoSuchProviderException, InvalidKeyException
+    {
+        if (key == null) {
+            throw new NullPointerException("key is null");
+        }
+        if (provider == null || provider.length() == 0) {
+            throw new IllegalArgumentException("missing provider");
+        }
+
+        try {
+            return unseal(key, provider);
+        } catch (IllegalBlockSizeException | BadPaddingException ex) {
+            throw new InvalidKeyException(ex.getMessage());
+        }
+    }
+
+
+    private Object unseal(Key key, String provider)
+        throws IOException, ClassNotFoundException, NoSuchAlgorithmException,
+            NoSuchProviderException, InvalidKeyException,
+            IllegalBlockSizeException, BadPaddingException
+    {
+        /*
+         * Create the parameter object.
+         */
+        AlgorithmParameters params = null;
+        if (this.encodedParams != null) {
+            try {
+                if (provider != null)
+                    params = AlgorithmParameters.getInstance(this.paramsAlg,
+                                                             provider);
+                else
+                    params = AlgorithmParameters.getInstance(this.paramsAlg);
+
+            } catch (NoSuchProviderException nspe) {
+                if (provider == null) {
+                    throw new NoSuchAlgorithmException(this.paramsAlg
+                                                       + " not found");
+                } else {
+                    throw new NoSuchProviderException(nspe.getMessage());
+                }
+            }
+            params.init(this.encodedParams);
+        }
+
+        /*
+         * Create and initialize the cipher.
+         */
+        Cipher c;
+        try {
+            if (provider != null)
+                c = Cipher.getInstance(this.sealAlg, provider);
+            else
+                c = Cipher.getInstance(this.sealAlg);
+        } catch (NoSuchPaddingException nspe) {
+            throw new NoSuchAlgorithmException("Padding that was used in "
+                                               + "sealing operation not "
+                                               + "available");
+        } catch (NoSuchProviderException nspe) {
+            if (provider == null) {
+                throw new NoSuchAlgorithmException(this.sealAlg+" not found");
+            } else {
+                throw new NoSuchProviderException(nspe.getMessage());
+            }
+        }
+
+        try {
+            if (params != null)
+                c.init(Cipher.DECRYPT_MODE, key, params);
+            else
+                c.init(Cipher.DECRYPT_MODE, key);
+        } catch (InvalidAlgorithmParameterException iape) {
+            // this should never happen, because we use the exact same
+            // parameters that were used in the sealing operation
+            throw new RuntimeException(iape.getMessage());
+        }
+
+        /*
+         * Unseal the object
+         */
+        byte[] content = c.doFinal(this.encryptedContent);
+
+        /*
+         * De-serialize it
+         */
+        // creating a stream pipe-line, from b to a
+        ByteArrayInputStream b = new ByteArrayInputStream(content);
+        ObjectInput a = new extObjectInputStream(b);
+        try {
+            Object obj = a.readObject();
+            return obj;
+        } finally {
+            a.close();
+        }
+    }
+
+    /**
+     * Restores the state of the SealedObject from a stream.
+     * @param s the object input stream.
+     * @exception NullPointerException if s is null.
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException
+    {
+        s.defaultReadObject();
+        if (encryptedContent != null)
+            encryptedContent = encryptedContent.clone();
+        if (encodedParams != null)
+            encodedParams = encodedParams.clone();
+    }
+}
+
+final class extObjectInputStream extends ObjectInputStream {
+
+    private static ClassLoader systemClassLoader = null;
+
+    extObjectInputStream(InputStream in)
+        throws IOException, StreamCorruptedException {
+        super(in);
+    }
+
+    protected Class<?> resolveClass(ObjectStreamClass v)
+        throws IOException, ClassNotFoundException
+    {
+
+        try {
+            /*
+             * Calling the super.resolveClass() first
+             * will let us pick up bug fixes in the super
+             * class (e.g., 4171142).
+             */
+            return super.resolveClass(v);
+        } catch (ClassNotFoundException cnfe) {
+            /*
+             * This is a workaround for bug 4224921.
+             */
+            ClassLoader loader = Thread.currentThread().getContextClassLoader();
+            if (loader == null) {
+                if (systemClassLoader == null) {
+                    systemClassLoader = ClassLoader.getSystemClassLoader();
+                }
+                loader = systemClassLoader;
+                if (loader == null) {
+                    throw new ClassNotFoundException(v.getName());
+                }
+            }
+
+            return Class.forName(v.getName(), false, loader);
+        }
+    }
+}
diff --git a/javax/crypto/SecretKey.java b/javax/crypto/SecretKey.java
new file mode 100644
index 0000000..e03639a
--- /dev/null
+++ b/javax/crypto/SecretKey.java
@@ -0,0 +1,68 @@
+/*
+ * 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 javax.crypto;
+
+/**
+ * A secret (symmetric) key.
+ * The purpose of this interface is to group (and provide type safety
+ * for) all secret key interfaces.
+ * <p>
+ * Provider implementations of this interface must overwrite the
+ * {@code equals} and {@code hashCode} methods inherited from
+ * {@link java.lang.Object}, so that secret keys are compared based on
+ * their underlying key material and not based on reference.
+ * 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 SecretKey} 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.
+ *
+ * <p>Keys that implement this interface return the string {@code RAW}
+ * as their encoding format (see {@code getFormat}), and return the
+ * raw key bytes as the result of a {@code getEncoded} method call. (The
+ * {@code getFormat} and {@code getEncoded} methods are inherited
+ * from the {@link java.security.Key} parent interface.)
+ *
+ * @author Jan Luehe
+ *
+ * @see SecretKeyFactory
+ * @see Cipher
+ * @since 1.4
+ */
+
+public interface SecretKey extends
+    java.security.Key, javax.security.auth.Destroyable {
+
+    /**
+     * The class fingerprint that is set to indicate serialization
+     * compatibility since J2SE 1.4.
+     */
+    static final long serialVersionUID = -4795878709595146952L;
+}
diff --git a/javax/crypto/SecretKeyFactory.java b/javax/crypto/SecretKeyFactory.java
new file mode 100644
index 0000000..bd8b271
--- /dev/null
+++ b/javax/crypto/SecretKeyFactory.java
@@ -0,0 +1,617 @@
+/*
+ * 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 javax.crypto;
+
+import java.util.*;
+
+import java.security.*;
+import java.security.Provider.Service;
+import java.security.spec.*;
+
+import sun.security.jca.*;
+import sun.security.jca.GetInstance.Instance;
+
+/**
+ * This class represents a factory for secret keys.
+ *
+ * <P> Key factories are used to convert <I>keys</I> (opaque
+ * cryptographic keys of type <code>Key</code>) into <I>key specifications</I>
+ * (transparent representations of the underlying key material), and vice
+ * versa.
+ * Secret key factories operate only on secret (symmetric) keys.
+ *
+ * <P> Key factories are bi-directional, i.e., they allow 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> Application developers should refer to their provider's documentation
+ * to find out which key specifications are supported by the
+ * {@link #generateSecret(java.security.spec.KeySpec) generateSecret} and
+ * {@link #getKeySpec(javax.crypto.SecretKey, java.lang.Class) getKeySpec}
+ * methods.
+ * For example, the DES secret-key factory supplied by the "SunJCE" provider
+ * supports <code>DESKeySpec</code> as a transparent representation of DES
+ * keys, and that provider's secret-key factory for Triple DES keys supports
+ * <code>DESedeKeySpec</code> as a transparent representation of Triple DES
+ * keys.
+ *
+ * <p> Android provides the following <code>SecretKeyFactory</code> algorithms:
+ * <table>
+ *   <thead>
+ *     <tr>
+ *       <th>Algorithm</th>
+ *       <th>Supported API Levels</th>
+ *     </tr>
+ *   </thead>
+ *   <tbody>
+ *     <tr>
+ *       <td>AES</td>
+ *       <td>23+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>DES</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>DESede</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>HmacSHA1</td>
+ *       <td>23+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>HmacSHA224</td>
+ *       <td>23+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>HmacSHA256</td>
+ *       <td>23+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>HmacSHA384</td>
+ *       <td>23+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>HmacSHA512</td>
+ *       <td>23+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PBEwithHmacSHA1</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>PBEwithMD5AND128BITAES-CBC-OPENSSL</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PBEwithMD5AND192BITAES-CBC-OPENSSL</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PBEwithMD5AND256BITAES-CBC-OPENSSL</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PBEwithMD5ANDDES</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PBEwithMD5ANDRC2</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PBEwithSHA1ANDDES</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PBEwithSHA1ANDRC2</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PBEwithSHA256AND128BITAES-CBC-BC</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PBEwithSHA256AND192BITAES-CBC-BC</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PBEwithSHA256AND256BITAES-CBC-BC</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PBEwithSHAAND128BITAES-CBC-BC</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PBEwithSHAAND128BITRC2-CBC</td>
+ *       <td>10+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PBEwithSHAAND128BITRC4</td>
+ *       <td>10+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PBEwithSHAAND192BITAES-CBC-BC</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PBEwithSHAAND2-KEYTRIPLEDES-CBC</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PBEwithSHAAND256BITAES-CBC-BC</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PBEwithSHAAND3-KEYTRIPLEDES-CBC</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PBEwithSHAAND40BITRC2-CBC</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PBEwithSHAAND40BITRC4</td>
+ *       <td>10+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PBEwithSHAANDTWOFISH-CBC</td>
+ *       <td>10+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PBKDF2withHmacSHA1</td>
+ *       <td>10+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PBKDF2withHmacSHA1And8BIT</td>
+ *       <td>19+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PBKDF2withHmacSHA224</td>
+ *       <td>26+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PBKDF2withHmacSHA256</td>
+ *       <td>26+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PBKDF2withHmacSHA384</td>
+ *       <td>26+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PBKDF2withHmacSHA512</td>
+ *       <td>26+</td>
+ *     </tr>
+ *   </tbody>
+ * </table>
+ *
+ * These algorithms are described in the <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#SecretKeyFactory">
+ * SecretKeyFactory section</a> of the
+ * Java Cryptography Architecture Standard Algorithm Name Documentation.
+ *
+ * @author Jan Luehe
+ *
+ * @see SecretKey
+ * @see javax.crypto.spec.DESKeySpec
+ * @see javax.crypto.spec.DESedeKeySpec
+ * @see javax.crypto.spec.PBEKeySpec
+ * @since 1.4
+ */
+
+public class SecretKeyFactory {
+
+    // The provider
+    private Provider provider;
+
+    // The algorithm associated with this factory
+    private final String algorithm;
+
+    // The provider implementation (delegate)
+    private volatile SecretKeyFactorySpi 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 SecretKeyFactory object.
+     *
+     * @param keyFacSpi the delegate
+     * @param provider the provider
+     * @param algorithm the secret-key algorithm
+     */
+    protected SecretKeyFactory(SecretKeyFactorySpi keyFacSpi,
+                               Provider provider, String algorithm) {
+        this.spi = keyFacSpi;
+        this.provider = provider;
+        this.algorithm = algorithm;
+    }
+
+    private SecretKeyFactory(String algorithm) throws NoSuchAlgorithmException {
+        this.algorithm = algorithm;
+        List<Service> list =
+                GetInstance.getServices("SecretKeyFactory", algorithm);
+        serviceIterator = list.iterator();
+        // fetch and instantiate initial spi
+        if (nextSpi(null) == null) {
+            throw new NoSuchAlgorithmException
+                (algorithm + " SecretKeyFactory not available");
+        }
+    }
+
+    /**
+     * Returns a <code>SecretKeyFactory</code> object that converts
+     * secret keys of the specified algorithm.
+     *
+     * <p> This method traverses the list of registered security Providers,
+     * starting with the most preferred Provider.
+     * A new SecretKeyFactory object encapsulating the
+     * SecretKeyFactorySpi 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 requested secret-key
+     * algorithm.
+     * See the SecretKeyFactory section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#SecretKeyFactory">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard algorithm names.
+     *
+     * @return the new <code>SecretKeyFactory</code> object.
+     *
+     * @exception NullPointerException if the specified algorithm
+     *          is null.
+     *
+     * @exception NoSuchAlgorithmException if no Provider supports a
+     *          SecretKeyFactorySpi implementation for the
+     *          specified algorithm.
+     *
+     * @see java.security.Provider
+     */
+    public static final SecretKeyFactory getInstance(String algorithm)
+            throws NoSuchAlgorithmException {
+        return new SecretKeyFactory(algorithm);
+    }
+
+    /**
+     * Returns a <code>SecretKeyFactory</code> object that converts
+     * secret keys of the specified algorithm.
+     *
+     * <p> A new SecretKeyFactory object encapsulating the
+     * SecretKeyFactorySpi 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 name of the requested secret-key
+     * algorithm.
+     * See the SecretKeyFactory section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#SecretKeyFactory">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard algorithm names.
+     *
+     * @param provider the name of the provider.
+     *
+     * @return the new <code>SecretKeyFactory</code> object.
+     *
+     * @exception NoSuchAlgorithmException if a SecretKeyFactorySpi
+     *          implementation for the specified algorithm is not
+     *          available from the specified provider.
+     *
+     * @exception NullPointerException if the specified algorithm
+     *          is null.
+     *
+     * @throws NoSuchProviderException if the specified provider is not
+     *          registered in the security provider list.
+     *
+     * @exception IllegalArgumentException if the <code>provider</code>
+     *          is null or empty.
+     *
+     * @see java.security.Provider
+     */
+    public static final SecretKeyFactory getInstance(String algorithm,
+            String provider) throws NoSuchAlgorithmException,
+            NoSuchProviderException {
+        // Android-added: Check for Bouncy Castle deprecation
+        Providers.checkBouncyCastleDeprecation(provider, "SecretKeyFactory", algorithm);
+        Instance instance = JceSecurity.getInstance("SecretKeyFactory",
+                SecretKeyFactorySpi.class, algorithm, provider);
+        return new SecretKeyFactory((SecretKeyFactorySpi)instance.impl,
+                instance.provider, algorithm);
+    }
+
+    /**
+     * Returns a <code>SecretKeyFactory</code> object that converts
+     * secret keys of the specified algorithm.
+     *
+     * <p> A new SecretKeyFactory object encapsulating the
+     * SecretKeyFactorySpi 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 name of the requested secret-key
+     * algorithm.
+     * See the SecretKeyFactory section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#SecretKeyFactory">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard algorithm names.
+     *
+     * @param provider the provider.
+     *
+     * @return the new <code>SecretKeyFactory</code> object.
+     *
+     * @exception NullPointerException if the specified algorithm
+     * is null.
+     *
+     * @exception NoSuchAlgorithmException if a SecretKeyFactorySpi
+     *          implementation for the specified algorithm is not available
+     *          from the specified Provider object.
+     *
+     * @exception IllegalArgumentException if the <code>provider</code>
+     *          is null.
+     *
+     * @see java.security.Provider
+     */
+    public static final SecretKeyFactory getInstance(String algorithm,
+            Provider provider) throws NoSuchAlgorithmException {
+        // Android-added: Check for Bouncy Castle deprecation
+        Providers.checkBouncyCastleDeprecation(provider, "SecretKeyFactory", algorithm);
+        Instance instance = JceSecurity.getInstance("SecretKeyFactory",
+                SecretKeyFactorySpi.class, algorithm, provider);
+        return new SecretKeyFactory((SecretKeyFactorySpi)instance.impl,
+                instance.provider, algorithm);
+    }
+
+    /**
+     * Returns the provider of this <code>SecretKeyFactory</code> object.
+     *
+     * @return the provider of this <code>SecretKeyFactory</code> object
+     */
+    public final Provider getProvider() {
+        synchronized (lock) {
+            // disable further failover after this call
+            serviceIterator = null;
+            return provider;
+        }
+    }
+
+    /**
+     * Returns the algorithm name of this <code>SecretKeyFactory</code> object.
+     *
+     * <p>This is the same name that was specified in one of the
+     * <code>getInstance</code> calls that created this
+     * <code>SecretKeyFactory</code> object.
+     *
+     * @return the algorithm name of this <code>SecretKeyFactory</code>
+     * object.
+     */
+    public final String getAlgorithm() {
+        return this.algorithm;
+    }
+
+    /**
+     * 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 SecretKeyFactorySpi nextSpi(SecretKeyFactorySpi 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();
+                if (JceSecurity.canUseProvider(s.getProvider()) == false) {
+                    continue;
+                }
+                try {
+                    Object obj = s.newInstance(null);
+                    if (obj instanceof SecretKeyFactorySpi == false) {
+                        continue;
+                    }
+                    SecretKeyFactorySpi spi = (SecretKeyFactorySpi)obj;
+                    provider = s.getProvider();
+                    this.spi = spi;
+                    return spi;
+                } catch (NoSuchAlgorithmException e) {
+                    // ignore
+                }
+            }
+            serviceIterator = null;
+            return null;
+        }
+    }
+
+    /**
+     * Generates a <code>SecretKey</code> object from the provided key
+     * specification (key material).
+     *
+     * @param keySpec the specification (key material) of the secret key
+     *
+     * @return the secret key
+     *
+     * @exception InvalidKeySpecException if the given key specification
+     * is inappropriate for this secret-key factory to produce a secret key.
+     */
+    public final SecretKey generateSecret(KeySpec keySpec)
+            throws InvalidKeySpecException {
+        if (serviceIterator == null) {
+            return spi.engineGenerateSecret(keySpec);
+        }
+        Exception failure = null;
+        SecretKeyFactorySpi mySpi = spi;
+        do {
+            try {
+                return mySpi.engineGenerateSecret(keySpec);
+            } catch (Exception e) {
+                if (failure == null) {
+                    failure = e;
+                }
+                mySpi = nextSpi(mySpi);
+            }
+        } while (mySpi != null);
+        if (failure instanceof InvalidKeySpecException) {
+            throw (InvalidKeySpecException)failure;
+        }
+        throw new InvalidKeySpecException
+                ("Could not generate secret key", failure);
+    }
+
+    /**
+     * Returns a specification (key material) of the given key object
+     * in the requested format.
+     *
+     * @param key the key
+     * @param keySpec the requested format in which the key material shall be
+     * returned
+     *
+     * @return the underlying key specification (key material) in the
+     * requested format
+     *
+     * @exception InvalidKeySpecException if the requested key specification is
+     * inappropriate for the given key (e.g., the algorithms associated with
+     * <code>key</code> and <code>keySpec</code> do not match, or
+     * <code>key</code> references a key on a cryptographic hardware device
+     * whereas <code>keySpec</code> is the specification of a software-based
+     * key), or the given key cannot be dealt with
+     * (e.g., the given key has an algorithm or format not supported by this
+     * secret-key factory).
+     */
+    public final KeySpec getKeySpec(SecretKey key, Class<?> keySpec)
+            throws InvalidKeySpecException {
+        if (serviceIterator == null) {
+            return spi.engineGetKeySpec(key, keySpec);
+        }
+        Exception failure = null;
+        SecretKeyFactorySpi 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 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 secret-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 secret-key factory.
+     */
+    public final SecretKey translateKey(SecretKey key)
+            throws InvalidKeyException {
+        if (serviceIterator == null) {
+            return spi.engineTranslateKey(key);
+        }
+        Exception failure = null;
+        SecretKeyFactorySpi 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 InvalidKeyException) {
+            throw (InvalidKeyException)failure;
+        }
+        throw new InvalidKeyException
+                ("Could not translate key", failure);
+    }
+}
diff --git a/javax/crypto/SecretKeyFactorySpi.java b/javax/crypto/SecretKeyFactorySpi.java
new file mode 100644
index 0000000..342a5c7
--- /dev/null
+++ b/javax/crypto/SecretKeyFactorySpi.java
@@ -0,0 +1,108 @@
+/*
+ * 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 javax.crypto;
+
+import java.security.*;
+import java.security.spec.*;
+
+/**
+ * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>)
+ * for the <code>SecretKeyFactory</code> class.
+ * All the abstract methods in this class must be implemented by each
+ * cryptographic service provider who wishes to supply the implementation
+ * of a secret-key factory for a particular algorithm.
+ *
+ * <P> A provider should document all the key specifications supported by its
+ * secret key factory.
+ * For example, the DES secret-key factory supplied by the "SunJCE" provider
+ * supports <code>DESKeySpec</code> as a transparent representation of DES
+ * keys, and that provider's secret-key factory for Triple DES keys supports
+ * <code>DESedeKeySpec</code> as a transparent representation of Triple DES
+ * keys.
+ *
+ * @author Jan Luehe
+ *
+ * @see SecretKey
+ * @see javax.crypto.spec.DESKeySpec
+ * @see javax.crypto.spec.DESedeKeySpec
+ * @since 1.4
+ */
+
+public abstract class SecretKeyFactorySpi {
+
+    /**
+     * Generates a <code>SecretKey</code> object from the
+     * provided key specification (key material).
+     *
+     * @param keySpec the specification (key material) of the secret key
+     *
+     * @return the secret key
+     *
+     * @exception InvalidKeySpecException if the given key specification
+     * is inappropriate for this secret-key factory to produce a secret key.
+     */
+    protected abstract SecretKey engineGenerateSecret(KeySpec keySpec)
+        throws InvalidKeySpecException;
+
+    /**
+     * Returns a specification (key material) of the given key
+     * object in the requested format.
+     *
+     * @param key the key
+     *
+     * @param keySpec the requested format in which the key material shall be
+     * returned
+     *
+     * @return the underlying key specification (key material) in the
+     * requested format
+     *
+     * @exception InvalidKeySpecException if the requested key specification is
+     * inappropriate for the given key (e.g., the algorithms associated with
+     * <code>key</code> and <code>keySpec</code> do not match, or
+     * <code>key</code> references a key on a cryptographic hardware device
+     * whereas <code>keySpec</code> is the specification of a software-based
+     * key), or the given key cannot be dealt with
+     * (e.g., the given key has an algorithm or format not supported by this
+     * secret-key factory).
+     */
+    protected abstract KeySpec engineGetKeySpec(SecretKey key, Class<?> keySpec)
+        throws InvalidKeySpecException;
+
+    /**
+     * Translates a key object, whose provider may be unknown or
+     * potentially untrusted, into a corresponding key object of this
+     * secret-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 secret-key factory.
+     */
+    protected abstract SecretKey engineTranslateKey(SecretKey key)
+        throws InvalidKeyException;
+}
diff --git a/javax/crypto/ShortBufferException.java b/javax/crypto/ShortBufferException.java
new file mode 100644
index 0000000..0a25fff
--- /dev/null
+++ b/javax/crypto/ShortBufferException.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1997, 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 javax.crypto;
+
+import java.security.GeneralSecurityException;
+
+/**
+ * This exception is thrown when an output buffer provided by the user
+ * is too short to hold the operation result.
+ *
+ * @author Jan Luehe
+ *
+ * @since 1.4
+ */
+
+public class ShortBufferException extends GeneralSecurityException {
+
+    private static final long serialVersionUID = 8427718640832943747L;
+
+    /**
+     * Constructs a ShortBufferException with no detail
+     * message. A detail message is a String that describes this
+     * particular exception.
+     */
+    public ShortBufferException() {
+        super();
+    }
+
+    /**
+     * Constructs a ShortBufferException with the specified
+     * detail message.
+     *
+     * @param msg the detail message.
+     */
+    public ShortBufferException(String msg) {
+        super(msg);
+    }
+}
diff --git a/javax/crypto/interfaces/DHKey.java b/javax/crypto/interfaces/DHKey.java
new file mode 100644
index 0000000..37dfda7
--- /dev/null
+++ b/javax/crypto/interfaces/DHKey.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 1997, 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 javax.crypto.interfaces;
+
+import javax.crypto.spec.DHParameterSpec;
+
+/**
+ * The interface to a Diffie-Hellman key.
+ *
+ * @author Jan Luehe
+ *
+ * @see javax.crypto.spec.DHParameterSpec
+ * @see DHPublicKey
+ * @see DHPrivateKey
+ * @since 1.4
+ */
+public interface DHKey {
+
+    /**
+     * Returns the key parameters.
+     *
+     * @return the key parameters
+     */
+    DHParameterSpec getParams();
+}
diff --git a/javax/crypto/interfaces/DHPrivateKey.java b/javax/crypto/interfaces/DHPrivateKey.java
new file mode 100644
index 0000000..1fa3ba0
--- /dev/null
+++ b/javax/crypto/interfaces/DHPrivateKey.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1997, 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 javax.crypto.interfaces;
+
+import java.math.BigInteger;
+
+/**
+ * The interface to a Diffie-Hellman private key.
+ *
+ * @author Jan Luehe
+ *
+ * @see DHKey
+ * @see DHPublicKey
+ * @since 1.4
+ */
+public interface DHPrivateKey extends DHKey, java.security.PrivateKey {
+
+    /**
+     * The class fingerprint that is set to indicate serialization
+     * compatibility since J2SE 1.4.
+     */
+    static final long serialVersionUID = 2211791113380396553L;
+
+    /**
+     * Returns the private value, <code>x</code>.
+     *
+     * @return the private value, <code>x</code>
+     */
+    BigInteger getX();
+}
diff --git a/javax/crypto/interfaces/DHPublicKey.java b/javax/crypto/interfaces/DHPublicKey.java
new file mode 100644
index 0000000..a1fdb41
--- /dev/null
+++ b/javax/crypto/interfaces/DHPublicKey.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1997, 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 javax.crypto.interfaces;
+
+import java.math.BigInteger;
+
+/**
+ * The interface to a Diffie-Hellman public key.
+ *
+ * @author Jan Luehe
+ *
+ * @see DHKey
+ * @see DHPrivateKey
+ * @since 1.4
+ */
+public interface DHPublicKey extends DHKey, java.security.PublicKey {
+
+    /**
+     * The class fingerprint that is set to indicate serialization
+     * compatibility since J2SE 1.4.
+     */
+    static final long serialVersionUID = -6628103563352519193L;
+
+    /**
+     * Returns the public value, <code>y</code>.
+     *
+     * @return the public value, <code>y</code>
+     */
+    BigInteger getY();
+}
diff --git a/javax/crypto/interfaces/PBEKey.java b/javax/crypto/interfaces/PBEKey.java
new file mode 100644
index 0000000..3027726
--- /dev/null
+++ b/javax/crypto/interfaces/PBEKey.java
@@ -0,0 +1,75 @@
+/*
+ * 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 javax.crypto.interfaces;
+
+import java.math.BigInteger;
+
+/**
+ * The interface to a PBE key.
+ *
+ * @author Valerie Peng
+ *
+ * @see javax.crypto.spec.PBEKeySpec
+ * @see javax.crypto.SecretKey
+ * @since 1.4
+ */
+public interface PBEKey extends javax.crypto.SecretKey {
+
+    /**
+     * The class fingerprint that is set to indicate serialization
+     * compatibility since J2SE 1.4.
+     */
+    static final long serialVersionUID = -1430015993304333921L;
+
+    /**
+     * Returns the password.
+     *
+     * <p> Note: this method should return a copy of the password. It is
+     * the caller's responsibility to zero out the password information after
+     * it is no longer needed.
+     *
+     * @return the password.
+     */
+    char[] getPassword();
+
+    /**
+     * Returns the salt or null if not specified.
+     *
+     * <p> Note: this method should return a copy of the salt. It is
+     * the caller's responsibility to zero out the salt information after
+     * it is no longer needed.
+     *
+     * @return the salt.
+     */
+    byte[] getSalt();
+
+    /**
+     * Returns the iteration count or 0 if not specified.
+     *
+     * @return the iteration count.
+     */
+    int getIterationCount();
+}
diff --git a/javax/crypto/spec/DESKeySpec.java b/javax/crypto/spec/DESKeySpec.java
new file mode 100644
index 0000000..2d35f0a
--- /dev/null
+++ b/javax/crypto/spec/DESKeySpec.java
@@ -0,0 +1,240 @@
+/*
+ * 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 javax.crypto.spec;
+
+import java.security.InvalidKeyException;
+
+/**
+ * This class specifies a DES key.
+ *
+ * @author Jan Luehe
+ *
+ * @since 1.4
+ */
+public class DESKeySpec implements java.security.spec.KeySpec {
+
+    /**
+     * The constant which defines the length of a DES key in bytes.
+     */
+    public static final int DES_KEY_LEN = 8;
+
+    private byte[] key;
+
+    /*
+     * Weak/semi-weak keys copied from FIPS 74.
+     *
+     * "...The first 6 keys have duals different than themselves, hence
+     * each is both a key and a dual giving 12 keys with duals. The last
+     * four keys equal their duals, and are called self-dual keys..."
+     *
+     * 1.   E001E001F101F101    01E001E001F101F1
+     * 2.   FE1FFE1FFEOEFEOE    1FFE1FFEOEFEOEFE
+     * 3.   E01FE01FF10EF10E    1FE01FEOOEF10EF1
+     * 4.   01FE01FE01FE01FE    FE01FE01FE01FE01
+     * 5.   011F011F010E010E    1F011F010E010E01
+     * 6.   E0FEE0FEF1FEF1FE    FEE0FEE0FEF1FEF1
+     * 7.   0101010101010101    0101010101010101
+     * 8.   FEFEFEFEFEFEFEFE    FEFEFEFEFEFEFEFE
+     * 9.   E0E0E0E0F1F1F1F1    E0E0E0E0F1F1F1F1
+     * 10.  1F1F1F1F0E0E0E0E    1F1F1F1F0E0E0E0E
+     */
+    private static final byte[][] WEAK_KEYS = {
+
+        { (byte)0x01, (byte)0x01, (byte)0x01, (byte)0x01, (byte)0x01,
+          (byte)0x01, (byte)0x01, (byte)0x01 },
+
+        { (byte)0xFE, (byte)0xFE, (byte)0xFE, (byte)0xFE, (byte)0xFE,
+          (byte)0xFE, (byte)0xFE, (byte)0xFE },
+
+        { (byte)0x1F, (byte)0x1F, (byte)0x1F, (byte)0x1F, (byte)0x0E,
+          (byte)0x0E, (byte)0x0E, (byte)0x0E },
+
+        { (byte)0xE0, (byte)0xE0, (byte)0xE0, (byte)0xE0, (byte)0xF1,
+          (byte)0xF1, (byte)0xF1, (byte)0xF1 },
+
+        { (byte)0x01, (byte)0xFE, (byte)0x01, (byte)0xFE, (byte)0x01,
+          (byte)0xFE, (byte)0x01, (byte)0xFE },
+
+        { (byte)0x1F, (byte)0xE0, (byte)0x1F, (byte)0xE0, (byte)0x0E,
+          (byte)0xF1, (byte)0x0E, (byte)0xF1 },
+
+        { (byte)0x01, (byte)0xE0, (byte)0x01, (byte)0xE0, (byte)0x01,
+          (byte)0xF1, (byte)0x01, (byte)0xF1 },
+
+        { (byte)0x1F, (byte)0xFE, (byte)0x1F, (byte)0xFE, (byte)0x0E,
+          (byte)0xFE, (byte)0x0E, (byte)0xFE },
+
+        { (byte)0x01, (byte)0x1F, (byte)0x01, (byte)0x1F, (byte)0x01,
+          (byte)0x0E, (byte)0x01, (byte)0x0E },
+
+        { (byte)0xE0, (byte)0xFE, (byte)0xE0, (byte)0xFE, (byte)0xF1,
+          (byte)0xFE, (byte)0xF1, (byte)0xFE },
+
+        { (byte)0xFE, (byte)0x01, (byte)0xFE, (byte)0x01, (byte)0xFE,
+          (byte)0x01, (byte)0xFE, (byte)0x01 },
+
+        { (byte)0xE0, (byte)0x1F, (byte)0xE0, (byte)0x1F, (byte)0xF1,
+          (byte)0x0E, (byte)0xF1, (byte)0x0E },
+
+        { (byte)0xE0, (byte)0x01, (byte)0xE0, (byte)0x01, (byte)0xF1,
+          (byte)0x01, (byte)0xF1, (byte)0x01 },
+
+        { (byte)0xFE, (byte)0x1F, (byte)0xFE, (byte)0x1F, (byte)0xFE,
+          (byte)0x0E, (byte)0xFE, (byte)0x0E },
+
+        { (byte)0x1F, (byte)0x01, (byte)0x1F, (byte)0x01, (byte)0x0E,
+          (byte)0x01, (byte)0x0E, (byte)0x01 },
+
+        { (byte)0xFE, (byte)0xE0, (byte)0xFE, (byte)0xE0, (byte)0xFE,
+          (byte)0xF1, (byte)0xFE, (byte)0xF1 }
+    };
+
+    /**
+     * Creates a DESKeySpec object using the first 8 bytes in
+     * <code>key</code> as the key material for the DES key.
+     *
+     * <p> The bytes that constitute the DES key are those between
+     * <code>key[0]</code> and <code>key[7]</code> inclusive.
+     *
+     * @param key the buffer with the DES key material. The first 8 bytes
+     * of the buffer are copied to protect against subsequent modification.
+     *
+     * @exception NullPointerException if the given key material is
+     * <code>null</code>
+     * @exception InvalidKeyException if the given key material is shorter
+     * than 8 bytes.
+     */
+    public DESKeySpec(byte[] key) throws InvalidKeyException {
+        this(key, 0);
+    }
+
+    /**
+     * Creates a DESKeySpec object using the first 8 bytes in
+     * <code>key</code>, beginning at <code>offset</code> inclusive,
+     * as the key material for the DES key.
+     *
+     * <p> The bytes that constitute the DES key are those between
+     * <code>key[offset]</code> and <code>key[offset+7]</code> inclusive.
+     *
+     * @param key the buffer with the DES key material. The first 8 bytes
+     * of the buffer beginning at <code>offset</code> inclusive are copied
+     * to protect against subsequent modification.
+     * @param offset the offset in <code>key</code>, where the DES key
+     * material starts.
+     *
+     * @exception NullPointerException if the given key material is
+     * <code>null</code>
+     * @exception InvalidKeyException if the given key material, starting at
+     * <code>offset</code> inclusive, is shorter than 8 bytes.
+     */
+    public DESKeySpec(byte[] key, int offset) throws InvalidKeyException {
+        if (key.length - offset < DES_KEY_LEN) {
+            throw new InvalidKeyException("Wrong key size");
+        }
+        this.key = new byte[DES_KEY_LEN];
+        System.arraycopy(key, offset, this.key, 0, DES_KEY_LEN);
+    }
+
+    /**
+     * Returns the DES key material.
+     *
+     * @return the DES key material. Returns a new array
+     * each time this method is called.
+     */
+    public byte[] getKey() {
+        return this.key.clone();
+    }
+
+    /**
+     * Checks if the given DES key material, starting at <code>offset</code>
+     * inclusive, is parity-adjusted.
+     *
+     * @param key the buffer with the DES key material.
+     * @param offset the offset in <code>key</code>, where the DES key
+     * material starts.
+     *
+     * @return true if the given DES key material is parity-adjusted, false
+     * otherwise.
+     *
+     * @exception InvalidKeyException if the given key material is
+     * <code>null</code>, or starting at <code>offset</code> inclusive, is
+     * shorter than 8 bytes.
+     */
+    public static boolean isParityAdjusted(byte[] key, int offset)
+        throws InvalidKeyException {
+            if (key == null) {
+                throw new InvalidKeyException("null key");
+            }
+            if (key.length - offset < DES_KEY_LEN) {
+                throw new InvalidKeyException("Wrong key size");
+            }
+
+            for (int i = 0; i < DES_KEY_LEN; i++) {
+                int k = Integer.bitCount(key[offset++] & 0xff);
+                if ((k & 1) == 0) {
+                    return false;
+                }
+            }
+
+            return true;
+    }
+
+    /**
+     * Checks if the given DES key material is weak or semi-weak.
+     *
+     * @param key the buffer with the DES key material.
+     * @param offset the offset in <code>key</code>, where the DES key
+     * material starts.
+     *
+     * @return true if the given DES key material is weak or semi-weak, false
+     * otherwise.
+     *
+     * @exception InvalidKeyException if the given key material is
+     * <code>null</code>, or starting at <code>offset</code> inclusive, is
+     * shorter than 8 bytes.
+     */
+    public static boolean isWeak(byte[] key, int offset)
+        throws InvalidKeyException {
+        if (key == null) {
+            throw new InvalidKeyException("null key");
+        }
+        if (key.length - offset < DES_KEY_LEN) {
+            throw new InvalidKeyException("Wrong key size");
+        }
+        for (int i = 0; i < WEAK_KEYS.length; i++) {
+            boolean found = true;
+            for (int j = 0; j < DES_KEY_LEN && found == true; j++) {
+                if (WEAK_KEYS[i][j] != key[j+offset]) {
+                    found = false;
+                }
+            }
+            if (found == true) {
+                return found;
+            }
+        }
+        return false;
+    }
+}
diff --git a/javax/crypto/spec/DESedeKeySpec.java b/javax/crypto/spec/DESedeKeySpec.java
new file mode 100644
index 0000000..32454de
--- /dev/null
+++ b/javax/crypto/spec/DESedeKeySpec.java
@@ -0,0 +1,126 @@
+/*
+ * 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 javax.crypto.spec;
+
+import java.security.InvalidKeyException;
+
+/**
+ * This class specifies a DES-EDE ("triple-DES") key.
+ *
+ * @author Jan Luehe
+ *
+ * @since 1.4
+ */
+public class DESedeKeySpec implements java.security.spec.KeySpec {
+
+    /**
+     * The constant which defines the length of a DESede key in bytes.
+     */
+    public static final int DES_EDE_KEY_LEN = 24;
+
+    private byte[] key;
+
+    /**
+     * Creates a DESedeKeySpec object using the first 24 bytes in
+     * <code>key</code> as the key material for the DES-EDE key.
+     *
+     * <p> The bytes that constitute the DES-EDE key are those between
+     * <code>key[0]</code> and <code>key[23]</code> inclusive
+     *
+     * @param key the buffer with the DES-EDE key material. The first
+     * 24 bytes of the buffer are copied to protect against subsequent
+     * modification.
+     *
+     * @exception NullPointerException if <code>key</code> is null.
+     * @exception InvalidKeyException if the given key material is shorter
+     * than 24 bytes.
+     */
+    public DESedeKeySpec(byte[] key) throws InvalidKeyException {
+        this(key, 0);
+    }
+
+    /**
+     * Creates a DESedeKeySpec object using the first 24 bytes in
+     * <code>key</code>, beginning at <code>offset</code> inclusive,
+     * as the key material for the DES-EDE key.
+     *
+     * <p> The bytes that constitute the DES-EDE key are those between
+     * <code>key[offset]</code> and <code>key[offset+23]</code> inclusive.
+     *
+     * @param key the buffer with the DES-EDE key material. The first
+     * 24 bytes of the buffer beginning at <code>offset</code> inclusive
+     * are copied to protect against subsequent modification.
+     * @param offset the offset in <code>key</code>, where the DES-EDE key
+     * material starts.
+     *
+     * @exception NullPointerException if <code>key</code> is null.
+     * @exception InvalidKeyException if the given key material, starting at
+     * <code>offset</code> inclusive, is shorter than 24 bytes
+     */
+    public DESedeKeySpec(byte[] key, int offset) throws InvalidKeyException {
+        if (key.length - offset < 24) {
+            throw new InvalidKeyException("Wrong key size");
+        }
+        this.key = new byte[24];
+        System.arraycopy(key, offset, this.key, 0, 24);
+    }
+
+    /**
+     * Returns the DES-EDE key.
+     *
+     * @return the DES-EDE key. Returns a new array
+     * each time this method is called.
+     */
+    public byte[] getKey() {
+        return this.key.clone();
+    }
+
+    /**
+     * Checks if the given DES-EDE key, starting at <code>offset</code>
+     * inclusive, is parity-adjusted.
+     *
+     * @param key    a byte array which holds the key value
+     * @param offset the offset into the byte array
+     * @return true if the given DES-EDE key is parity-adjusted, false
+     * otherwise
+     *
+     * @exception NullPointerException if <code>key</code> is null.
+     * @exception InvalidKeyException if the given key material, starting at
+     * <code>offset</code> inclusive, is shorter than 24 bytes
+     */
+    public static boolean isParityAdjusted(byte[] key, int offset)
+        throws InvalidKeyException {
+            if (key.length - offset < 24) {
+                throw new InvalidKeyException("Wrong key size");
+            }
+            if (DESKeySpec.isParityAdjusted(key, offset) == false
+                || DESKeySpec.isParityAdjusted(key, offset + 8) == false
+                || DESKeySpec.isParityAdjusted(key, offset + 16) == false) {
+                return false;
+            }
+            return true;
+    }
+}
diff --git a/javax/crypto/spec/DHGenParameterSpec.java b/javax/crypto/spec/DHGenParameterSpec.java
new file mode 100644
index 0000000..d3b5cf4
--- /dev/null
+++ b/javax/crypto/spec/DHGenParameterSpec.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 1997, 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 javax.crypto.spec;
+
+import java.math.BigInteger;
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * This class specifies the set of parameters used for generating
+ * Diffie-Hellman (system) parameters for use in Diffie-Hellman key
+ * agreement. This is typically done by a central
+ * authority.
+ *
+ * <p> The central authority, after computing the parameters, must send this
+ * information to the parties looking to agree on a secret key.
+ *
+ * @author Jan Luehe
+ *
+ * @see DHParameterSpec
+ * @since 1.4
+ */
+public class DHGenParameterSpec implements AlgorithmParameterSpec {
+
+    // The size in bits of the prime modulus
+    private int primeSize;
+
+    // The size in bits of the random exponent (private value)
+    private int exponentSize;
+
+    /**
+     * Constructs a parameter set for the generation of Diffie-Hellman
+     * (system) parameters. The constructed parameter set can be used to
+     * initialize an
+     * {@link java.security.AlgorithmParameterGenerator AlgorithmParameterGenerator}
+     * object for the generation of Diffie-Hellman parameters.
+     *
+     * @param primeSize the size (in bits) of the prime modulus.
+     * @param exponentSize the size (in bits) of the random exponent.
+     */
+    public DHGenParameterSpec(int primeSize, int exponentSize) {
+        this.primeSize = primeSize;
+        this.exponentSize = exponentSize;
+    }
+
+    /**
+     * Returns the size in bits of the prime modulus.
+     *
+     * @return the size in bits of the prime modulus
+     */
+    public int getPrimeSize() {
+        return this.primeSize;
+    }
+
+    /**
+     * Returns the size in bits of the random exponent (private value).
+     *
+     * @return the size in bits of the random exponent (private value)
+     */
+    public int getExponentSize() {
+        return this.exponentSize;
+    }
+}
diff --git a/javax/crypto/spec/DHParameterSpec.java b/javax/crypto/spec/DHParameterSpec.java
new file mode 100644
index 0000000..4d113ec
--- /dev/null
+++ b/javax/crypto/spec/DHParameterSpec.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 1997, 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 javax.crypto.spec;
+
+import java.math.BigInteger;
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * This class specifies the set of parameters used with the Diffie-Hellman
+ * algorithm, as specified in PKCS #3: <i>Diffie-Hellman Key-Agreement
+ * Standard</i>.
+ *
+ * <p>A central authority generates parameters and gives them to the two
+ * entities seeking to generate a secret key. The parameters are a prime
+ * <code>p</code>, a base <code>g</code>, and optionally the length
+ * in bits of the private value, <code>l</code>.
+ *
+ * <p>It is possible that more than one instance of parameters may be
+ * generated by a given central authority, and that there may be more than
+ * one central authority. Indeed, each individual may be its own central
+ * authority, with different entities having different parameters.
+ *
+ * <p>Note that this class does not perform any validation on specified
+ * parameters. Thus, the specified values are returned directly even
+ * if they are null.
+ *
+ * @author Jan Luehe
+ *
+ * @see javax.crypto.KeyAgreement
+ * @since 1.4
+ */
+public class DHParameterSpec implements AlgorithmParameterSpec {
+
+    // The prime modulus
+    private BigInteger p;
+
+    // The base generator
+    private BigInteger g;
+
+    // The size in bits of the random exponent (private value) (optional)
+    private int l;
+
+    /**
+     * Constructs a parameter set for Diffie-Hellman, using a prime modulus
+     * <code>p</code> and a base generator <code>g</code>.
+     *
+     * @param p the prime modulus
+     * @param g the base generator
+     */
+    public DHParameterSpec(BigInteger p, BigInteger g) {
+        this.p = p;
+        this.g = g;
+        this.l = 0;
+    }
+
+    /**
+     * Constructs a parameter set for Diffie-Hellman, using a prime modulus
+     * <code>p</code>, a base generator <code>g</code>,
+     * and the size in bits, <code>l</code>, of the random exponent
+     * (private value).
+     *
+     * @param p the prime modulus
+     * @param g the base generator
+     * @param l the size in bits of the random exponent (private value)
+     */
+    public DHParameterSpec(BigInteger p, BigInteger g, int l) {
+        this.p = p;
+        this.g = g;
+        this.l = l;
+    }
+
+    /**
+     * Returns the prime modulus <code>p</code>.
+     *
+     * @return the prime modulus <code>p</code>
+     */
+    public BigInteger getP() {
+        return this.p;
+    }
+
+    /**
+     * Returns the base generator <code>g</code>.
+     *
+     * @return the base generator <code>g</code>
+     */
+    public BigInteger getG() {
+        return this.g;
+    }
+
+    /**
+     * Returns the size in bits, <code>l</code>, of the random exponent
+     * (private value).
+     *
+     * @return the size in bits, <code>l</code>, of the random exponent
+     * (private value), or 0 if this size has not been set
+     */
+    public int getL() {
+        return this.l;
+    }
+}
diff --git a/javax/crypto/spec/DHPrivateKeySpec.java b/javax/crypto/spec/DHPrivateKeySpec.java
new file mode 100644
index 0000000..5842bbc
--- /dev/null
+++ b/javax/crypto/spec/DHPrivateKeySpec.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 1997, 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 javax.crypto.spec;
+
+import java.math.BigInteger;
+
+/**
+ * This class specifies a Diffie-Hellman private key with its associated
+ * parameters.
+ *
+ * <p>Note that this class does not perform any validation on specified
+ * parameters. Thus, the specified values are returned directly even
+ * if they are null.
+ *
+ * @author Jan Luehe
+ *
+ * @see DHPublicKeySpec
+ * @since 1.4
+ */
+public class DHPrivateKeySpec implements java.security.spec.KeySpec {
+
+    // The private value
+    private BigInteger x;
+
+    // The prime modulus
+    private BigInteger p;
+
+    // The base generator
+    private BigInteger g;
+
+    /**
+     * Constructor that takes a private value <code>x</code>, a prime
+     * modulus <code>p</code>, and a base generator <code>g</code>.
+     * @param x private value x
+     * @param p prime modulus p
+     * @param g base generator g
+     */
+    public DHPrivateKeySpec(BigInteger x, BigInteger p, BigInteger g) {
+        this.x = x;
+        this.p = p;
+        this.g = g;
+    }
+
+    /**
+     * Returns the private value <code>x</code>.
+     *
+     * @return the private value <code>x</code>
+     */
+    public BigInteger getX() {
+        return this.x;
+    }
+
+    /**
+     * Returns the prime modulus <code>p</code>.
+     *
+     * @return the prime modulus <code>p</code>
+     */
+    public BigInteger getP() {
+        return this.p;
+    }
+
+    /**
+     * Returns the base generator <code>g</code>.
+     *
+     * @return the base generator <code>g</code>
+     */
+    public BigInteger getG() {
+        return this.g;
+    }
+}
diff --git a/javax/crypto/spec/DHPublicKeySpec.java b/javax/crypto/spec/DHPublicKeySpec.java
new file mode 100644
index 0000000..91baf7a
--- /dev/null
+++ b/javax/crypto/spec/DHPublicKeySpec.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 1997, 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 javax.crypto.spec;
+
+import java.math.BigInteger;
+
+/**
+ * This class specifies a Diffie-Hellman public key with its associated
+ * parameters.
+ *
+ * <p>Note that this class does not perform any validation on specified
+ * parameters. Thus, the specified values are returned directly even
+ * if they are null.
+ *
+ * @author Jan Luehe
+ *
+ * @see DHPrivateKeySpec
+ * @since 1.4
+ */
+public class DHPublicKeySpec implements java.security.spec.KeySpec {
+
+    // The public value
+    private BigInteger y;
+
+    // The prime modulus
+    private BigInteger p;
+
+    // The base generator
+    private BigInteger g;
+
+    /**
+     * Constructor that takes a public value <code>y</code>, a prime
+     * modulus <code>p</code>, and a base generator <code>g</code>.
+     * @param y  public value y
+     * @param p  prime modulus p
+     * @param g  base generator g
+     */
+    public DHPublicKeySpec(BigInteger y, BigInteger p, BigInteger g) {
+        this.y = y;
+        this.p = p;
+        this.g = g;
+    }
+
+    /**
+     * Returns the public value <code>y</code>.
+     *
+     * @return the public value <code>y</code>
+     */
+    public BigInteger getY() {
+        return this.y;
+    }
+
+    /**
+     * Returns the prime modulus <code>p</code>.
+     *
+     * @return the prime modulus <code>p</code>
+     */
+    public BigInteger getP() {
+        return this.p;
+    }
+
+    /**
+     * Returns the base generator <code>g</code>.
+     *
+     * @return the base generator <code>g</code>
+     */
+    public BigInteger getG() {
+        return this.g;
+    }
+}
diff --git a/javax/crypto/spec/GCMParameterSpec.java b/javax/crypto/spec/GCMParameterSpec.java
new file mode 100644
index 0000000..403205a
--- /dev/null
+++ b/javax/crypto/spec/GCMParameterSpec.java
@@ -0,0 +1,149 @@
+/*
+ * 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 javax.crypto.spec;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * Specifies the set of parameters required by a {@link
+ * javax.crypto.Cipher} using the Galois/Counter Mode (GCM) mode.
+ * <p>
+ * Simple block cipher modes (such as CBC) generally require only an
+ * initialization vector (such as {@code IvParameterSpec}),
+ * but GCM needs these parameters:
+ * <ul>
+ * <li>{@code IV}: Initialization Vector (IV) </li>
+ * <li>{@code tLen}: length (in bits) of authentication tag T</li>
+ * </ul>
+ * <p>
+ * In addition to the parameters described here, other GCM inputs/output
+ * (Additional Authenticated Data (AAD), Keys, block ciphers,
+ * plain/ciphertext and authentication tags) are handled in the {@code
+ * Cipher} class.
+ * <p>
+ * Please see <a href="http://www.ietf.org/rfc/rfc5116.txt"> RFC 5116
+ * </a> for more information on the Authenticated Encryption with
+ * Associated Data (AEAD) algorithm, and <a href=
+ * "http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf">
+ * NIST Special Publication 800-38D</a>, "NIST Recommendation for Block
+ * Cipher Modes of Operation:  Galois/Counter Mode (GCM) and GMAC."
+ * <p>
+ * The GCM specification states that {@code tLen} may only have the
+ * values {128, 120, 112, 104, 96}, or {64, 32} for certain
+ * applications.  Other values can be specified for this class, but not
+ * all CSP implementations will support them.
+ *
+ * @see javax.crypto.Cipher
+ *
+ * @since 1.7
+ */
+public class GCMParameterSpec implements AlgorithmParameterSpec {
+
+    // Initialization Vector.  Could use IvParameterSpec, but that
+    // would add extra copies.
+    private byte[] iv;
+
+    // Required Tag length (in bits).
+    private int tLen;
+
+    /**
+     * Constructs a GCMParameterSpec using the specified authentication
+     * tag bit-length and IV buffer.
+     *
+     * @param tLen the authentication tag length (in bits)
+     * @param src the IV source buffer.  The contents of the buffer are
+     * copied to protect against subsequent modification.
+     *
+     * @throws IllegalArgumentException if {@code tLen} is negative,
+     * or {@code src} is null.
+     */
+    public GCMParameterSpec(int tLen, byte[] src) {
+        if (src == null) {
+            throw new IllegalArgumentException("src array is null");
+        }
+
+        init(tLen, src, 0, src.length);
+    }
+
+    /**
+     * Constructs a GCMParameterSpec object using the specified
+     * authentication tag bit-length and a subset of the specified
+     * buffer as the IV.
+     *
+     * @param tLen the authentication tag length (in bits)
+     * @param src the IV source buffer.  The contents of the
+     * buffer are copied to protect against subsequent modification.
+     * @param offset the offset in {@code src} where the IV starts
+     * @param len the number of IV bytes
+     *
+     * @throws IllegalArgumentException if {@code tLen} is negative,
+     * {@code src} is null, {@code len} or {@code offset} is negative,
+     * or the sum of {@code offset} and {@code len} is greater than the
+     * length of the {@code src} byte array.
+     */
+    public GCMParameterSpec(int tLen, byte[] src, int offset, int len) {
+        init(tLen, src, offset, len);
+    }
+
+    /*
+     * Check input parameters.
+     */
+    private void init(int tLen, byte[] src, int offset, int len) {
+        if (tLen < 0) {
+            throw new IllegalArgumentException(
+                "Length argument is negative");
+        }
+        this.tLen = tLen;
+
+        // Input sanity check
+        if ((src == null) ||(len < 0) || (offset < 0)
+                || ((len + offset) > src.length)) {
+            throw new IllegalArgumentException("Invalid buffer arguments");
+        }
+
+        iv = new byte[len];
+        System.arraycopy(src, offset, iv, 0, len);
+    }
+
+    /**
+     * Returns the authentication tag length.
+     *
+     * @return the authentication tag length (in bits)
+     */
+    public int getTLen() {
+        return tLen;
+    }
+
+    /**
+     * Returns the Initialization Vector (IV).
+     *
+     * @return the IV.  Creates a new array each time this method
+     * is called.
+     */
+    public byte[] getIV() {
+        return iv.clone();
+    }
+}
diff --git a/javax/crypto/spec/IvParameterSpec.java b/javax/crypto/spec/IvParameterSpec.java
new file mode 100644
index 0000000..243c848
--- /dev/null
+++ b/javax/crypto/spec/IvParameterSpec.java
@@ -0,0 +1,99 @@
+/*
+ * 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 javax.crypto.spec;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * This class specifies an <i>initialization vector</i> (IV).
+ * Examples which use IVs are ciphers in feedback mode,
+ * e.g., DES in CBC mode and RSA ciphers with OAEP encoding
+ * operation.
+ *
+ * @author Jan Luehe
+ *
+ * @since 1.4
+ */
+public class IvParameterSpec implements AlgorithmParameterSpec {
+
+    private byte[] iv;
+
+    /**
+     * Creates an IvParameterSpec object using the bytes in <code>iv</code>
+     * as the IV.
+     *
+     * @param iv the buffer with the IV. The contents of the
+     * buffer are copied to protect against subsequent modification.
+     * @throws NullPointerException if <code>iv</code> is <code>null</code>
+     */
+    public IvParameterSpec(byte[] iv) {
+        this(iv, 0, iv.length);
+    }
+
+    /**
+     * Creates an IvParameterSpec object using the first <code>len</code>
+     * bytes in <code>iv</code>, beginning at <code>offset</code>
+     * inclusive, as the IV.
+     *
+     * <p> The bytes that constitute the IV are those between
+     * <code>iv[offset]</code> and <code>iv[offset+len-1]</code> inclusive.
+     *
+     * @param iv the buffer with the IV. The first <code>len</code>
+     * bytes of the buffer beginning at <code>offset</code> inclusive
+     * are copied to protect against subsequent modification.
+     * @param offset the offset in <code>iv</code> where the IV
+     * starts.
+     * @param len the number of IV bytes.
+     * @throws IllegalArgumentException if <code>iv</code> is <code>null</code>
+     * or {@code (iv.length - offset < len)}
+     * @throws ArrayIndexOutOfBoundsException is thrown if <code>offset</code>
+     * or <code>len</code> index bytes outside the <code>iv</code>.
+     */
+    public IvParameterSpec(byte[] iv, int offset, int len) {
+        if (iv == null) {
+            throw new IllegalArgumentException("IV missing");
+        }
+        if (iv.length - offset < len) {
+            throw new IllegalArgumentException
+                ("IV buffer too short for given offset/length combination");
+        }
+        if (len < 0) {
+            throw new ArrayIndexOutOfBoundsException("len is negative");
+        }
+        this.iv = new byte[len];
+        System.arraycopy(iv, offset, this.iv, 0, len);
+    }
+
+    /**
+     * Returns the initialization vector (IV).
+     *
+     * @return the initialization vector (IV). Returns a new array
+     * each time this method is called.
+     */
+    public byte[] getIV() {
+        return this.iv.clone();
+    }
+}
diff --git a/javax/crypto/spec/OAEPParameterSpec.java b/javax/crypto/spec/OAEPParameterSpec.java
new file mode 100644
index 0000000..fcdc018
--- /dev/null
+++ b/javax/crypto/spec/OAEPParameterSpec.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2003, 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 javax.crypto.spec;
+
+import java.math.BigInteger;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.MGF1ParameterSpec;
+
+/**
+ * This class specifies the set of parameters used with OAEP Padding,
+ * as defined in the
+ * <a href="http://www.ietf.org/rfc/rfc3447.txt">PKCS #1</a>
+ * standard.
+ *
+ * Its ASN.1 definition in PKCS#1 standard is described below:
+ * <pre>
+ * RSAES-OAEP-params ::= SEQUENCE {
+ *   hashAlgorithm      [0] OAEP-PSSDigestAlgorithms     DEFAULT sha1,
+ *   maskGenAlgorithm   [1] PKCS1MGFAlgorithms  DEFAULT mgf1SHA1,
+ *   pSourceAlgorithm   [2] PKCS1PSourceAlgorithms  DEFAULT pSpecifiedEmpty
+ * }
+ * </pre>
+ * where
+ * <pre>
+ * OAEP-PSSDigestAlgorithms    ALGORITHM-IDENTIFIER ::= {
+ *   { OID id-sha1 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 --
+ * }
+ * PKCS1PSourceAlgorithms    ALGORITHM-IDENTIFIER ::= {
+ *   { OID id-pSpecified PARAMETERS OCTET STRING },
+ *   ...  -- Allows for future expansion --
+ * }
+ * </pre>
+ * <p>Note: the OAEPParameterSpec.DEFAULT uses the following:
+ *     message digest  -- "SHA-1"
+ *     mask generation function (mgf) -- "MGF1"
+ *     parameters for mgf -- MGF1ParameterSpec.SHA1
+ *     source of encoding input -- PSource.PSpecified.DEFAULT
+ *
+ * @see java.security.spec.MGF1ParameterSpec
+ * @see PSource
+ *
+ * @author Valerie Peng
+ *
+ * @since 1.5
+ */
+public class OAEPParameterSpec implements AlgorithmParameterSpec {
+
+    private String mdName = "SHA-1";
+    private String mgfName = "MGF1";
+    private AlgorithmParameterSpec mgfSpec = MGF1ParameterSpec.SHA1;
+    private PSource pSrc = PSource.PSpecified.DEFAULT;
+
+    /**
+     * The OAEP parameter set with all default values.
+     */
+    public static final OAEPParameterSpec DEFAULT = new OAEPParameterSpec();
+
+    /**
+     * Constructs a parameter set for OAEP padding as defined in
+     * the PKCS #1 standard using the default values.
+     */
+    private OAEPParameterSpec() {
+    }
+
+    /**
+     * Constructs a parameter set for OAEP padding as defined in
+     * the PKCS #1 standard using the specified message digest
+     * algorithm <code>mdName</code>, mask generation function
+     * algorithm <code>mgfName</code>, parameters for the mask
+     * generation function <code>mgfSpec</code>, and source of
+     * the encoding input P <code>pSrc</code>.
+     *
+     * @param mdName the algorithm name for the message digest.
+     * @param mgfName the algorithm name for the mask generation
+     * function.
+     * @param mgfSpec the parameters for the mask generation function.
+     * If null is specified, null will be returned by getMGFParameters().
+     * @param pSrc the source of the encoding input P.
+     * @exception NullPointerException if <code>mdName</code>,
+     * <code>mgfName</code>, or <code>pSrc</code> is null.
+     */
+    public OAEPParameterSpec(String mdName, String mgfName,
+                             AlgorithmParameterSpec mgfSpec,
+                             PSource pSrc) {
+        if (mdName == null) {
+            throw new NullPointerException("digest algorithm is null");
+        }
+        if (mgfName == null) {
+            throw new NullPointerException("mask generation function " +
+                                           "algorithm is null");
+        }
+        if (pSrc == null) {
+            throw new NullPointerException("source of the encoding input " +
+                                           "is null");
+        }
+        this.mdName =  mdName;
+        this.mgfName =  mgfName;
+        this.mgfSpec =  mgfSpec;
+        this.pSrc =  pSrc;
+    }
+
+    /**
+     * Returns the message digest algorithm name.
+     *
+     * @return the message digest algorithm name.
+     */
+    public String getDigestAlgorithm() {
+        return mdName;
+    }
+
+    /**
+     * Returns the mask generation function algorithm name.
+     *
+     * @return the mask generation function algorithm name.
+     */
+    public String getMGFAlgorithm() {
+        return mgfName;
+    }
+
+    /**
+     * Returns the parameters for the mask generation function.
+     *
+     * @return the parameters for the mask generation function.
+     */
+    public AlgorithmParameterSpec getMGFParameters() {
+        return mgfSpec;
+    }
+
+    /**
+     * Returns the source of encoding input P.
+     *
+     * @return the source of encoding input P.
+     */
+    public PSource getPSource() {
+        return pSrc;
+    }
+}
diff --git a/javax/crypto/spec/PBEKeySpec.java b/javax/crypto/spec/PBEKeySpec.java
new file mode 100644
index 0000000..239231d
--- /dev/null
+++ b/javax/crypto/spec/PBEKeySpec.java
@@ -0,0 +1,240 @@
+/*
+ * 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 javax.crypto.spec;
+
+import java.security.spec.KeySpec;
+
+/**
+ * A user-chosen password that can be used with password-based encryption
+ * (<i>PBE</i>).
+ *
+ * <p>The password can be viewed as some kind of raw key material, from which
+ * the encryption mechanism that uses it derives a cryptographic key.
+ *
+ * <p>Different PBE mechanisms may consume different bits of each password
+ * character. For example, the PBE mechanism defined in
+ * <a href="http://www.ietf.org/rfc/rfc2898.txt">
+ * PKCS #5</a> looks at only the low order 8 bits of each character, whereas
+ * PKCS #12 looks at all 16 bits of each character.
+ *
+ * <p>You convert the password characters to a PBE key by creating an
+ * instance of the appropriate secret-key factory. For example, a secret-key
+ * factory for PKCS #5 will construct a PBE key from only the low order 8 bits
+ * of each password character, whereas a secret-key factory for PKCS #12 will
+ * take all 16 bits of each character.
+ *
+ * <p>Also note that this class stores passwords as char arrays instead of
+ * <code>String</code> objects (which would seem more logical), because the
+ * String class is immutable and there is no way to overwrite its
+ * internal value when the password stored in it is no longer needed. Hence,
+ * this class requests the password as a char array, so it can be overwritten
+ * when done.
+ *
+ * @author Jan Luehe
+ * @author Valerie Peng
+ *
+ * @see javax.crypto.SecretKeyFactory
+ * @see PBEParameterSpec
+ * @since 1.4
+ */
+public class PBEKeySpec implements KeySpec {
+
+    private char[] password;
+    private byte[] salt = null;
+    private int iterationCount = 0;
+    private int keyLength = 0;
+
+    /**
+     * Constructor that takes a password. An empty char[] is used if
+     * null is specified.
+     *
+     * <p> Note: <code>password</code> is cloned before it is stored in
+     * the new <code>PBEKeySpec</code> object.
+     *
+     * @param password the password.
+     */
+    public PBEKeySpec(char[] password) {
+        if ((password == null) || (password.length == 0)) {
+            this.password = new char[0];
+        } else {
+            this.password = password.clone();
+        }
+    }
+
+
+    /**
+     * Constructor that takes a password, salt, iteration count, and
+     * to-be-derived key length for generating PBEKey of variable-key-size
+     * PBE ciphers.  An empty char[] is used if null is specified for
+     * <code>password</code>.
+     *
+     * <p> Note: the <code>password</code> and <code>salt</code>
+     * are cloned before they are stored in
+     * the new <code>PBEKeySpec</code> object.
+     *
+     * @param password the password.
+     * @param salt the salt.
+     * @param iterationCount the iteration count.
+     * @param keyLength the to-be-derived key length.
+     * @exception NullPointerException if <code>salt</code> is null.
+     * @exception IllegalArgumentException if <code>salt</code> is empty,
+     * i.e. 0-length, <code>iterationCount</code> or
+     * <code>keyLength</code> is not positive.
+     */
+    public PBEKeySpec(char[] password, byte[] salt, int iterationCount,
+        int keyLength) {
+        if ((password == null) || (password.length == 0)) {
+            this.password = new char[0];
+        } else {
+            this.password = password.clone();
+        }
+        if (salt == null) {
+            throw new NullPointerException("the salt parameter " +
+                                            "must be non-null");
+        } else if (salt.length == 0) {
+            throw new IllegalArgumentException("the salt parameter " +
+                                                "must not be empty");
+        } else {
+            this.salt = salt.clone();
+        }
+        if (iterationCount<=0) {
+            throw new IllegalArgumentException("invalid iterationCount value");
+        }
+        if (keyLength<=0) {
+            throw new IllegalArgumentException("invalid keyLength value");
+        }
+        this.iterationCount = iterationCount;
+        this.keyLength = keyLength;
+    }
+
+
+    /**
+     * Constructor that takes a password, salt, iteration count for
+     * generating PBEKey of fixed-key-size PBE ciphers. An empty
+     * char[] is used if null is specified for <code>password</code>.
+     *
+     * <p> Note: the <code>password</code> and <code>salt</code>
+     * are cloned before they are stored in the new
+     * <code>PBEKeySpec</code> object.
+     *
+     * @param password the password.
+     * @param salt the salt.
+     * @param iterationCount the iteration count.
+     * @exception NullPointerException if <code>salt</code> is null.
+     * @exception IllegalArgumentException if <code>salt</code> is empty,
+     * i.e. 0-length, or <code>iterationCount</code> is not positive.
+     */
+    public PBEKeySpec(char[] password, byte[] salt, int iterationCount) {
+        if ((password == null) || (password.length == 0)) {
+            this.password = new char[0];
+        } else {
+            this.password = password.clone();
+        }
+        if (salt == null) {
+            throw new NullPointerException("the salt parameter " +
+                                            "must be non-null");
+        } else if (salt.length == 0) {
+            throw new IllegalArgumentException("the salt parameter " +
+                                                "must not be empty");
+        } else {
+            this.salt = salt.clone();
+        }
+        if (iterationCount<=0) {
+            throw new IllegalArgumentException("invalid iterationCount value");
+        }
+        this.iterationCount = iterationCount;
+    }
+
+    /**
+     * Clears the internal copy of the password.
+     *
+     */
+    public final void clearPassword() {
+        if (password != null) {
+            for (int i = 0; i < password.length; i++) {
+                password[i] = ' ';
+            }
+            password = null;
+        }
+    }
+
+    /**
+     * Returns a copy of the password.
+     *
+     * <p> Note: this method returns a copy of the password. It is
+     * the caller's responsibility to zero out the password information after
+     * it is no longer needed.
+     *
+     * @exception IllegalStateException if password has been cleared by
+     * calling <code>clearPassword</code> method.
+     * @return the password.
+     */
+    public final char[] getPassword() {
+        if (password == null) {
+            throw new IllegalStateException("password has been cleared");
+        }
+        return password.clone();
+    }
+
+    /**
+     * Returns a copy of the salt or null if not specified.
+     *
+     * <p> Note: this method should return a copy of the salt. It is
+     * the caller's responsibility to zero out the salt information after
+     * it is no longer needed.
+     *
+     * @return the salt.
+     */
+    public final byte[] getSalt() {
+        if (salt != null) {
+            return salt.clone();
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Returns the iteration count or 0 if not specified.
+     *
+     * @return the iteration count.
+     */
+    public final int getIterationCount() {
+        return iterationCount;
+    }
+
+    /**
+     * Returns the to-be-derived key length or 0 if not specified.
+     *
+     * <p> Note: this is used to indicate the preference on key length
+     * for variable-key-size ciphers. The actual key size depends on
+     * each provider's implementation.
+     *
+     * @return the to-be-derived key length.
+     */
+    public final int getKeyLength() {
+        return keyLength;
+    }
+}
diff --git a/javax/crypto/spec/PBEParameterSpec.java b/javax/crypto/spec/PBEParameterSpec.java
new file mode 100644
index 0000000..ca45c73
--- /dev/null
+++ b/javax/crypto/spec/PBEParameterSpec.java
@@ -0,0 +1,109 @@
+/*
+ * 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 javax.crypto.spec;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * This class specifies the set of parameters used with password-based
+ * encryption (PBE), as defined in the
+ * <a href="http://www.ietf.org/rfc/rfc2898.txt">PKCS #5</a>
+ * standard.
+ *
+ * @author Jan Luehe
+ *
+ * @since 1.4
+ */
+public class PBEParameterSpec implements AlgorithmParameterSpec {
+
+    private byte[] salt;
+    private int iterationCount;
+    private AlgorithmParameterSpec paramSpec = null;
+
+    /**
+     * Constructs a parameter set for password-based encryption as defined in
+     * the PKCS #5 standard.
+     *
+     * @param salt the salt. The contents of <code>salt</code> are copied
+     * to protect against subsequent modification.
+     * @param iterationCount the iteration count.
+     * @exception NullPointerException if <code>salt</code> is null.
+     */
+    public PBEParameterSpec(byte[] salt, int iterationCount) {
+        this.salt = salt.clone();
+        this.iterationCount = iterationCount;
+    }
+
+    /**
+     * Constructs a parameter set for password-based encryption as defined in
+     * the PKCS #5 standard.
+     *
+     * @param salt the salt. The contents of <code>salt</code> are copied
+     * to protect against subsequent modification.
+     * @param iterationCount the iteration count.
+     * @param paramSpec the cipher algorithm parameter specification, which
+     * may be null.
+     * @exception NullPointerException if <code>salt</code> is null.
+     *
+     * @since 1.8
+     */
+    public PBEParameterSpec(byte[] salt, int iterationCount,
+            AlgorithmParameterSpec paramSpec) {
+        this.salt = salt.clone();
+        this.iterationCount = iterationCount;
+        this.paramSpec = paramSpec;
+    }
+
+    /**
+     * Returns the salt.
+     *
+     * @return the salt. Returns a new array
+     * each time this method is called.
+     */
+    public byte[] getSalt() {
+        return this.salt.clone();
+    }
+
+    /**
+     * Returns the iteration count.
+     *
+     * @return the iteration count
+     */
+    public int getIterationCount() {
+        return this.iterationCount;
+    }
+
+    /**
+     * Returns the cipher algorithm parameter specification.
+     *
+     * @return the parameter specification, or null if none was set.
+     *
+     * @since 1.8
+     */
+    public AlgorithmParameterSpec getParameterSpec() {
+        return this.paramSpec;
+    }
+}
diff --git a/javax/crypto/spec/PSource.java b/javax/crypto/spec/PSource.java
new file mode 100644
index 0000000..a3d2efe
--- /dev/null
+++ b/javax/crypto/spec/PSource.java
@@ -0,0 +1,108 @@
+/*
+ * 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 javax.crypto.spec;
+
+/**
+ * This class specifies the source for encoding input P in OAEP Padding,
+ * as defined in the
+ * <a href="http://www.ietf.org/rfc/rfc3447.txt">PKCS #1</a>
+ * standard.
+ * <pre>
+ * PKCS1PSourceAlgorithms    ALGORITHM-IDENTIFIER ::= {
+ *   { OID id-pSpecified PARAMETERS OCTET STRING },
+ *   ...  -- Allows for future expansion --
+ * }
+ * </pre>
+ * @author Valerie Peng
+ *
+ * @since 1.5
+ */
+public class PSource {
+
+    private String pSrcName;
+
+    /**
+     * Constructs a source of the encoding input P for OAEP
+     * padding as defined in the PKCS #1 standard using the
+     * specified PSource algorithm.
+     * @param pSrcName the algorithm for the source of the
+     * encoding input P.
+     * @exception NullPointerException if <code>pSrcName</code>
+     * is null.
+     */
+    protected PSource(String pSrcName) {
+        if (pSrcName == null) {
+            throw new NullPointerException("pSource algorithm is null");
+        }
+        this.pSrcName = pSrcName;
+    }
+    /**
+     * Returns the PSource algorithm name.
+     *
+     * @return the PSource algorithm name.
+     */
+    public String getAlgorithm() {
+        return pSrcName;
+    }
+
+    /**
+     * This class is used to explicitly specify the value for
+     * encoding input P in OAEP Padding.
+     *
+     * @since 1.5
+     */
+    public static final class PSpecified extends PSource {
+
+        private byte[] p = new byte[0];
+
+        /**
+         * The encoding input P whose value equals byte[0].
+         */
+        public static final PSpecified DEFAULT = new PSpecified(new byte[0]);
+
+        /**
+         * Constructs the source explicitly with the specified
+         * value <code>p</code> as the encoding input P.
+         * Note:
+         * @param p the value of the encoding input. The contents
+         * of the array are copied to protect against subsequent
+         * modification.
+         * @exception NullPointerException if <code>p</code> is null.
+         */
+        public PSpecified(byte[] p) {
+            super("PSpecified");
+            this.p = p.clone();
+        }
+        /**
+         * Returns the value of encoding input P.
+         * @return the value of encoding input P. A new array is
+         * returned each time this method is called.
+         */
+        public byte[] getValue() {
+            return (p.length==0? p: p.clone());
+        }
+    }
+}
diff --git a/javax/crypto/spec/RC2ParameterSpec.java b/javax/crypto/spec/RC2ParameterSpec.java
new file mode 100644
index 0000000..766b317
--- /dev/null
+++ b/javax/crypto/spec/RC2ParameterSpec.java
@@ -0,0 +1,160 @@
+/*
+ * 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 javax.crypto.spec;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * This class specifies the parameters used with the
+ * <a href="http://www.ietf.org/rfc/rfc2268.txt"><i>RC2</i></a>
+ * algorithm.
+ *
+ * <p> The parameters consist of an effective key size and optionally
+ * an 8-byte initialization vector (IV) (only in feedback mode).
+ *
+ * <p> This class can be used to initialize a <code>Cipher</code> object that
+ * implements the <i>RC2</i> algorithm.
+ *
+ * @author Jan Luehe
+ *
+ * @since 1.4
+ */
+public class RC2ParameterSpec implements AlgorithmParameterSpec {
+
+    private byte[] iv = null;
+    private int effectiveKeyBits;
+
+    /**
+     * Constructs a parameter set for RC2 from the given effective key size
+     * (in bits).
+     *
+     * @param effectiveKeyBits the effective key size in bits.
+     */
+    public RC2ParameterSpec(int effectiveKeyBits) {
+        this.effectiveKeyBits = effectiveKeyBits;
+    }
+
+    /**
+     * Constructs a parameter set for RC2 from the given effective key size
+     * (in bits) and an 8-byte IV.
+     *
+     * <p> The bytes that constitute the IV are those between
+     * <code>iv[0]</code> and <code>iv[7]</code> inclusive.
+     *
+     * @param effectiveKeyBits the effective key size in bits.
+     * @param iv the buffer with the 8-byte IV. The first 8 bytes of
+     * the buffer are copied to protect against subsequent modification.
+     * @exception IllegalArgumentException if <code>iv</code> is null.
+     */
+    public RC2ParameterSpec(int effectiveKeyBits, byte[] iv) {
+        this(effectiveKeyBits, iv, 0);
+    }
+
+    /**
+     * Constructs a parameter set for RC2 from the given effective key size
+     * (in bits) and IV.
+     *
+     * <p> The IV is taken from <code>iv</code>, starting at
+     * <code>offset</code> inclusive.
+     * The bytes that constitute the IV are those between
+     * <code>iv[offset]</code> and <code>iv[offset+7]</code> inclusive.
+     *
+     * @param effectiveKeyBits the effective key size in bits.
+     * @param iv the buffer with the IV. The first 8 bytes
+     * of the buffer beginning at <code>offset</code> inclusive
+     * are copied to protect against subsequent modification.
+     * @param offset the offset in <code>iv</code> where the 8-byte IV
+     * starts.
+     * @exception IllegalArgumentException if <code>iv</code> is null.
+     */
+    public RC2ParameterSpec(int effectiveKeyBits, byte[] iv, int offset) {
+        this.effectiveKeyBits = effectiveKeyBits;
+        if (iv == null) throw new IllegalArgumentException("IV missing");
+        int blockSize = 8;
+        if (iv.length - offset < blockSize) {
+            throw new IllegalArgumentException("IV too short");
+        }
+        this.iv = new byte[blockSize];
+        System.arraycopy(iv, offset, this.iv, 0, blockSize);
+    }
+
+    /**
+     * Returns the effective key size in bits.
+     *
+     * @return the effective key size in bits.
+     */
+    public int getEffectiveKeyBits() {
+        return this.effectiveKeyBits;
+    }
+
+    /**
+     * Returns the IV or null if this parameter set does not contain an IV.
+     *
+     * @return the IV or null if this parameter set does not contain an IV.
+     * Returns a new array each time this method is called.
+     */
+    public byte[] getIV() {
+        return (iv == null? null:iv.clone());
+    }
+
+   /**
+     * Tests for equality between the specified object and this
+     * object. Two RC2ParameterSpec objects are considered equal if their
+     * effective key sizes and IVs are equal.
+     * (Two IV references are considered equal if both are <tt>null</tt>.)
+     *
+     * @param obj the object to test for equality with this object.
+     *
+     * @return true if the objects are considered equal, false if
+     * <code>obj</code> is null or otherwise.
+     */
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (!(obj instanceof RC2ParameterSpec)) {
+            return false;
+        }
+        RC2ParameterSpec other = (RC2ParameterSpec) obj;
+
+        return ((effectiveKeyBits == other.effectiveKeyBits) &&
+                java.util.Arrays.equals(iv, other.iv));
+    }
+
+    /**
+     * Calculates a hash code value for the object.
+     * Objects that are equal will also have the same hashcode.
+     */
+    public int hashCode() {
+        int retval = 0;
+        if (iv != null) {
+            for (int i = 1; i < iv.length; i++) {
+                retval += iv[i] * i;
+            }
+        }
+        return (retval += effectiveKeyBits);
+    }
+}
diff --git a/javax/crypto/spec/RC5ParameterSpec.java b/javax/crypto/spec/RC5ParameterSpec.java
new file mode 100644
index 0000000..0eddb61
--- /dev/null
+++ b/javax/crypto/spec/RC5ParameterSpec.java
@@ -0,0 +1,203 @@
+/*
+ * 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 javax.crypto.spec;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * This class specifies the parameters used with the
+ * <a href="http://www.ietf.org/rfc/rfc2040.txt"><i>RC5</i></a>
+ * algorithm.
+ *
+ * <p> The parameters consist of a version number, a rounds count, a word
+ * size, and optionally an initialization vector (IV) (only in feedback mode).
+ *
+ * <p> This class can be used to initialize a <code>Cipher</code> object that
+ * implements the <i>RC5</i> algorithm as supplied by
+ * <a href="http://www.rsasecurity.com">RSA Security Inc.</a>,
+ * or any parties authorized by RSA Security.
+ *
+ * @author Jan Luehe
+ *
+ * @since 1.4
+ */
+public class RC5ParameterSpec implements AlgorithmParameterSpec {
+
+    private byte[] iv = null;
+    private int version;
+    private int rounds;
+    private int wordSize; // the word size in bits
+
+    /**
+     * Constructs a parameter set for RC5 from the given version, number of
+     * rounds and word size (in bits).
+     *
+     * @param version the version.
+     * @param rounds the number of rounds.
+     * @param wordSize the word size in bits.
+     */
+    public RC5ParameterSpec(int version, int rounds, int wordSize) {
+        this.version = version;
+        this.rounds = rounds;
+        this.wordSize = wordSize;
+    }
+
+    /**
+     * Constructs a parameter set for RC5 from the given version, number of
+     * rounds, word size (in bits), and IV.
+     *
+     * <p> Note that the size of the IV (block size) must be twice the word
+     * size. The bytes that constitute the IV are those between
+     * <code>iv[0]</code> and <code>iv[2*(wordSize/8)-1]</code> inclusive.
+     *
+     * @param version the version.
+     * @param rounds the number of rounds.
+     * @param wordSize the word size in bits.
+     * @param iv the buffer with the IV. The first <code>2*(wordSize/8)
+     * </code> bytes of the buffer are copied to protect against subsequent
+     * modification.
+     * @exception IllegalArgumentException if <code>iv</code> is
+     * <code>null</code> or {@code (iv.length < 2 * (wordSize / 8))}
+     */
+    public RC5ParameterSpec(int version, int rounds, int wordSize, byte[] iv) {
+        this(version, rounds, wordSize, iv, 0);
+    }
+
+    /**
+     * Constructs a parameter set for RC5 from the given version, number of
+     * rounds, word size (in bits), and IV.
+     *
+     * <p> The IV is taken from <code>iv</code>, starting at
+     * <code>offset</code> inclusive.
+     * Note that the size of the IV (block size), starting at
+     * <code>offset</code> inclusive, must be twice the word size.
+     * The bytes that constitute the IV are those between
+     * <code>iv[offset]</code> and <code>iv[offset+2*(wordSize/8)-1]</code>
+     * inclusive.
+     *
+     * @param version the version.
+     * @param rounds the number of rounds.
+     * @param wordSize the word size in bits.
+     * @param iv the buffer with the IV. The first <code>2*(wordSize/8)
+     * </code> bytes of the buffer beginning at <code>offset</code>
+     * inclusive are copied to protect against subsequent modification.
+     * @param offset the offset in <code>iv</code> where the IV starts.
+     * @exception IllegalArgumentException if <code>iv</code> is
+     * <code>null</code> or
+     * {@code (iv.length - offset < 2 * (wordSize / 8))}
+     */
+    public RC5ParameterSpec(int version, int rounds, int wordSize,
+                            byte[] iv, int offset) {
+        this.version = version;
+        this.rounds = rounds;
+        this.wordSize = wordSize;
+        if (iv == null) throw new IllegalArgumentException("IV missing");
+        int blockSize = (wordSize / 8) * 2;
+        if (iv.length - offset < blockSize) {
+            throw new IllegalArgumentException("IV too short");
+        }
+        this.iv = new byte[blockSize];
+        System.arraycopy(iv, offset, this.iv, 0, blockSize);
+    }
+
+    /**
+     * Returns the version.
+     *
+     * @return the version.
+     */
+    public int getVersion() {
+        return this.version;
+    }
+
+    /**
+     * Returns the number of rounds.
+     *
+     * @return the number of rounds.
+     */
+    public int getRounds() {
+        return this.rounds;
+    }
+
+    /**
+     * Returns the word size in bits.
+     *
+     * @return the word size in bits.
+     */
+    public int getWordSize() {
+        return this.wordSize;
+    }
+
+    /**
+     * Returns the IV or null if this parameter set does not contain an IV.
+     *
+     * @return the IV or null if this parameter set does not contain an IV.
+     * Returns a new array each time this method is called.
+     */
+    public byte[] getIV() {
+        return (iv == null? null:iv.clone());
+    }
+
+   /**
+     * Tests for equality between the specified object and this
+     * object. Two RC5ParameterSpec objects are considered equal if their
+     * version numbers, number of rounds, word sizes, and IVs are equal.
+     * (Two IV references are considered equal if both are <tt>null</tt>.)
+     *
+     * @param obj the object to test for equality with this object.
+     *
+     * @return true if the objects are considered equal, false if
+     * <code>obj</code> is null or otherwise.
+     */
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (!(obj instanceof RC5ParameterSpec)) {
+            return false;
+        }
+        RC5ParameterSpec other = (RC5ParameterSpec) obj;
+
+        return ((version == other.version) &&
+                (rounds == other.rounds) &&
+                (wordSize == other.wordSize) &&
+                java.util.Arrays.equals(iv, other.iv));
+    }
+
+    /**
+     * Calculates a hash code value for the object.
+     * Objects that are equal will also have the same hashcode.
+     */
+    public int hashCode() {
+        int retval = 0;
+        if (iv != null) {
+            for (int i = 1; i < iv.length; i++) {
+                retval += iv[i] * i;
+            }
+        }
+        retval += (version + rounds + wordSize);
+        return retval;
+    }
+}
diff --git a/javax/crypto/spec/SecretKeySpec.java b/javax/crypto/spec/SecretKeySpec.java
new file mode 100644
index 0000000..767c0d2
--- /dev/null
+++ b/javax/crypto/spec/SecretKeySpec.java
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 1998, 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 javax.crypto.spec;
+
+import java.security.MessageDigest;
+import java.security.spec.KeySpec;
+import java.util.Locale;
+import javax.crypto.SecretKey;
+
+/**
+ * This class specifies a secret key in a provider-independent fashion.
+ *
+ * <p>It can be used to construct a <code>SecretKey</code> from a byte array,
+ * without having to go through a (provider-based)
+ * <code>SecretKeyFactory</code>.
+ *
+ * <p>This class is only useful for raw secret keys that can be represented as
+ * a byte array and have no key parameters associated with them, e.g., DES or
+ * Triple DES keys.
+ *
+ * @author Jan Luehe
+ *
+ * @see javax.crypto.SecretKey
+ * @see javax.crypto.SecretKeyFactory
+ * @since 1.4
+ */
+public class SecretKeySpec implements KeySpec, SecretKey {
+
+    private static final long serialVersionUID = 6577238317307289933L;
+
+    /**
+     * The secret key.
+     *
+     * @serial
+     */
+    private byte[] key;
+
+    /**
+     * The name of the algorithm associated with this key.
+     *
+     * @serial
+     */
+    private String algorithm;
+
+    /**
+     * Constructs a secret key from the given byte array.
+     *
+     * <p>This constructor does not check if the given bytes indeed specify a
+     * secret key of the specified algorithm. For example, if the algorithm is
+     * DES, this constructor does not check if <code>key</code> is 8 bytes
+     * long, and also does not check for weak or semi-weak keys.
+     * In order for those checks to be performed, an algorithm-specific
+     * <i>key specification</i> class (in this case:
+     * {@link DESKeySpec DESKeySpec})
+     * should be used.
+     *
+     * @param key the key material of the secret key. The contents of
+     * the array are copied to protect against subsequent modification.
+     * @param algorithm the name of the secret-key algorithm to be associated
+     * with the given key material.
+     * See Appendix A in the <a href=
+     *   "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
+     * Java Cryptography Architecture Reference Guide</a>
+     * for information about standard algorithm names.
+     * @exception IllegalArgumentException if <code>algorithm</code>
+     * is null or <code>key</code> is null or empty.
+     */
+    public SecretKeySpec(byte[] key, String algorithm) {
+        if (key == null || algorithm == null) {
+            throw new IllegalArgumentException("Missing argument");
+        }
+        if (key.length == 0) {
+            throw new IllegalArgumentException("Empty key");
+        }
+        this.key = key.clone();
+        this.algorithm = algorithm;
+    }
+
+    /**
+     * Constructs a secret key from the given byte array, using the first
+     * <code>len</code> bytes of <code>key</code>, starting at
+     * <code>offset</code> inclusive.
+     *
+     * <p> The bytes that constitute the secret key are
+     * those between <code>key[offset]</code> and
+     * <code>key[offset+len-1]</code> inclusive.
+     *
+     * <p>This constructor does not check if the given bytes indeed specify a
+     * secret key of the specified algorithm. For example, if the algorithm is
+     * DES, this constructor does not check if <code>key</code> is 8 bytes
+     * long, and also does not check for weak or semi-weak keys.
+     * In order for those checks to be performed, an algorithm-specific key
+     * specification class (in this case:
+     * {@link DESKeySpec DESKeySpec})
+     * must be used.
+     *
+     * @param key the key material of the secret key. The first
+     * <code>len</code> bytes of the array beginning at
+     * <code>offset</code> inclusive are copied to protect
+     * against subsequent modification.
+     * @param offset the offset in <code>key</code> where the key material
+     * starts.
+     * @param len the length of the key material.
+     * @param algorithm the name of the secret-key algorithm to be associated
+     * with the given key material.
+     * See Appendix A in the <a href=
+     *   "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
+     * Java Cryptography Architecture Reference Guide</a>
+     * for information about standard algorithm names.
+     * @exception IllegalArgumentException if <code>algorithm</code>
+     * is null or <code>key</code> is null, empty, or too short,
+     * i.e. {@code key.length-offset<len}.
+     * @exception ArrayIndexOutOfBoundsException is thrown if
+     * <code>offset</code> or <code>len</code> index bytes outside the
+     * <code>key</code>.
+     */
+    public SecretKeySpec(byte[] key, int offset, int len, String algorithm) {
+        if (key == null || algorithm == null) {
+            throw new IllegalArgumentException("Missing argument");
+        }
+        if (key.length == 0) {
+            throw new IllegalArgumentException("Empty key");
+        }
+        if (key.length-offset < len) {
+            throw new IllegalArgumentException
+                ("Invalid offset/length combination");
+        }
+        if (len < 0) {
+            throw new ArrayIndexOutOfBoundsException("len is negative");
+        }
+        this.key = new byte[len];
+        System.arraycopy(key, offset, this.key, 0, len);
+        this.algorithm = algorithm;
+    }
+
+    /**
+     * Returns the name of the algorithm associated with this secret key.
+     *
+     * @return the secret key algorithm.
+     */
+    public String getAlgorithm() {
+        return this.algorithm;
+    }
+
+    /**
+     * Returns the name of the encoding format for this secret key.
+     *
+     * @return the string "RAW".
+     */
+    public String getFormat() {
+        return "RAW";
+    }
+
+    /**
+     * Returns the key material of this secret key.
+     *
+     * @return the key material. Returns a new array
+     * each time this method is called.
+     */
+    public byte[] getEncoded() {
+        return this.key.clone();
+    }
+
+    /**
+     * Calculates a hash code value for the object.
+     * Objects that are equal will also have the same hashcode.
+     */
+    public int hashCode() {
+        int retval = 0;
+        for (int i = 1; i < this.key.length; i++) {
+            retval += this.key[i] * i;
+        }
+        if (this.algorithm.equalsIgnoreCase("TripleDES"))
+            return (retval ^= "desede".hashCode());
+        else
+            return (retval ^=
+                    this.algorithm.toLowerCase(Locale.ENGLISH).hashCode());
+    }
+
+   /**
+     * Tests for equality between the specified object and this
+     * object. Two SecretKeySpec objects are considered equal if
+     * they are both SecretKey instances which have the
+     * same case-insensitive algorithm name and key encoding.
+     *
+     * @param obj the object to test for equality with this object.
+     *
+     * @return true if the objects are considered equal, false if
+     * <code>obj</code> is null or otherwise.
+     */
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+
+        if (!(obj instanceof SecretKey))
+            return false;
+
+        String thatAlg = ((SecretKey)obj).getAlgorithm();
+        if (!(thatAlg.equalsIgnoreCase(this.algorithm))) {
+            if ((!(thatAlg.equalsIgnoreCase("DESede"))
+                 || !(this.algorithm.equalsIgnoreCase("TripleDES")))
+                && (!(thatAlg.equalsIgnoreCase("TripleDES"))
+                    || !(this.algorithm.equalsIgnoreCase("DESede"))))
+            return false;
+        }
+
+        byte[] thatKey = ((SecretKey)obj).getEncoded();
+
+        return MessageDigest.isEqual(this.key, thatKey);
+    }
+}
diff --git a/javax/microedition/khronos/egl/EGL.java b/javax/microedition/khronos/egl/EGL.java
new file mode 100644
index 0000000..18f8ae6
--- /dev/null
+++ b/javax/microedition/khronos/egl/EGL.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2006 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 javax.microedition.khronos.egl;
+
+public interface EGL {
+}
+
diff --git a/javax/microedition/khronos/egl/EGL10.java b/javax/microedition/khronos/egl/EGL10.java
new file mode 100644
index 0000000..ea571c7
--- /dev/null
+++ b/javax/microedition/khronos/egl/EGL10.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2006 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 javax.microedition.khronos.egl;
+
+import android.compat.annotation.UnsupportedAppUsage;
+
+public interface EGL10 extends EGL {
+    int EGL_SUCCESS                     = 0x3000;
+    int EGL_NOT_INITIALIZED             = 0x3001;
+    int EGL_BAD_ACCESS                  = 0x3002;
+    int EGL_BAD_ALLOC                   = 0x3003;
+    int EGL_BAD_ATTRIBUTE               = 0x3004;
+    int EGL_BAD_CONFIG                  = 0x3005;
+    int EGL_BAD_CONTEXT                 = 0x3006;
+    int EGL_BAD_CURRENT_SURFACE         = 0x3007;
+    int EGL_BAD_DISPLAY                 = 0x3008;
+    int EGL_BAD_MATCH                   = 0x3009;
+    int EGL_BAD_NATIVE_PIXMAP           = 0x300A;
+    int EGL_BAD_NATIVE_WINDOW           = 0x300B;
+    int EGL_BAD_PARAMETER               = 0x300C;
+    int EGL_BAD_SURFACE                 = 0x300D;
+    int EGL_BUFFER_SIZE                 = 0x3020;
+    int EGL_ALPHA_SIZE                  = 0x3021;
+    int EGL_BLUE_SIZE                   = 0x3022;
+    int EGL_GREEN_SIZE                  = 0x3023;
+    int EGL_RED_SIZE                    = 0x3024;
+    int EGL_DEPTH_SIZE                  = 0x3025;
+    int EGL_STENCIL_SIZE                = 0x3026;
+    int EGL_CONFIG_CAVEAT               = 0x3027;
+    int EGL_CONFIG_ID                   = 0x3028;
+    int EGL_LEVEL                       = 0x3029;
+    int EGL_MAX_PBUFFER_HEIGHT          = 0x302A;
+    int EGL_MAX_PBUFFER_PIXELS          = 0x302B;
+    int EGL_MAX_PBUFFER_WIDTH           = 0x302C;
+    int EGL_NATIVE_RENDERABLE           = 0x302D;
+    int EGL_NATIVE_VISUAL_ID            = 0x302E;
+    int EGL_NATIVE_VISUAL_TYPE          = 0x302F;
+    int EGL_SAMPLES                     = 0x3031;
+    int EGL_SAMPLE_BUFFERS              = 0x3032;
+    int EGL_SURFACE_TYPE                = 0x3033;
+    int EGL_TRANSPARENT_TYPE            = 0x3034;
+    int EGL_TRANSPARENT_BLUE_VALUE      = 0x3035;
+    int EGL_TRANSPARENT_GREEN_VALUE     = 0x3036;
+    int EGL_TRANSPARENT_RED_VALUE       = 0x3037;
+    int EGL_NONE                        = 0x3038;
+    int EGL_LUMINANCE_SIZE              = 0x303D;
+    int EGL_ALPHA_MASK_SIZE             = 0x303E;
+    int EGL_COLOR_BUFFER_TYPE           = 0x303F;
+    int EGL_RENDERABLE_TYPE             = 0x3040;
+    int EGL_SLOW_CONFIG                 = 0x3050;
+    int EGL_NON_CONFORMANT_CONFIG       = 0x3051;
+    int EGL_TRANSPARENT_RGB             = 0x3052;
+    int EGL_RGB_BUFFER                  = 0x308E;
+    int EGL_LUMINANCE_BUFFER            = 0x308F;
+    int EGL_VENDOR                      = 0x3053;
+    int EGL_VERSION                     = 0x3054;
+    int EGL_EXTENSIONS                  = 0x3055;
+    int EGL_HEIGHT                      = 0x3056;
+    int EGL_WIDTH                       = 0x3057;
+    int EGL_LARGEST_PBUFFER             = 0x3058;
+    int EGL_RENDER_BUFFER               = 0x3086;
+    int EGL_COLORSPACE                  = 0x3087;
+    int EGL_ALPHA_FORMAT                = 0x3088;
+    int EGL_HORIZONTAL_RESOLUTION       = 0x3090;
+    int EGL_VERTICAL_RESOLUTION         = 0x3091;
+    int EGL_PIXEL_ASPECT_RATIO          = 0x3092;
+    int EGL_SINGLE_BUFFER               = 0x3085;
+    int EGL_CORE_NATIVE_ENGINE          = 0x305B;
+    int EGL_DRAW                        = 0x3059;
+    int EGL_READ                        = 0x305A;
+
+    int EGL_DONT_CARE                   = -1;
+
+    int EGL_PBUFFER_BIT                 = 0x01;
+    int EGL_PIXMAP_BIT                  = 0x02;
+    int EGL_WINDOW_BIT                  = 0x04;
+
+    Object     EGL_DEFAULT_DISPLAY = null;
+    EGLDisplay EGL_NO_DISPLAY = new com.google.android.gles_jni.EGLDisplayImpl(0);
+    EGLContext EGL_NO_CONTEXT = new com.google.android.gles_jni.EGLContextImpl(0);
+    EGLSurface EGL_NO_SURFACE = new com.google.android.gles_jni.EGLSurfaceImpl(0);
+    
+    boolean     eglChooseConfig(EGLDisplay display, int[] attrib_list, EGLConfig[] configs, int config_size, int[] num_config);
+    boolean     eglCopyBuffers(EGLDisplay display, EGLSurface surface, Object native_pixmap);
+    EGLContext  eglCreateContext(EGLDisplay display, EGLConfig config, EGLContext share_context, int[] attrib_list);
+    EGLSurface  eglCreatePbufferSurface(EGLDisplay display, EGLConfig config, int[] attrib_list);
+    @Deprecated
+    EGLSurface  eglCreatePixmapSurface(EGLDisplay display, EGLConfig config, Object native_pixmap, int[] attrib_list);
+    EGLSurface  eglCreateWindowSurface(EGLDisplay display, EGLConfig config, Object native_window, int[] attrib_list);
+    boolean     eglDestroyContext(EGLDisplay display, EGLContext context);
+    boolean     eglDestroySurface(EGLDisplay display, EGLSurface surface);
+    boolean     eglGetConfigAttrib(EGLDisplay display, EGLConfig config, int attribute, int[] value);
+    boolean     eglGetConfigs(EGLDisplay display, EGLConfig[] configs, int config_size, int[] num_config);
+    EGLContext  eglGetCurrentContext();
+    EGLDisplay  eglGetCurrentDisplay();
+    EGLSurface  eglGetCurrentSurface(int readdraw);
+    EGLDisplay  eglGetDisplay(Object native_display);
+    int         eglGetError();
+    boolean     eglInitialize(EGLDisplay display, int[] major_minor);
+    boolean     eglMakeCurrent(EGLDisplay display, EGLSurface draw, EGLSurface read, EGLContext context);
+    boolean     eglQueryContext(EGLDisplay display, EGLContext context, int attribute, int[] value);
+    String      eglQueryString(EGLDisplay display, int name);
+    boolean     eglQuerySurface(EGLDisplay display, EGLSurface surface, int attribute, int[] value);
+    /** @hide **/
+    @UnsupportedAppUsage
+    boolean     eglReleaseThread();
+    boolean     eglSwapBuffers(EGLDisplay display, EGLSurface surface);
+    boolean     eglTerminate(EGLDisplay display);
+    boolean     eglWaitGL();
+    boolean     eglWaitNative(int engine, Object bindTarget);
+}
diff --git a/javax/microedition/khronos/egl/EGL11.java b/javax/microedition/khronos/egl/EGL11.java
new file mode 100644
index 0000000..41d62e6
--- /dev/null
+++ b/javax/microedition/khronos/egl/EGL11.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2006 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 javax.microedition.khronos.egl;
+
+public interface EGL11 extends EGL10 {
+    int EGL_CONTEXT_LOST                = 0x300E;
+}
diff --git a/javax/microedition/khronos/egl/EGLConfig.java b/javax/microedition/khronos/egl/EGLConfig.java
new file mode 100644
index 0000000..c8a9ba2
--- /dev/null
+++ b/javax/microedition/khronos/egl/EGLConfig.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2006 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 javax.microedition.khronos.egl;
+
+public abstract class EGLConfig
+{
+}
diff --git a/javax/microedition/khronos/egl/EGLContext.java b/javax/microedition/khronos/egl/EGLContext.java
new file mode 100644
index 0000000..f8d745d
--- /dev/null
+++ b/javax/microedition/khronos/egl/EGLContext.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2006 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 javax.microedition.khronos.egl;
+
+import javax.microedition.khronos.opengles.GL;
+
+public abstract class EGLContext
+{
+    private static final EGL EGL_INSTANCE = new com.google.android.gles_jni.EGLImpl();
+    
+    public static EGL getEGL() {
+        return EGL_INSTANCE;
+    }
+
+    public abstract GL getGL();
+}
diff --git a/javax/microedition/khronos/egl/EGLDisplay.java b/javax/microedition/khronos/egl/EGLDisplay.java
new file mode 100644
index 0000000..5368b4b
--- /dev/null
+++ b/javax/microedition/khronos/egl/EGLDisplay.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2006 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 javax.microedition.khronos.egl;
+
+public abstract class EGLDisplay
+{
+}
diff --git a/javax/microedition/khronos/egl/EGLSurface.java b/javax/microedition/khronos/egl/EGLSurface.java
new file mode 100644
index 0000000..e1d08d3
--- /dev/null
+++ b/javax/microedition/khronos/egl/EGLSurface.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2006 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 javax.microedition.khronos.egl;
+
+public abstract class EGLSurface
+{
+}
diff --git a/javax/microedition/khronos/opengles/GL.java b/javax/microedition/khronos/opengles/GL.java
new file mode 100644
index 0000000..3b78f3d
--- /dev/null
+++ b/javax/microedition/khronos/opengles/GL.java
@@ -0,0 +1,22 @@
+/* //device/java/android/javax/microedition/khronos/opengles/GL.java
+**
+** Copyright 2006, 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 javax.microedition.khronos.opengles;
+
+public interface GL {
+}
+
diff --git a/javax/microedition/khronos/opengles/GL10.java b/javax/microedition/khronos/opengles/GL10.java
new file mode 100644
index 0000000..4fcfb52
--- /dev/null
+++ b/javax/microedition/khronos/opengles/GL10.java
@@ -0,0 +1,972 @@
+/* //device/java/android/javax/microedition/khronos/opengles/GL10.java
+**
+** Copyright 2006, 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.
+*/
+
+// This source file is automatically generated
+
+package javax.microedition.khronos.opengles;
+
+public interface GL10 extends GL {
+    int GL_ADD                                   = 0x0104;
+    int GL_ALIASED_LINE_WIDTH_RANGE              = 0x846E;
+    int GL_ALIASED_POINT_SIZE_RANGE              = 0x846D;
+    int GL_ALPHA                                 = 0x1906;
+    int GL_ALPHA_BITS                            = 0x0D55;
+    int GL_ALPHA_TEST                            = 0x0BC0;
+    int GL_ALWAYS                                = 0x0207;
+    int GL_AMBIENT                               = 0x1200;
+    int GL_AMBIENT_AND_DIFFUSE                   = 0x1602;
+    int GL_AND                                   = 0x1501;
+    int GL_AND_INVERTED                          = 0x1504;
+    int GL_AND_REVERSE                           = 0x1502;
+    int GL_BACK                                  = 0x0405;
+    int GL_BLEND                                 = 0x0BE2;
+    int GL_BLUE_BITS                             = 0x0D54;
+    int GL_BYTE                                  = 0x1400;
+    int GL_CCW                                   = 0x0901;
+    int GL_CLAMP_TO_EDGE                         = 0x812F;
+    int GL_CLEAR                                 = 0x1500;
+    int GL_COLOR_ARRAY                           = 0x8076;
+    int GL_COLOR_BUFFER_BIT                      = 0x4000;
+    int GL_COLOR_LOGIC_OP                        = 0x0BF2;
+    int GL_COLOR_MATERIAL                        = 0x0B57;
+    int GL_COMPRESSED_TEXTURE_FORMATS            = 0x86A3;
+    int GL_CONSTANT_ATTENUATION                  = 0x1207;
+    int GL_COPY                                  = 0x1503;
+    int GL_COPY_INVERTED                         = 0x150C;
+    int GL_CULL_FACE                             = 0x0B44;
+    int GL_CW                                    = 0x0900;
+    int GL_DECAL                                 = 0x2101;
+    int GL_DECR                                  = 0x1E03;
+    int GL_DEPTH_BITS                            = 0x0D56;
+    int GL_DEPTH_BUFFER_BIT                      = 0x0100;
+    int GL_DEPTH_TEST                            = 0x0B71;
+    int GL_DIFFUSE                               = 0x1201;
+    int GL_DITHER                                = 0x0BD0;
+    int GL_DONT_CARE                             = 0x1100;
+    int GL_DST_ALPHA                             = 0x0304;
+    int GL_DST_COLOR                             = 0x0306;
+    int GL_EMISSION                              = 0x1600;
+    int GL_EQUAL                                 = 0x0202;
+    int GL_EQUIV                                 = 0x1509;
+    int GL_EXP                                   = 0x0800;
+    int GL_EXP2                                  = 0x0801;
+    int GL_EXTENSIONS                            = 0x1F03;
+    int GL_FALSE                                 = 0;
+    int GL_FASTEST                               = 0x1101;
+    int GL_FIXED                                 = 0x140C;
+    int GL_FLAT                                  = 0x1D00;
+    int GL_FLOAT                                 = 0x1406;
+    int GL_FOG                                   = 0x0B60;
+    int GL_FOG_COLOR                             = 0x0B66;
+    int GL_FOG_DENSITY                           = 0x0B62;
+    int GL_FOG_END                               = 0x0B64;
+    int GL_FOG_HINT                              = 0x0C54;
+    int GL_FOG_MODE                              = 0x0B65;
+    int GL_FOG_START                             = 0x0B63;
+    int GL_FRONT                                 = 0x0404;
+    int GL_FRONT_AND_BACK                        = 0x0408;
+    int GL_GEQUAL                                = 0x0206;
+    int GL_GREATER                               = 0x0204;
+    int GL_GREEN_BITS                            = 0x0D53;
+    int GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES  = 0x8B9B;
+    int GL_IMPLEMENTATION_COLOR_READ_TYPE_OES    = 0x8B9A;
+    int GL_INCR                                  = 0x1E02;
+    int GL_INVALID_ENUM                          = 0x0500;
+    int GL_INVALID_OPERATION                     = 0x0502;
+    int GL_INVALID_VALUE                         = 0x0501;
+    int GL_INVERT                                = 0x150A;
+    int GL_KEEP                                  = 0x1E00;
+    int GL_LEQUAL                                = 0x0203;
+    int GL_LESS                                  = 0x0201;
+    int GL_LIGHT_MODEL_AMBIENT                   = 0x0B53;
+    int GL_LIGHT_MODEL_TWO_SIDE                  = 0x0B52;
+    int GL_LIGHT0                                = 0x4000;
+    int GL_LIGHT1                                = 0x4001;
+    int GL_LIGHT2                                = 0x4002;
+    int GL_LIGHT3                                = 0x4003;
+    int GL_LIGHT4                                = 0x4004;
+    int GL_LIGHT5                                = 0x4005;
+    int GL_LIGHT6                                = 0x4006;
+    int GL_LIGHT7                                = 0x4007;
+    int GL_LIGHTING                              = 0x0B50;
+    int GL_LINE_LOOP                             = 0x0002;
+    int GL_LINE_SMOOTH                           = 0x0B20;
+    int GL_LINE_SMOOTH_HINT                      = 0x0C52;
+    int GL_LINE_STRIP                            = 0x0003;
+    int GL_LINEAR                                = 0x2601;
+    int GL_LINEAR_ATTENUATION                    = 0x1208;
+    int GL_LINEAR_MIPMAP_LINEAR                  = 0x2703;
+    int GL_LINEAR_MIPMAP_NEAREST                 = 0x2701;
+    int GL_LINES                                 = 0x0001;
+    int GL_LUMINANCE                             = 0x1909;
+    int GL_LUMINANCE_ALPHA                       = 0x190A;
+    int GL_MAX_ELEMENTS_INDICES                  = 0x80E9;
+    int GL_MAX_ELEMENTS_VERTICES                 = 0x80E8;
+    int GL_MAX_LIGHTS                            = 0x0D31;
+    int GL_MAX_MODELVIEW_STACK_DEPTH             = 0x0D36;
+    int GL_MAX_PROJECTION_STACK_DEPTH            = 0x0D38;
+    int GL_MAX_TEXTURE_SIZE                      = 0x0D33;
+    int GL_MAX_TEXTURE_STACK_DEPTH               = 0x0D39;
+    int GL_MAX_TEXTURE_UNITS                     = 0x84E2;
+    int GL_MAX_VIEWPORT_DIMS                     = 0x0D3A;
+    int GL_MODELVIEW                             = 0x1700;
+    int GL_MODULATE                              = 0x2100;
+    int GL_MULTISAMPLE                           = 0x809D;
+    int GL_NAND                                  = 0x150E;
+    int GL_NEAREST                               = 0x2600;
+    int GL_NEAREST_MIPMAP_LINEAR                 = 0x2702;
+    int GL_NEAREST_MIPMAP_NEAREST                = 0x2700;
+    int GL_NEVER                                 = 0x0200;
+    int GL_NICEST                                = 0x1102;
+    int GL_NO_ERROR                              = 0;
+    int GL_NOOP                                  = 0x1505;
+    int GL_NOR                                   = 0x1508;
+    int GL_NORMAL_ARRAY                          = 0x8075;
+    int GL_NORMALIZE                             = 0x0BA1;
+    int GL_NOTEQUAL                              = 0x0205;
+    int GL_NUM_COMPRESSED_TEXTURE_FORMATS        = 0x86A2;
+    int GL_ONE                                   = 1;
+    int GL_ONE_MINUS_DST_ALPHA                   = 0x0305;
+    int GL_ONE_MINUS_DST_COLOR                   = 0x0307;
+    int GL_ONE_MINUS_SRC_ALPHA                   = 0x0303;
+    int GL_ONE_MINUS_SRC_COLOR                   = 0x0301;
+    int GL_OR                                    = 0x1507;
+    int GL_OR_INVERTED                           = 0x150D;
+    int GL_OR_REVERSE                            = 0x150B;
+    int GL_OUT_OF_MEMORY                         = 0x0505;
+    int GL_PACK_ALIGNMENT                        = 0x0D05;
+    int GL_PALETTE4_R5_G6_B5_OES                 = 0x8B92;
+    int GL_PALETTE4_RGB5_A1_OES                  = 0x8B94;
+    int GL_PALETTE4_RGB8_OES                     = 0x8B90;
+    int GL_PALETTE4_RGBA4_OES                    = 0x8B93;
+    int GL_PALETTE4_RGBA8_OES                    = 0x8B91;
+    int GL_PALETTE8_R5_G6_B5_OES                 = 0x8B97;
+    int GL_PALETTE8_RGB5_A1_OES                  = 0x8B99;
+    int GL_PALETTE8_RGB8_OES                     = 0x8B95;
+    int GL_PALETTE8_RGBA4_OES                    = 0x8B98;
+    int GL_PALETTE8_RGBA8_OES                    = 0x8B96;
+    int GL_PERSPECTIVE_CORRECTION_HINT           = 0x0C50;
+    int GL_POINT_SMOOTH                          = 0x0B10;
+    int GL_POINT_SMOOTH_HINT                     = 0x0C51;
+    int GL_POINTS                                = 0x0000;
+    int GL_POINT_FADE_THRESHOLD_SIZE             = 0x8128;
+    int GL_POINT_SIZE                            = 0x0B11;
+    int GL_POLYGON_OFFSET_FILL                   = 0x8037;
+    int GL_POLYGON_SMOOTH_HINT                   = 0x0C53;
+    int GL_POSITION                              = 0x1203;
+    int GL_PROJECTION                            = 0x1701;
+    int GL_QUADRATIC_ATTENUATION                 = 0x1209;
+    int GL_RED_BITS                              = 0x0D52;
+    int GL_RENDERER                              = 0x1F01;
+    int GL_REPEAT                                = 0x2901;
+    int GL_REPLACE                               = 0x1E01;
+    int GL_RESCALE_NORMAL                        = 0x803A;
+    int GL_RGB                                   = 0x1907;
+    int GL_RGBA                                  = 0x1908;
+    int GL_SAMPLE_ALPHA_TO_COVERAGE              = 0x809E;
+    int GL_SAMPLE_ALPHA_TO_ONE                   = 0x809F;
+    int GL_SAMPLE_COVERAGE                       = 0x80A0;
+    int GL_SCISSOR_TEST                          = 0x0C11;
+    int GL_SET                                   = 0x150F;
+    int GL_SHININESS                             = 0x1601;
+    int GL_SHORT                                 = 0x1402;
+    int GL_SMOOTH                                = 0x1D01;
+    int GL_SMOOTH_LINE_WIDTH_RANGE               = 0x0B22;
+    int GL_SMOOTH_POINT_SIZE_RANGE               = 0x0B12;
+    int GL_SPECULAR                              = 0x1202;
+    int GL_SPOT_CUTOFF                           = 0x1206;
+    int GL_SPOT_DIRECTION                        = 0x1204;
+    int GL_SPOT_EXPONENT                         = 0x1205;
+    int GL_SRC_ALPHA                             = 0x0302;
+    int GL_SRC_ALPHA_SATURATE                    = 0x0308;
+    int GL_SRC_COLOR                             = 0x0300;
+    int GL_STACK_OVERFLOW                        = 0x0503;
+    int GL_STACK_UNDERFLOW                       = 0x0504;
+    int GL_STENCIL_BITS                          = 0x0D57;
+    int GL_STENCIL_BUFFER_BIT                    = 0x0400;
+    int GL_STENCIL_TEST                          = 0x0B90;
+    int GL_SUBPIXEL_BITS                         = 0x0D50;
+    int GL_TEXTURE                               = 0x1702;
+    int GL_TEXTURE_2D                            = 0x0DE1;
+    int GL_TEXTURE_COORD_ARRAY                   = 0x8078;
+    int GL_TEXTURE_ENV                           = 0x2300;
+    int GL_TEXTURE_ENV_COLOR                     = 0x2201;
+    int GL_TEXTURE_ENV_MODE                      = 0x2200;
+    int GL_TEXTURE_MAG_FILTER                    = 0x2800;
+    int GL_TEXTURE_MIN_FILTER                    = 0x2801;
+    int GL_TEXTURE_WRAP_S                        = 0x2802;
+    int GL_TEXTURE_WRAP_T                        = 0x2803;
+    int GL_TEXTURE0                              = 0x84C0;
+    int GL_TEXTURE1                              = 0x84C1;
+    int GL_TEXTURE2                              = 0x84C2;
+    int GL_TEXTURE3                              = 0x84C3;
+    int GL_TEXTURE4                              = 0x84C4;
+    int GL_TEXTURE5                              = 0x84C5;
+    int GL_TEXTURE6                              = 0x84C6;
+    int GL_TEXTURE7                              = 0x84C7;
+    int GL_TEXTURE8                              = 0x84C8;
+    int GL_TEXTURE9                              = 0x84C9;
+    int GL_TEXTURE10                             = 0x84CA;
+    int GL_TEXTURE11                             = 0x84CB;
+    int GL_TEXTURE12                             = 0x84CC;
+    int GL_TEXTURE13                             = 0x84CD;
+    int GL_TEXTURE14                             = 0x84CE;
+    int GL_TEXTURE15                             = 0x84CF;
+    int GL_TEXTURE16                             = 0x84D0;
+    int GL_TEXTURE17                             = 0x84D1;
+    int GL_TEXTURE18                             = 0x84D2;
+    int GL_TEXTURE19                             = 0x84D3;
+    int GL_TEXTURE20                             = 0x84D4;
+    int GL_TEXTURE21                             = 0x84D5;
+    int GL_TEXTURE22                             = 0x84D6;
+    int GL_TEXTURE23                             = 0x84D7;
+    int GL_TEXTURE24                             = 0x84D8;
+    int GL_TEXTURE25                             = 0x84D9;
+    int GL_TEXTURE26                             = 0x84DA;
+    int GL_TEXTURE27                             = 0x84DB;
+    int GL_TEXTURE28                             = 0x84DC;
+    int GL_TEXTURE29                             = 0x84DD;
+    int GL_TEXTURE30                             = 0x84DE;
+    int GL_TEXTURE31                             = 0x84DF;
+    int GL_TRIANGLE_FAN                          = 0x0006;
+    int GL_TRIANGLE_STRIP                        = 0x0005;
+    int GL_TRIANGLES                             = 0x0004;
+    int GL_TRUE                                  = 1;
+    int GL_UNPACK_ALIGNMENT                      = 0x0CF5;
+    int GL_UNSIGNED_BYTE                         = 0x1401;
+    int GL_UNSIGNED_SHORT                        = 0x1403;
+    int GL_UNSIGNED_SHORT_4_4_4_4                = 0x8033;
+    int GL_UNSIGNED_SHORT_5_5_5_1                = 0x8034;
+    int GL_UNSIGNED_SHORT_5_6_5                  = 0x8363;
+    int GL_VENDOR                                = 0x1F00;
+    int GL_VERSION                               = 0x1F02;
+    int GL_VERTEX_ARRAY                          = 0x8074;
+    int GL_XOR                                   = 0x1506;
+    int GL_ZERO                                  = 0;
+
+    void glActiveTexture(
+        int texture
+    );
+
+    void glAlphaFunc(
+        int func,
+        float ref
+    );
+
+    void glAlphaFuncx(
+        int func,
+        int ref
+    );
+
+    void glBindTexture(
+        int target,
+        int texture
+    );
+
+    void glBlendFunc(
+        int sfactor,
+        int dfactor
+    );
+
+    void glClear(
+        int mask
+    );
+
+    void glClearColor(
+        float red,
+        float green,
+        float blue,
+        float alpha
+    );
+
+    void glClearColorx(
+        int red,
+        int green,
+        int blue,
+        int alpha
+    );
+
+    void glClearDepthf(
+        float depth
+    );
+
+    void glClearDepthx(
+        int depth
+    );
+
+    void glClearStencil(
+        int s
+    );
+
+    void glClientActiveTexture(
+        int texture
+    );
+
+    void glColor4f(
+        float red,
+        float green,
+        float blue,
+        float alpha
+    );
+
+    void glColor4x(
+        int red,
+        int green,
+        int blue,
+        int alpha
+    );
+
+    void glColorMask(
+        boolean red,
+        boolean green,
+        boolean blue,
+        boolean alpha
+    );
+
+    void glColorPointer(
+        int size,
+        int type,
+        int stride,
+        java.nio.Buffer pointer
+    );
+
+    void glCompressedTexImage2D(
+        int target,
+        int level,
+        int internalformat,
+        int width,
+        int height,
+        int border,
+        int imageSize,
+        java.nio.Buffer data
+    );
+
+    void glCompressedTexSubImage2D(
+        int target,
+        int level,
+        int xoffset,
+        int yoffset,
+        int width,
+        int height,
+        int format,
+        int imageSize,
+        java.nio.Buffer data
+    );
+
+    void glCopyTexImage2D(
+        int target,
+        int level,
+        int internalformat,
+        int x,
+        int y,
+        int width,
+        int height,
+        int border
+    );
+
+    void glCopyTexSubImage2D(
+        int target,
+        int level,
+        int xoffset,
+        int yoffset,
+        int x,
+        int y,
+        int width,
+        int height
+    );
+
+    void glCullFace(
+        int mode
+    );
+
+    void glDeleteTextures(
+        int n,
+        int[] textures,
+        int offset
+    );
+
+    void glDeleteTextures(
+        int n,
+        java.nio.IntBuffer textures
+    );
+
+    void glDepthFunc(
+        int func
+    );
+
+    void glDepthMask(
+        boolean flag
+    );
+
+    void glDepthRangef(
+        float zNear,
+        float zFar
+    );
+
+    void glDepthRangex(
+        int zNear,
+        int zFar
+    );
+
+    void glDisable(
+        int cap
+    );
+
+    void glDisableClientState(
+        int array
+    );
+
+    void glDrawArrays(
+        int mode,
+        int first,
+        int count
+    );
+
+    void glDrawElements(
+        int mode,
+        int count,
+        int type,
+        java.nio.Buffer indices
+    );
+
+    void glEnable(
+        int cap
+    );
+
+    void glEnableClientState(
+        int array
+    );
+
+    void glFinish(
+    );
+
+    void glFlush(
+    );
+
+    void glFogf(
+        int pname,
+        float param
+    );
+
+    void glFogfv(
+        int pname,
+        float[] params,
+        int offset
+    );
+
+    void glFogfv(
+        int pname,
+        java.nio.FloatBuffer params
+    );
+
+    void glFogx(
+        int pname,
+        int param
+    );
+
+    void glFogxv(
+        int pname,
+        int[] params,
+        int offset
+    );
+
+    void glFogxv(
+        int pname,
+        java.nio.IntBuffer params
+    );
+
+    void glFrontFace(
+        int mode
+    );
+
+    void glFrustumf(
+        float left,
+        float right,
+        float bottom,
+        float top,
+        float zNear,
+        float zFar
+    );
+
+    void glFrustumx(
+        int left,
+        int right,
+        int bottom,
+        int top,
+        int zNear,
+        int zFar
+    );
+
+    void glGenTextures(
+        int n,
+        int[] textures,
+        int offset
+    );
+
+    void glGenTextures(
+        int n,
+        java.nio.IntBuffer textures
+    );
+
+    int glGetError(
+    );
+
+    void glGetIntegerv(
+        int pname,
+        int[] params,
+        int offset
+    );
+
+    void glGetIntegerv(
+        int pname,
+        java.nio.IntBuffer params
+    );
+
+    public String glGetString(
+        int name
+    );
+
+    void glHint(
+        int target,
+        int mode
+    );
+
+    void glLightModelf(
+        int pname,
+        float param
+    );
+
+    void glLightModelfv(
+        int pname,
+        float[] params,
+        int offset
+    );
+
+    void glLightModelfv(
+        int pname,
+        java.nio.FloatBuffer params
+    );
+
+    void glLightModelx(
+        int pname,
+        int param
+    );
+
+    void glLightModelxv(
+        int pname,
+        int[] params,
+        int offset
+    );
+
+    void glLightModelxv(
+        int pname,
+        java.nio.IntBuffer params
+    );
+
+    void glLightf(
+        int light,
+        int pname,
+        float param
+    );
+
+    void glLightfv(
+        int light,
+        int pname,
+        float[] params,
+        int offset
+    );
+
+    void glLightfv(
+        int light,
+        int pname,
+        java.nio.FloatBuffer params
+    );
+
+    void glLightx(
+        int light,
+        int pname,
+        int param
+    );
+
+    void glLightxv(
+        int light,
+        int pname,
+        int[] params,
+        int offset
+    );
+
+    void glLightxv(
+        int light,
+        int pname,
+        java.nio.IntBuffer params
+    );
+
+    void glLineWidth(
+        float width
+    );
+
+    void glLineWidthx(
+        int width
+    );
+
+    void glLoadIdentity(
+    );
+
+    void glLoadMatrixf(
+        float[] m,
+        int offset
+    );
+
+    void glLoadMatrixf(
+        java.nio.FloatBuffer m
+    );
+
+    void glLoadMatrixx(
+        int[] m,
+        int offset
+    );
+
+    void glLoadMatrixx(
+        java.nio.IntBuffer m
+    );
+
+    void glLogicOp(
+        int opcode
+    );
+
+    void glMaterialf(
+        int face,
+        int pname,
+        float param
+    );
+
+    void glMaterialfv(
+        int face,
+        int pname,
+        float[] params,
+        int offset
+    );
+
+    void glMaterialfv(
+        int face,
+        int pname,
+        java.nio.FloatBuffer params
+    );
+
+    void glMaterialx(
+        int face,
+        int pname,
+        int param
+    );
+
+    void glMaterialxv(
+        int face,
+        int pname,
+        int[] params,
+        int offset
+    );
+
+    void glMaterialxv(
+        int face,
+        int pname,
+        java.nio.IntBuffer params
+    );
+
+    void glMatrixMode(
+        int mode
+    );
+
+    void glMultMatrixf(
+        float[] m,
+        int offset
+    );
+
+    void glMultMatrixf(
+        java.nio.FloatBuffer m
+    );
+
+    void glMultMatrixx(
+        int[] m,
+        int offset
+    );
+
+    void glMultMatrixx(
+        java.nio.IntBuffer m
+    );
+
+    void glMultiTexCoord4f(
+        int target,
+        float s,
+        float t,
+        float r,
+        float q
+    );
+
+    void glMultiTexCoord4x(
+        int target,
+        int s,
+        int t,
+        int r,
+        int q
+    );
+
+    void glNormal3f(
+        float nx,
+        float ny,
+        float nz
+    );
+
+    void glNormal3x(
+        int nx,
+        int ny,
+        int nz
+    );
+
+    void glNormalPointer(
+        int type,
+        int stride,
+        java.nio.Buffer pointer
+    );
+
+    void glOrthof(
+        float left,
+        float right,
+        float bottom,
+        float top,
+        float zNear,
+        float zFar
+    );
+
+    void glOrthox(
+        int left,
+        int right,
+        int bottom,
+        int top,
+        int zNear,
+        int zFar
+    );
+
+    void glPixelStorei(
+        int pname,
+        int param
+    );
+
+    void glPointSize(
+        float size
+    );
+
+    void glPointSizex(
+        int size
+    );
+
+    void glPolygonOffset(
+        float factor,
+        float units
+    );
+
+    void glPolygonOffsetx(
+        int factor,
+        int units
+    );
+
+    void glPopMatrix(
+    );
+
+    void glPushMatrix(
+    );
+
+    void glReadPixels(
+        int x,
+        int y,
+        int width,
+        int height,
+        int format,
+        int type,
+        java.nio.Buffer pixels
+    );
+
+    void glRotatef(
+        float angle,
+        float x,
+        float y,
+        float z
+    );
+
+    void glRotatex(
+        int angle,
+        int x,
+        int y,
+        int z
+    );
+
+    void glSampleCoverage(
+        float value,
+        boolean invert
+    );
+
+    void glSampleCoveragex(
+        int value,
+        boolean invert
+    );
+
+    void glScalef(
+        float x,
+        float y,
+        float z
+    );
+
+    void glScalex(
+        int x,
+        int y,
+        int z
+    );
+
+    void glScissor(
+        int x,
+        int y,
+        int width,
+        int height
+    );
+
+    void glShadeModel(
+        int mode
+    );
+
+    void glStencilFunc(
+        int func,
+        int ref,
+        int mask
+    );
+
+    void glStencilMask(
+        int mask
+    );
+
+    void glStencilOp(
+        int fail,
+        int zfail,
+        int zpass
+    );
+
+    void glTexCoordPointer(
+        int size,
+        int type,
+        int stride,
+        java.nio.Buffer pointer
+    );
+
+    void glTexEnvf(
+        int target,
+        int pname,
+        float param
+    );
+
+    void glTexEnvfv(
+        int target,
+        int pname,
+        float[] params,
+        int offset
+    );
+
+    void glTexEnvfv(
+        int target,
+        int pname,
+        java.nio.FloatBuffer params
+    );
+
+    void glTexEnvx(
+        int target,
+        int pname,
+        int param
+    );
+
+    void glTexEnvxv(
+        int target,
+        int pname,
+        int[] params,
+        int offset
+    );
+
+    void glTexEnvxv(
+        int target,
+        int pname,
+        java.nio.IntBuffer params
+    );
+
+    void glTexImage2D(
+        int target,
+        int level,
+        int internalformat,
+        int width,
+        int height,
+        int border,
+        int format,
+        int type,
+        java.nio.Buffer pixels
+    );
+
+    void glTexParameterf(
+        int target,
+        int pname,
+        float param
+    );
+
+    void glTexParameterx(
+        int target,
+        int pname,
+        int param
+    );
+
+    void glTexSubImage2D(
+        int target,
+        int level,
+        int xoffset,
+        int yoffset,
+        int width,
+        int height,
+        int format,
+        int type,
+        java.nio.Buffer pixels
+    );
+
+    void glTranslatef(
+        float x,
+        float y,
+        float z
+    );
+
+    void glTranslatex(
+        int x,
+        int y,
+        int z
+    );
+
+    void glVertexPointer(
+        int size,
+        int type,
+        int stride,
+        java.nio.Buffer pointer
+    );
+
+    void glViewport(
+        int x,
+        int y,
+        int width,
+        int height
+    );
+
+}
diff --git a/javax/microedition/khronos/opengles/GL10Ext.java b/javax/microedition/khronos/opengles/GL10Ext.java
new file mode 100644
index 0000000..562b20a
--- /dev/null
+++ b/javax/microedition/khronos/opengles/GL10Ext.java
@@ -0,0 +1,36 @@
+/* //device/java/android/javax/microedition/khronos/opengles/GL10Ext.java
+**
+** Copyright 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.
+*/
+
+// This source file is automatically generated
+
+package javax.microedition.khronos.opengles;
+
+public interface GL10Ext extends GL {
+
+    int glQueryMatrixxOES(
+        int[] mantissa,
+        int mantissaOffset,
+        int[] exponent,
+        int exponentOffset
+    );
+
+    int glQueryMatrixxOES(
+        java.nio.IntBuffer mantissa,
+        java.nio.IntBuffer exponent
+    );
+
+}
diff --git a/javax/microedition/khronos/opengles/GL11.java b/javax/microedition/khronos/opengles/GL11.java
new file mode 100644
index 0000000..3ba110c
--- /dev/null
+++ b/javax/microedition/khronos/opengles/GL11.java
@@ -0,0 +1,550 @@
+/* //device/java/android/javax/microedition/khronos/opengles/GL11.java
+**
+** Copyright 2006, 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.
+*/
+
+// This source file is automatically generated
+
+package javax.microedition.khronos.opengles;
+
+public interface GL11 extends GL10 {
+    int GL_ACTIVE_TEXTURE                          = 0x84E0;
+    int GL_ADD_SIGNED                              = 0x8574;
+    int GL_ALPHA_SCALE                             = 0x0D1C;
+    int GL_ALPHA_TEST_FUNC                         = 0x0BC1;
+    int GL_ALPHA_TEST_REF                          = 0x0BC2;
+    int GL_ARRAY_BUFFER                            = 0x8892;
+    int GL_ARRAY_BUFFER_BINDING                    = 0x8894;
+    int GL_BLEND_DST                               = 0x0BE0;
+    int GL_BLEND_SRC                               = 0x0BE1;
+    int GL_BUFFER_ACCESS                           = 0x88BB;
+    int GL_BUFFER_SIZE                             = 0x8764;
+    int GL_BUFFER_USAGE                            = 0x8765;
+    int GL_CLIENT_ACTIVE_TEXTURE                   = 0x84E1;
+    int GL_CLIP_PLANE0                             = 0x3000;
+    int GL_CLIP_PLANE1                             = 0x3001;
+    int GL_CLIP_PLANE2                             = 0x3002;
+    int GL_CLIP_PLANE3                             = 0x3003;
+    int GL_CLIP_PLANE4                             = 0x3004;
+    int GL_CLIP_PLANE5                             = 0x3005;
+    int GL_COLOR_ARRAY_BUFFER_BINDING              = 0x8898;
+    int GL_COLOR_ARRAY_POINTER                     = 0x8090;
+    int GL_COLOR_ARRAY_SIZE                        = 0x8081;
+    int GL_COLOR_ARRAY_STRIDE                      = 0x8083;
+    int GL_COLOR_ARRAY_TYPE                        = 0x8082;
+    int GL_COLOR_CLEAR_VALUE                       = 0x0C22;
+    int GL_COLOR_WRITEMASK                         = 0x0C23;
+    int GL_COMBINE                                 = 0x8570;
+    int GL_COMBINE_ALPHA                           = 0x8572;
+    int GL_COMBINE_RGB                             = 0x8571;
+    int GL_CONSTANT                                = 0x8576;
+    int GL_COORD_REPLACE_OES                       = 0x8862;
+    int GL_CULL_FACE_MODE                          = 0x0B45;
+    int GL_CURRENT_COLOR                           = 0x0B00;
+    int GL_CURRENT_NORMAL                          = 0x0B02;
+    int GL_CURRENT_TEXTURE_COORDS                  = 0x0B03;
+    int GL_DEPTH_CLEAR_VALUE                       = 0x0B73;
+    int GL_DEPTH_FUNC                              = 0x0B74;
+    int GL_DEPTH_RANGE                             = 0x0B70;
+    int GL_DEPTH_WRITEMASK                         = 0x0B72;
+    int GL_DOT3_RGB                                = 0x86AE;
+    int GL_DOT3_RGBA                               = 0x86AF;
+    int GL_DYNAMIC_DRAW                            = 0x88E8;
+    int GL_ELEMENT_ARRAY_BUFFER                    = 0x8893;
+    int GL_ELEMENT_ARRAY_BUFFER_BINDING            = 0x8895;
+    int GL_FRONT_FACE                              = 0x0B46;
+    int GL_GENERATE_MIPMAP                         = 0x8191;
+    int GL_GENERATE_MIPMAP_HINT                    = 0x8192;
+    int GL_INTERPOLATE                             = 0x8575;
+    int GL_LINE_WIDTH                              = 0x0B21;
+    int GL_LOGIC_OP_MODE                           = 0x0BF0;
+    int GL_MATRIX_MODE                             = 0x0BA0;
+    int GL_MAX_CLIP_PLANES                         = 0x0D32;
+    int GL_MODELVIEW_MATRIX                        = 0x0BA6;
+    int GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES  = 0x898D;
+    int GL_MODELVIEW_STACK_DEPTH                   = 0x0BA3;
+    int GL_NORMAL_ARRAY_BUFFER_BINDING             = 0x8897;
+    int GL_NORMAL_ARRAY_POINTER                    = 0x808F;
+    int GL_NORMAL_ARRAY_STRIDE                     = 0x807F;
+    int GL_NORMAL_ARRAY_TYPE                       = 0x807E;
+    int GL_OPERAND0_ALPHA                          = 0x8598;
+    int GL_OPERAND0_RGB                            = 0x8590;
+    int GL_OPERAND1_ALPHA                          = 0x8599;
+    int GL_OPERAND1_RGB                            = 0x8591;
+    int GL_OPERAND2_ALPHA                          = 0x859A;
+    int GL_OPERAND2_RGB                            = 0x8592;
+    int GL_POINT_DISTANCE_ATTENUATION              = 0x8129;
+    int GL_POINT_FADE_THRESHOLD_SIZE               = 0x8128;
+    int GL_POINT_SIZE                              = 0x0B11;
+    int GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES     = 0x8B9F;
+    int GL_POINT_SIZE_ARRAY_OES                    = 0x8B9C;
+    int GL_POINT_SIZE_ARRAY_POINTER_OES            = 0x898C;
+    int GL_POINT_SIZE_ARRAY_STRIDE_OES             = 0x898B;
+    int GL_POINT_SIZE_ARRAY_TYPE_OES               = 0x898A;
+    int GL_POINT_SIZE_MAX                          = 0x8127;
+    int GL_POINT_SIZE_MIN                          = 0x8126;
+    int GL_POINT_SPRITE_OES                        = 0x8861;
+    int GL_POLYGON_OFFSET_FACTOR                   = 0x8038;
+    int GL_POLYGON_OFFSET_UNITS                    = 0x2A00;
+    int GL_PREVIOUS                                = 0x8578;
+    int GL_PRIMARY_COLOR                           = 0x8577;
+    int GL_PROJECTION_MATRIX                       = 0x0BA7;
+    int GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES = 0x898E;
+    int GL_PROJECTION_STACK_DEPTH                  = 0x0BA4;
+    int GL_RGB_SCALE                               = 0x8573;
+    int GL_SAMPLE_BUFFERS                          = 0x80A8;
+    int GL_SAMPLE_COVERAGE_INVERT                  = 0x80AB;
+    int GL_SAMPLE_COVERAGE_VALUE                   = 0x80AA;
+    int GL_SAMPLES                                 = 0x80A9;
+    int GL_SCISSOR_BOX                             = 0x0C10;
+    int GL_SHADE_MODEL                             = 0x0B54;
+    int GL_SRC0_ALPHA                              = 0x8588;
+    int GL_SRC0_RGB                                = 0x8580;
+    int GL_SRC1_ALPHA                              = 0x8589;
+    int GL_SRC1_RGB                                = 0x8581;
+    int GL_SRC2_ALPHA                              = 0x858A;
+    int GL_SRC2_RGB                                = 0x8582;
+    int GL_STATIC_DRAW                             = 0x88E4;
+    int GL_STENCIL_CLEAR_VALUE                     = 0x0B91;
+    int GL_STENCIL_FAIL                            = 0x0B94;
+    int GL_STENCIL_FUNC                            = 0x0B92;
+    int GL_STENCIL_PASS_DEPTH_FAIL                 = 0x0B95;
+    int GL_STENCIL_PASS_DEPTH_PASS                 = 0x0B96;
+    int GL_STENCIL_REF                             = 0x0B97;
+    int GL_STENCIL_VALUE_MASK                      = 0x0B93;
+    int GL_STENCIL_WRITEMASK                       = 0x0B98;
+    int GL_SUBTRACT                                = 0x84E7;
+    int GL_TEXTURE_BINDING_2D                      = 0x8069;
+    int GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING      = 0x889A;
+    int GL_TEXTURE_COORD_ARRAY_POINTER             = 0x8092;
+    int GL_TEXTURE_COORD_ARRAY_SIZE                = 0x8088;
+    int GL_TEXTURE_COORD_ARRAY_STRIDE              = 0x808A;
+    int GL_TEXTURE_COORD_ARRAY_TYPE                = 0x8089;
+    int GL_TEXTURE_MATRIX                          = 0x0BA8;
+    int GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES    = 0x898F;
+    int GL_TEXTURE_STACK_DEPTH                     = 0x0BA5;
+    int GL_VERTEX_ARRAY_BUFFER_BINDING             = 0x8896;
+    int GL_VERTEX_ARRAY_POINTER                    = 0x808E;
+    int GL_VERTEX_ARRAY_SIZE                       = 0x807A;
+    int GL_VERTEX_ARRAY_STRIDE                     = 0x807C;
+    int GL_VERTEX_ARRAY_TYPE                       = 0x807B;
+    int GL_VIEWPORT                                = 0x0BA2;
+    int GL_WRITE_ONLY                              = 0x88B9;
+
+    void glGetPointerv(int pname, java.nio.Buffer[] params);
+    void glBindBuffer(
+        int target,
+        int buffer
+    );
+
+    void glBufferData(
+        int target,
+        int size,
+        java.nio.Buffer data,
+        int usage
+    );
+
+    void glBufferSubData(
+        int target,
+        int offset,
+        int size,
+        java.nio.Buffer data
+    );
+
+    void glClipPlanef(
+        int plane,
+        float[] equation,
+        int offset
+    );
+
+    void glClipPlanef(
+        int plane,
+        java.nio.FloatBuffer equation
+    );
+
+    void glClipPlanex(
+        int plane,
+        int[] equation,
+        int offset
+    );
+
+    void glClipPlanex(
+        int plane,
+        java.nio.IntBuffer equation
+    );
+
+    void glColor4ub(
+        byte red,
+        byte green,
+        byte blue,
+        byte alpha
+    );
+
+    void glColorPointer(
+        int size,
+        int type,
+        int stride,
+        int offset
+    );
+
+    void glDeleteBuffers(
+        int n,
+        int[] buffers,
+        int offset
+    );
+
+    void glDeleteBuffers(
+        int n,
+        java.nio.IntBuffer buffers
+    );
+
+    void glDrawElements(
+        int mode,
+        int count,
+        int type,
+        int offset
+    );
+
+    void glGenBuffers(
+        int n,
+        int[] buffers,
+        int offset
+    );
+
+    void glGenBuffers(
+        int n,
+        java.nio.IntBuffer buffers
+    );
+
+    void glGetBooleanv(
+        int pname,
+        boolean[] params,
+        int offset
+    );
+
+    void glGetBooleanv(
+        int pname,
+        java.nio.IntBuffer params
+    );
+
+    void glGetBufferParameteriv(
+        int target,
+        int pname,
+        int[] params,
+        int offset
+    );
+
+    void glGetBufferParameteriv(
+        int target,
+        int pname,
+        java.nio.IntBuffer params
+    );
+
+    void glGetClipPlanef(
+        int pname,
+        float[] eqn,
+        int offset
+    );
+
+    void glGetClipPlanef(
+        int pname,
+        java.nio.FloatBuffer eqn
+    );
+
+    void glGetClipPlanex(
+        int pname,
+        int[] eqn,
+        int offset
+    );
+
+    void glGetClipPlanex(
+        int pname,
+        java.nio.IntBuffer eqn
+    );
+
+    void glGetFixedv(
+        int pname,
+        int[] params,
+        int offset
+    );
+
+    void glGetFixedv(
+        int pname,
+        java.nio.IntBuffer params
+    );
+
+    void glGetFloatv(
+        int pname,
+        float[] params,
+        int offset
+    );
+
+    void glGetFloatv(
+        int pname,
+        java.nio.FloatBuffer params
+    );
+
+    void glGetLightfv(
+        int light,
+        int pname,
+        float[] params,
+        int offset
+    );
+
+    void glGetLightfv(
+        int light,
+        int pname,
+        java.nio.FloatBuffer params
+    );
+
+    void glGetLightxv(
+        int light,
+        int pname,
+        int[] params,
+        int offset
+    );
+
+    void glGetLightxv(
+        int light,
+        int pname,
+        java.nio.IntBuffer params
+    );
+
+    void glGetMaterialfv(
+        int face,
+        int pname,
+        float[] params,
+        int offset
+    );
+
+    void glGetMaterialfv(
+        int face,
+        int pname,
+        java.nio.FloatBuffer params
+    );
+
+    void glGetMaterialxv(
+        int face,
+        int pname,
+        int[] params,
+        int offset
+    );
+
+    void glGetMaterialxv(
+        int face,
+        int pname,
+        java.nio.IntBuffer params
+    );
+
+    void glGetTexEnviv(
+        int env,
+        int pname,
+        int[] params,
+        int offset
+    );
+
+    void glGetTexEnviv(
+        int env,
+        int pname,
+        java.nio.IntBuffer params
+    );
+
+    void glGetTexEnvxv(
+        int env,
+        int pname,
+        int[] params,
+        int offset
+    );
+
+    void glGetTexEnvxv(
+        int env,
+        int pname,
+        java.nio.IntBuffer params
+    );
+
+    void glGetTexParameterfv(
+        int target,
+        int pname,
+        float[] params,
+        int offset
+    );
+
+    void glGetTexParameterfv(
+        int target,
+        int pname,
+        java.nio.FloatBuffer params
+    );
+
+    void glGetTexParameteriv(
+        int target,
+        int pname,
+        int[] params,
+        int offset
+    );
+
+    void glGetTexParameteriv(
+        int target,
+        int pname,
+        java.nio.IntBuffer params
+    );
+
+    void glGetTexParameterxv(
+        int target,
+        int pname,
+        int[] params,
+        int offset
+    );
+
+    void glGetTexParameterxv(
+        int target,
+        int pname,
+        java.nio.IntBuffer params
+    );
+
+    boolean glIsBuffer(
+        int buffer
+    );
+
+    boolean glIsEnabled(
+        int cap
+    );
+
+    boolean glIsTexture(
+        int texture
+    );
+
+    void glNormalPointer(
+        int type,
+        int stride,
+        int offset
+    );
+
+    void glPointParameterf(
+        int pname,
+        float param
+    );
+
+    void glPointParameterfv(
+        int pname,
+        float[] params,
+        int offset
+    );
+
+    void glPointParameterfv(
+        int pname,
+        java.nio.FloatBuffer params
+    );
+
+    void glPointParameterx(
+        int pname,
+        int param
+    );
+
+    void glPointParameterxv(
+        int pname,
+        int[] params,
+        int offset
+    );
+
+    void glPointParameterxv(
+        int pname,
+        java.nio.IntBuffer params
+    );
+
+    void glPointSizePointerOES(
+        int type,
+        int stride,
+        java.nio.Buffer pointer
+    );
+
+    void glTexCoordPointer(
+        int size,
+        int type,
+        int stride,
+        int offset
+    );
+
+    void glTexEnvi(
+        int target,
+        int pname,
+        int param
+    );
+
+    void glTexEnviv(
+        int target,
+        int pname,
+        int[] params,
+        int offset
+    );
+
+    void glTexEnviv(
+        int target,
+        int pname,
+        java.nio.IntBuffer params
+    );
+
+    void glTexParameterfv(
+        int target,
+        int pname,
+        float[] params,
+        int offset
+    );
+
+    void glTexParameterfv(
+        int target,
+        int pname,
+        java.nio.FloatBuffer params
+    );
+
+    void glTexParameteri(
+        int target,
+        int pname,
+        int param
+    );
+
+    void glTexParameteriv(
+        int target,
+        int pname,
+        int[] params,
+        int offset
+    );
+
+    void glTexParameteriv(
+        int target,
+        int pname,
+        java.nio.IntBuffer params
+    );
+
+    void glTexParameterxv(
+        int target,
+        int pname,
+        int[] params,
+        int offset
+    );
+
+    void glTexParameterxv(
+        int target,
+        int pname,
+        java.nio.IntBuffer params
+    );
+
+    void glVertexPointer(
+        int size,
+        int type,
+        int stride,
+        int offset
+    );
+
+}
diff --git a/javax/microedition/khronos/opengles/GL11Ext.java b/javax/microedition/khronos/opengles/GL11Ext.java
new file mode 100644
index 0000000..459a1ab
--- /dev/null
+++ b/javax/microedition/khronos/opengles/GL11Ext.java
@@ -0,0 +1,153 @@
+/* //device/java/android/javax/microedition/khronos/opengles/GL11Ext.java
+**
+** Copyright 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.
+*/
+
+// This source file is automatically generated
+
+package javax.microedition.khronos.opengles;
+
+public interface GL11Ext extends GL {
+    int GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES = 0x8B9E;
+    int GL_MATRIX_INDEX_ARRAY_OES                = 0x8844;
+    int GL_MATRIX_INDEX_ARRAY_POINTER_OES        = 0x8849;
+    int GL_MATRIX_INDEX_ARRAY_SIZE_OES           = 0x8846;
+    int GL_MATRIX_INDEX_ARRAY_STRIDE_OES         = 0x8848;
+    int GL_MATRIX_INDEX_ARRAY_TYPE_OES           = 0x8847;
+    int GL_MATRIX_PALETTE_OES                    = 0x8840;
+    int GL_MAX_PALETTE_MATRICES_OES              = 0x8842;
+    int GL_MAX_VERTEX_UNITS_OES                  = 0x86A4;
+    int GL_TEXTURE_CROP_RECT_OES                 = 0x8B9D;
+    int GL_WEIGHT_ARRAY_BUFFER_BINDING_OES       = 0x889E;
+    int GL_WEIGHT_ARRAY_OES                      = 0x86AD;
+    int GL_WEIGHT_ARRAY_POINTER_OES              = 0x86AC;
+    int GL_WEIGHT_ARRAY_SIZE_OES                 = 0x86AB;
+    int GL_WEIGHT_ARRAY_STRIDE_OES               = 0x86AA;
+    int GL_WEIGHT_ARRAY_TYPE_OES                 = 0x86A9;
+
+    void glTexParameterfv(int target, int pname, float[] param, int offset);
+
+    void glCurrentPaletteMatrixOES(
+        int matrixpaletteindex
+    );
+
+    void glDrawTexfOES(
+        float x,
+        float y,
+        float z,
+        float width,
+        float height
+    );
+
+    void glDrawTexfvOES(
+        float[] coords,
+        int offset
+    );
+
+    void glDrawTexfvOES(
+        java.nio.FloatBuffer coords
+    );
+
+    void glDrawTexiOES(
+        int x,
+        int y,
+        int z,
+        int width,
+        int height
+    );
+
+    void glDrawTexivOES(
+        int[] coords,
+        int offset
+    );
+
+    void glDrawTexivOES(
+        java.nio.IntBuffer coords
+    );
+
+    void glDrawTexsOES(
+        short x,
+        short y,
+        short z,
+        short width,
+        short height
+    );
+
+    void glDrawTexsvOES(
+        short[] coords,
+        int offset
+    );
+
+    void glDrawTexsvOES(
+        java.nio.ShortBuffer coords
+    );
+
+    void glDrawTexxOES(
+        int x,
+        int y,
+        int z,
+        int width,
+        int height
+    );
+
+    void glDrawTexxvOES(
+        int[] coords,
+        int offset
+    );
+
+    void glDrawTexxvOES(
+        java.nio.IntBuffer coords
+    );
+
+    void glEnable(
+        int cap
+    );
+
+    void glEnableClientState(
+        int array
+    );
+
+    void glLoadPaletteFromModelViewMatrixOES(
+    );
+
+    void glMatrixIndexPointerOES(
+        int size,
+        int type,
+        int stride,
+        java.nio.Buffer pointer
+    );
+
+    void glMatrixIndexPointerOES(
+        int size,
+        int type,
+        int stride,
+        int offset
+    );
+
+    void glWeightPointerOES(
+        int size,
+        int type,
+        int stride,
+        java.nio.Buffer pointer
+    );
+
+    void glWeightPointerOES(
+        int size,
+        int type,
+        int stride,
+        int offset
+    );
+
+}
diff --git a/javax/microedition/khronos/opengles/GL11ExtensionPack.java b/javax/microedition/khronos/opengles/GL11ExtensionPack.java
new file mode 100644
index 0000000..933c91e
--- /dev/null
+++ b/javax/microedition/khronos/opengles/GL11ExtensionPack.java
@@ -0,0 +1,434 @@
+/* //device/java/android/javax/microedition/khronos/opengles/GL11ExtensionPack.java
+**
+** Copyright 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.
+*/
+
+// This source file is automatically generated
+
+package javax.microedition.khronos.opengles;
+
+public interface GL11ExtensionPack extends GL {
+    int GL_BLEND_DST_ALPHA                                  = 0x80CA;
+    int GL_BLEND_DST_RGB                                    = 0x80C8;
+    int GL_BLEND_EQUATION                                   = 0x8009;
+    int GL_BLEND_EQUATION_ALPHA                             = 0x883D;
+    int GL_BLEND_EQUATION_RGB                               = 0x8009;
+    int GL_BLEND_SRC_ALPHA                                  = 0x80CB;
+    int GL_BLEND_SRC_RGB                                    = 0x80C9;
+    int GL_COLOR_ATTACHMENT0_OES                            = 0x8CE0;
+    int GL_COLOR_ATTACHMENT1_OES                            = 0x8CE1;
+    int GL_COLOR_ATTACHMENT2_OES                            = 0x8CE2;
+    int GL_COLOR_ATTACHMENT3_OES                            = 0x8CE3;
+    int GL_COLOR_ATTACHMENT4_OES                            = 0x8CE4;
+    int GL_COLOR_ATTACHMENT5_OES                            = 0x8CE5;
+    int GL_COLOR_ATTACHMENT6_OES                            = 0x8CE6;
+    int GL_COLOR_ATTACHMENT7_OES                            = 0x8CE7;
+    int GL_COLOR_ATTACHMENT8_OES                            = 0x8CE8;
+    int GL_COLOR_ATTACHMENT9_OES                            = 0x8CE9;
+    int GL_COLOR_ATTACHMENT10_OES                           = 0x8CEA;
+    int GL_COLOR_ATTACHMENT11_OES                           = 0x8CEB;
+    int GL_COLOR_ATTACHMENT12_OES                           = 0x8CEC;
+    int GL_COLOR_ATTACHMENT13_OES                           = 0x8CED;
+    int GL_COLOR_ATTACHMENT14_OES                           = 0x8CEE;
+    int GL_COLOR_ATTACHMENT15_OES                           = 0x8CEF;
+    int GL_DECR_WRAP                                        = 0x8508;
+    int GL_DEPTH_ATTACHMENT_OES                             = 0x8D00;
+    int GL_DEPTH_COMPONENT                                  = 0x1902;
+    int GL_DEPTH_COMPONENT16                                = 0x81A5;
+    int GL_DEPTH_COMPONENT24                                = 0x81A6;
+    int GL_DEPTH_COMPONENT32                                = 0x81A7;
+    int GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_OES           = 0x8CD1;
+    int GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_OES           = 0x8CD0;
+    int GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_OES = 0x8CD3;
+    int GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_OES         = 0x8CD2;
+    int GL_FRAMEBUFFER_BINDING_OES                          = 0x8CA6;
+    int GL_FRAMEBUFFER_COMPLETE_OES                         = 0x8CD5;
+    int GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES            = 0x8CD6;
+    int GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_OES            = 0x8CD9;
+    int GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_OES           = 0x8CDB;
+    int GL_FRAMEBUFFER_INCOMPLETE_FORMATS_OES               = 0x8CDA;
+    int GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_OES    = 0x8CD7;
+    int GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_OES           = 0x8CDC;
+    int GL_FRAMEBUFFER_OES                                  = 0x8D40;
+    int GL_FRAMEBUFFER_UNSUPPORTED_OES                      = 0x8CDD;
+    int GL_FUNC_ADD                                         = 0x8006;
+    int GL_FUNC_REVERSE_SUBTRACT                            = 0x800B;
+    int GL_FUNC_SUBTRACT                                    = 0x800A;
+    int GL_INCR_WRAP                                        = 0x8507;
+    int GL_INVALID_FRAMEBUFFER_OPERATION_OES                = 0x0506;
+    int GL_MAX_COLOR_ATTACHMENTS_OES                        = 0x8CDF;
+    int GL_MAX_CUBE_MAP_TEXTURE_SIZE                        = 0x851C;
+    int GL_MAX_RENDERBUFFER_SIZE_OES                        = 0x84E8;
+    int GL_MIRRORED_REPEAT                                  = 0x8370;
+    int GL_NORMAL_MAP                                       = 0x8511;
+    int GL_REFLECTION_MAP                                   = 0x8512;
+    int GL_RENDERBUFFER_ALPHA_SIZE_OES                      = 0x8D53;
+    int GL_RENDERBUFFER_BINDING_OES                         = 0x8CA7;
+    int GL_RENDERBUFFER_BLUE_SIZE_OES                       = 0x8D52;
+    int GL_RENDERBUFFER_DEPTH_SIZE_OES                      = 0x8D54;
+    int GL_RENDERBUFFER_GREEN_SIZE_OES                      = 0x8D51;
+    int GL_RENDERBUFFER_HEIGHT_OES                          = 0x8D43;
+    int GL_RENDERBUFFER_INTERNAL_FORMAT_OES                 = 0x8D44;
+    int GL_RENDERBUFFER_OES                                 = 0x8D41;
+    int GL_RENDERBUFFER_RED_SIZE_OES                        = 0x8D50;
+    int GL_RENDERBUFFER_STENCIL_SIZE_OES                    = 0x8D55;
+    int GL_RENDERBUFFER_WIDTH_OES                           = 0x8D42;
+    int GL_RGB5_A1                                          = 0x8057;
+    int GL_RGB565_OES                                       = 0x8D62;
+    int GL_RGB8                                             = 0x8051;
+    int GL_RGBA4                                            = 0x8056;
+    int GL_RGBA8                                            = 0x8058;
+    int GL_STENCIL_ATTACHMENT_OES                           = 0x8D20;
+    int GL_STENCIL_INDEX                                    = 0x1901;
+    int GL_STENCIL_INDEX1_OES                               = 0x8D46;
+    int GL_STENCIL_INDEX4_OES                               = 0x8D47;
+    int GL_STENCIL_INDEX8_OES                               = 0x8D48;
+    int GL_STR                                              = -1;
+    int GL_TEXTURE_BINDING_CUBE_MAP                         = 0x8514;
+    int GL_TEXTURE_CUBE_MAP                                 = 0x8513;
+    int GL_TEXTURE_CUBE_MAP_NEGATIVE_X                      = 0x8516;
+    int GL_TEXTURE_CUBE_MAP_NEGATIVE_Y                      = 0x8518;
+    int GL_TEXTURE_CUBE_MAP_NEGATIVE_Z                      = 0x851A;
+    int GL_TEXTURE_CUBE_MAP_POSITIVE_X                      = 0x8515;
+    int GL_TEXTURE_CUBE_MAP_POSITIVE_Y                      = 0x8517;
+    int GL_TEXTURE_CUBE_MAP_POSITIVE_Z                      = 0x8519;
+    int GL_TEXTURE_GEN_MODE                                 = 0x2500;
+    int GL_TEXTURE_GEN_STR                                  = 0x8D60;
+
+    void glBindFramebufferOES(
+        int target,
+        int framebuffer
+    );
+
+    void glBindRenderbufferOES(
+        int target,
+        int renderbuffer
+    );
+
+    void glBindTexture(
+        int target,
+        int texture
+    );
+
+    void glBlendEquation(
+        int mode
+    );
+
+    void glBlendEquationSeparate(
+        int modeRGB,
+        int modeAlpha
+    );
+
+    void glBlendFuncSeparate(
+        int srcRGB,
+        int dstRGB,
+        int srcAlpha,
+        int dstAlpha
+    );
+
+    int glCheckFramebufferStatusOES(
+        int target
+    );
+
+    void glCompressedTexImage2D(
+        int target,
+        int level,
+        int internalformat,
+        int width,
+        int height,
+        int border,
+        int imageSize,
+        java.nio.Buffer data
+    );
+
+    void glCopyTexImage2D(
+        int target,
+        int level,
+        int internalformat,
+        int x,
+        int y,
+        int width,
+        int height,
+        int border
+    );
+
+    void glDeleteFramebuffersOES(
+        int n,
+        int[] framebuffers,
+        int offset
+    );
+
+    void glDeleteFramebuffersOES(
+        int n,
+        java.nio.IntBuffer framebuffers
+    );
+
+    void glDeleteRenderbuffersOES(
+        int n,
+        int[] renderbuffers,
+        int offset
+    );
+
+    void glDeleteRenderbuffersOES(
+        int n,
+        java.nio.IntBuffer renderbuffers
+    );
+
+    void glEnable(
+        int cap
+    );
+
+    void glFramebufferRenderbufferOES(
+        int target,
+        int attachment,
+        int renderbuffertarget,
+        int renderbuffer
+    );
+
+    void glFramebufferTexture2DOES(
+        int target,
+        int attachment,
+        int textarget,
+        int texture,
+        int level
+    );
+
+    void glGenerateMipmapOES(
+        int target
+    );
+
+    void glGenFramebuffersOES(
+        int n,
+        int[] framebuffers,
+        int offset
+    );
+
+    void glGenFramebuffersOES(
+        int n,
+        java.nio.IntBuffer framebuffers
+    );
+
+    void glGenRenderbuffersOES(
+        int n,
+        int[] renderbuffers,
+        int offset
+    );
+
+    void glGenRenderbuffersOES(
+        int n,
+        java.nio.IntBuffer renderbuffers
+    );
+
+    void glGetFramebufferAttachmentParameterivOES(
+        int target,
+        int attachment,
+        int pname,
+        int[] params,
+        int offset
+    );
+
+    void glGetFramebufferAttachmentParameterivOES(
+        int target,
+        int attachment,
+        int pname,
+        java.nio.IntBuffer params
+    );
+
+    void glGetIntegerv(
+        int pname,
+        int[] params,
+        int offset
+    );
+
+    void glGetIntegerv(
+        int pname,
+        java.nio.IntBuffer params
+    );
+
+    void glGetRenderbufferParameterivOES(
+        int target,
+        int pname,
+        int[] params,
+        int offset
+    );
+
+    void glGetRenderbufferParameterivOES(
+        int target,
+        int pname,
+        java.nio.IntBuffer params
+    );
+
+    void glGetTexGenfv(
+        int coord,
+        int pname,
+        float[] params,
+        int offset
+    );
+
+    void glGetTexGenfv(
+        int coord,
+        int pname,
+        java.nio.FloatBuffer params
+    );
+
+    void glGetTexGeniv(
+        int coord,
+        int pname,
+        int[] params,
+        int offset
+    );
+
+    void glGetTexGeniv(
+        int coord,
+        int pname,
+        java.nio.IntBuffer params
+    );
+
+    void glGetTexGenxv(
+        int coord,
+        int pname,
+        int[] params,
+        int offset
+    );
+
+    void glGetTexGenxv(
+        int coord,
+        int pname,
+        java.nio.IntBuffer params
+    );
+
+    boolean glIsFramebufferOES(
+        int framebuffer
+    );
+
+    boolean glIsRenderbufferOES(
+        int renderbuffer
+    );
+
+    void glRenderbufferStorageOES(
+        int target,
+        int internalformat,
+        int width,
+        int height
+    );
+
+    void glStencilOp(
+        int fail,
+        int zfail,
+        int zpass
+    );
+
+    void glTexEnvf(
+        int target,
+        int pname,
+        float param
+    );
+
+    void glTexEnvfv(
+        int target,
+        int pname,
+        float[] params,
+        int offset
+    );
+
+    void glTexEnvfv(
+        int target,
+        int pname,
+        java.nio.FloatBuffer params
+    );
+
+    void glTexEnvx(
+        int target,
+        int pname,
+        int param
+    );
+
+    void glTexEnvxv(
+        int target,
+        int pname,
+        int[] params,
+        int offset
+    );
+
+    void glTexEnvxv(
+        int target,
+        int pname,
+        java.nio.IntBuffer params
+    );
+
+    void glTexGenf(
+        int coord,
+        int pname,
+        float param
+    );
+
+    void glTexGenfv(
+        int coord,
+        int pname,
+        float[] params,
+        int offset
+    );
+
+    void glTexGenfv(
+        int coord,
+        int pname,
+        java.nio.FloatBuffer params
+    );
+
+    void glTexGeni(
+        int coord,
+        int pname,
+        int param
+    );
+
+    void glTexGeniv(
+        int coord,
+        int pname,
+        int[] params,
+        int offset
+    );
+
+    void glTexGeniv(
+        int coord,
+        int pname,
+        java.nio.IntBuffer params
+    );
+
+    void glTexGenx(
+        int coord,
+        int pname,
+        int param
+    );
+
+    void glTexGenxv(
+        int coord,
+        int pname,
+        int[] params,
+        int offset
+    );
+
+    void glTexGenxv(
+        int coord,
+        int pname,
+        java.nio.IntBuffer params
+    );
+
+    void glTexParameterf(
+        int target,
+        int pname,
+        float param
+    );
+
+}
diff --git a/javax/net/ServerSocketFactory.java b/javax/net/ServerSocketFactory.java
new file mode 100644
index 0000000..4181544
--- /dev/null
+++ b/javax/net/ServerSocketFactory.java
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 1997, 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 javax.net;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.SocketException;
+
+/**
+ * This class creates server sockets.  It may be subclassed by other
+ * factories, which create particular types of server sockets.  This
+ * provides a general framework for the addition of public socket-level
+ * functionality.  It is the server side analogue of a socket factory,
+ * and similarly provides a way to capture a variety of policies related
+ * to the sockets being constructed.
+ *
+ * <P> Like socket factories, server Socket factory instances have
+ * methods used to create sockets. There is also an environment
+ * specific default server socket factory; frameworks will often use
+ * their own customized factory.
+ *
+ * @since 1.4
+ * @see SocketFactory
+ *
+ * @author David Brownell
+ */
+public abstract class ServerSocketFactory
+{
+    //
+    // NOTE:  JDK 1.1 bug in class GC, this can get collected
+    // even though it's always accessible via getDefault().
+    //
+    private static ServerSocketFactory          theFactory;
+
+
+    /**
+     * Creates a server socket factory.
+     */
+    protected ServerSocketFactory() { /* NOTHING */ }
+
+    /**
+     * Returns a copy of the environment's default socket factory.
+     *
+     * @return the <code>ServerSocketFactory</code>
+     */
+    public static ServerSocketFactory getDefault()
+    {
+        synchronized (ServerSocketFactory.class) {
+            if (theFactory == null) {
+                //
+                // Different implementations of this method could
+                // work rather differently.  For example, driving
+                // this from a system property, or using a different
+                // implementation than JavaSoft's.
+                //
+                theFactory = new DefaultServerSocketFactory();
+            }
+        }
+
+        return theFactory;
+    }
+
+
+    /**
+     * Returns an unbound server socket.  The socket is configured with
+     * the socket options (such as accept timeout) given to this factory.
+     *
+     * @return the unbound socket
+     * @throws IOException if the socket cannot be created
+     * @see java.net.ServerSocket#bind(java.net.SocketAddress)
+     * @see java.net.ServerSocket#bind(java.net.SocketAddress, int)
+     * @see java.net.ServerSocket#ServerSocket()
+     */
+    public ServerSocket createServerSocket() throws IOException {
+        throw new SocketException("Unbound server sockets not implemented");
+    }
+
+    /**
+     * Returns a server socket bound to the specified port.
+     * The socket is configured with the socket options
+     * (such as accept timeout) given to this factory.
+     * <P>
+     * If there is a security manager, its <code>checkListen</code>
+     * method is called with the <code>port</code> argument as its
+     * argument to ensure the operation is allowed. This could result
+     * in a SecurityException.
+     *
+     * @param port the port to listen to
+     * @return the <code>ServerSocket</code>
+     * @throws IOException for networking errors
+     * @throws SecurityException if a security manager exists and its
+     *         <code>checkListen</code> method doesn't allow the operation.
+     * @throws IllegalArgumentException if the port parameter is outside the
+     *         specified range of valid port values, which is between 0 and
+     *         65535, inclusive.
+     * @see    SecurityManager#checkListen
+     * @see java.net.ServerSocket#ServerSocket(int)
+     */
+    public abstract ServerSocket createServerSocket(int port)
+        throws IOException;
+
+
+    /**
+     * Returns a server socket bound to the specified port, and uses the
+     * specified connection backlog.  The socket is configured with
+     * the socket options (such as accept timeout) given to this factory.
+     * <P>
+     * The <code>backlog</code> argument must be a positive
+     * value greater than 0. If the value passed if equal or less
+     * than 0, then the default value will be assumed.
+     * <P>
+     * If there is a security manager, its <code>checkListen</code>
+     * method is called with the <code>port</code> argument as its
+     * argument to ensure the operation is allowed. This could result
+     * in a SecurityException.
+     *
+     * @param port the port to listen to
+     * @param backlog how many connections are queued
+     * @return the <code>ServerSocket</code>
+     * @throws IOException for networking errors
+     * @throws SecurityException if a security manager exists and its
+     *         <code>checkListen</code> method doesn't allow the operation.
+     * @throws IllegalArgumentException if the port parameter is outside the
+     *         specified range of valid port values, which is between 0 and
+     *         65535, inclusive.
+     * @see    SecurityManager#checkListen
+     * @see java.net.ServerSocket#ServerSocket(int, int)
+     */
+    public abstract ServerSocket
+    createServerSocket(int port, int backlog)
+    throws IOException;
+
+
+    /**
+     * Returns a server socket bound to the specified port,
+     * with a specified listen backlog and local IP.
+     * <P>
+     * The <code>ifAddress</code> argument can be used on a multi-homed
+     * host for a <code>ServerSocket</code> that will only accept connect
+     * requests to one of its addresses. If <code>ifAddress</code> is null,
+     * it will accept connections on all local addresses. The socket is
+     * configured with the socket options (such as accept timeout) given
+     * to this factory.
+     * <P>
+     * The <code>backlog</code> argument must be a positive
+     * value greater than 0. If the value passed if equal or less
+     * than 0, then the default value will be assumed.
+     * <P>
+     * If there is a security manager, its <code>checkListen</code>
+     * method is called with the <code>port</code> argument as its
+     * argument to ensure the operation is allowed. This could result
+     * in a SecurityException.
+     *
+     * @param port the port to listen to
+     * @param backlog how many connections are queued
+     * @param ifAddress the network interface address to use
+     * @return the <code>ServerSocket</code>
+     * @throws IOException for networking errors
+     * @throws SecurityException if a security manager exists and its
+     *         <code>checkListen</code> method doesn't allow the operation.
+     * @throws IllegalArgumentException if the port parameter is outside the
+     *         specified range of valid port values, which is between 0 and
+     *         65535, inclusive.
+     * @see    SecurityManager#checkListen
+     * @see java.net.ServerSocket#ServerSocket(int, int, java.net.InetAddress)
+     */
+    public abstract ServerSocket
+    createServerSocket(int port, int backlog, InetAddress ifAddress)
+    throws IOException;
+}
+
+
+//
+// The default factory has NO intelligence.  In fact it's not clear
+// what sort of intelligence servers need; the onus is on clients,
+// who have to know how to tunnel etc.
+//
+class DefaultServerSocketFactory extends ServerSocketFactory {
+
+    DefaultServerSocketFactory()
+    {
+        /* NOTHING */
+    }
+
+    public ServerSocket createServerSocket()
+    throws IOException
+    {
+        return new ServerSocket();
+    }
+
+    public ServerSocket createServerSocket(int port)
+    throws IOException
+    {
+        return new ServerSocket(port);
+    }
+
+    public ServerSocket createServerSocket(int port, int backlog)
+    throws IOException
+    {
+        return new ServerSocket(port, backlog);
+    }
+
+    public ServerSocket
+    createServerSocket(int port, int backlog, InetAddress ifAddress)
+    throws IOException
+    {
+        return new ServerSocket(port, backlog, ifAddress);
+    }
+}
diff --git a/javax/net/SocketFactory.java b/javax/net/SocketFactory.java
new file mode 100644
index 0000000..3c89371
--- /dev/null
+++ b/javax/net/SocketFactory.java
@@ -0,0 +1,301 @@
+/*
+ * Copyright (c) 1997, 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 javax.net;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+
+/**
+ * This class creates sockets.  It may be subclassed by other factories,
+ * which create particular subclasses of sockets and thus provide a general
+ * framework for the addition of public socket-level functionality.
+ *
+ * <P> Socket factories are a simple way to capture a variety of policies
+ * related to the sockets being constructed, producing such sockets in
+ * a way which does not require special configuration of the code which
+ * asks for the sockets:  <UL>
+ *
+ *      <LI> Due to polymorphism of both factories and sockets, different
+ *      kinds of sockets can be used by the same application code just
+ *      by passing it different kinds of factories.
+ *
+ *      <LI> Factories can themselves be customized with parameters used
+ *      in socket construction.  So for example, factories could be
+ *      customized to return sockets with different networking timeouts
+ *      or security parameters already configured.
+ *
+ *      <LI> The sockets returned to the application can be subclasses
+ *      of java.net.Socket, so that they can directly expose new APIs
+ *      for features such as compression, security, record marking,
+ *      statistics collection, or firewall tunneling.
+ *
+ *      </UL>
+ *
+ * <P> Factory classes are specified by environment-specific configuration
+ * mechanisms.  For example, the <em>getDefault</em> method could return
+ * a factory that was appropriate for a particular user or applet, and a
+ * framework could use a factory customized to its own purposes.
+ *
+ * @since 1.4
+ * @see ServerSocketFactory
+ *
+ * @author David Brownell
+ */
+public abstract class SocketFactory
+{
+    //
+    // NOTE:  JDK 1.1 bug in class GC, this can get collected
+    // even though it's always accessible via getDefault().
+    //
+    private static SocketFactory                theFactory;
+
+    /**
+     * Creates a <code>SocketFactory</code>.
+     */
+    protected SocketFactory() { /* NOTHING */ }
+
+
+    /**
+     * Returns a copy of the environment's default socket factory.
+     *
+     * @return the default <code>SocketFactory</code>
+     */
+    public static SocketFactory getDefault()
+    {
+        synchronized (SocketFactory.class) {
+            if (theFactory == null) {
+                //
+                // Different implementations of this method SHOULD
+                // work rather differently.  For example, driving
+                // this from a system property, or using a different
+                // implementation than JavaSoft's.
+                //
+                theFactory = new DefaultSocketFactory();
+            }
+        }
+
+        return theFactory;
+    }
+
+    // Android-added: Added method for testing default socket factory.
+    /** @hide Visible for testing only */
+    public static void setDefault(SocketFactory factory) {
+        synchronized (SocketFactory.class) {
+            theFactory = factory;
+        }
+    }
+
+
+    /**
+     * Creates an unconnected socket.
+     *
+     * @return the unconnected socket
+     * @throws IOException if the socket cannot be created
+     * @see java.net.Socket#connect(java.net.SocketAddress)
+     * @see java.net.Socket#connect(java.net.SocketAddress, int)
+     * @see java.net.Socket#Socket()
+     */
+    public Socket createSocket() throws IOException {
+        //
+        // bug 6771432:
+        // The Exception is used by HttpsClient to signal that
+        // unconnected sockets have not been implemented.
+        //
+        UnsupportedOperationException uop = new
+                UnsupportedOperationException();
+        SocketException se =  new SocketException(
+                "Unconnected sockets not implemented");
+        se.initCause(uop);
+        throw se;
+    }
+
+
+    /**
+     * Creates a socket and connects it to the specified remote host
+     * at the specified remote port.  This socket is configured using
+     * the socket options established for this factory.
+     * <p>
+     * If there is a security manager, its <code>checkConnect</code>
+     * method is called with the host address and <code>port</code>
+     * as its arguments. This could result in a SecurityException.
+     *
+     * @param host the server host name with which to connect, or
+     *        <code>null</code> for the loopback address.
+     * @param port the server port
+     * @return the <code>Socket</code>
+     * @throws IOException if an I/O error occurs when creating the socket
+     * @throws SecurityException if a security manager exists and its
+     *         <code>checkConnect</code> method doesn't allow the operation.
+     * @throws UnknownHostException if the host is not known
+     * @throws IllegalArgumentException if the port parameter is outside the
+     *         specified range of valid port values, which is between 0 and
+     *         65535, inclusive.
+     * @see SecurityManager#checkConnect
+     * @see java.net.Socket#Socket(String, int)
+     */
+    public abstract Socket createSocket(String host, int port)
+    throws IOException, UnknownHostException;
+
+
+    /**
+     * Creates a socket and connects it to the specified remote host
+     * on the specified remote port.
+     * The socket will also be bound to the local address and port supplied.
+     * This socket is configured using
+     * the socket options established for this factory.
+     * <p>
+     * If there is a security manager, its <code>checkConnect</code>
+     * method is called with the host address and <code>port</code>
+     * as its arguments. This could result in a SecurityException.
+     *
+     * @param host the server host name with which to connect, or
+     *        <code>null</code> for the loopback address.
+     * @param port the server port
+     * @param localHost the local address the socket is bound to
+     * @param localPort the local port the socket is bound to
+     * @return the <code>Socket</code>
+     * @throws IOException if an I/O error occurs when creating the socket
+     * @throws SecurityException if a security manager exists and its
+     *         <code>checkConnect</code> method doesn't allow the operation.
+     * @throws UnknownHostException if the host is not known
+     * @throws 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
+     * @see java.net.Socket#Socket(String, int, java.net.InetAddress, int)
+     */
+    public abstract Socket
+    createSocket(String host, int port, InetAddress localHost, int localPort)
+    throws IOException, UnknownHostException;
+
+
+    /**
+     * Creates a socket and connects it to the specified port number
+     * at the specified address.  This socket is configured using
+     * the socket options established for this factory.
+     * <p>
+     * If there is a security manager, its <code>checkConnect</code>
+     * method is called with the host address and <code>port</code>
+     * as its arguments. This could result in a SecurityException.
+     *
+     * @param host the server host
+     * @param port the server port
+     * @return the <code>Socket</code>
+     * @throws IOException if an I/O error occurs when creating the socket
+     * @throws SecurityException if a security manager exists and its
+     *         <code>checkConnect</code> method doesn't allow the operation.
+     * @throws IllegalArgumentException if the port parameter is outside the
+     *         specified range of valid port values, which is between 0 and
+     *         65535, inclusive.
+     * @throws NullPointerException if <code>host</code> is null.
+     * @see SecurityManager#checkConnect
+     * @see java.net.Socket#Socket(java.net.InetAddress, int)
+     */
+    public abstract Socket createSocket(InetAddress host, int port)
+    throws IOException;
+
+
+    /**
+     * Creates a socket and connect it to the specified remote address
+     * on the specified remote port.  The socket will also be bound
+     * to the local address and port suplied.  The socket is configured using
+     * the socket options established for this factory.
+     * <p>
+     * If there is a security manager, its <code>checkConnect</code>
+     * method is called with the host address and <code>port</code>
+     * as its arguments. This could result in a SecurityException.
+     *
+     * @param address the server network address
+     * @param port the server port
+     * @param localAddress the client network address
+     * @param localPort the client port
+     * @return the <code>Socket</code>
+     * @throws IOException if an I/O error occurs when creating the socket
+     * @throws SecurityException if a security manager exists and its
+     *         <code>checkConnect</code> method doesn't allow the operation.
+     * @throws IllegalArgumentException if the port parameter or localPort
+     *         parameter is outside the specified range of valid port values,
+     *         which is between 0 and 65535, inclusive.
+     * @throws NullPointerException if <code>address</code> is null.
+     * @see SecurityManager#checkConnect
+     * @see java.net.Socket#Socket(java.net.InetAddress, int,
+     *     java.net.InetAddress, int)
+     */
+    public abstract Socket
+    createSocket(InetAddress address, int port,
+        InetAddress localAddress, int localPort)
+    throws IOException;
+}
+
+
+//
+// The default factory has NO intelligence about policies like tunneling
+// out through firewalls (e.g. SOCKS V4 or V5) or in through them
+// (e.g. using SSL), or that some ports are reserved for use with SSL.
+//
+// Note that at least JDK 1.1 has a low level "plainSocketImpl" that
+// knows about SOCKS V4 tunneling, so this isn't a totally bogus default.
+//
+// ALSO:  we may want to expose this class somewhere so other folk
+// can reuse it, particularly if we start to add highly useful features
+// such as ability to set connect timeouts.
+//
+class DefaultSocketFactory extends SocketFactory {
+
+    public Socket createSocket() {
+        return new Socket();
+    }
+
+    public Socket createSocket(String host, int port)
+    throws IOException, UnknownHostException
+    {
+        return new Socket(host, port);
+    }
+
+    public Socket createSocket(InetAddress address, int port)
+    throws IOException
+    {
+        return new Socket(address, port);
+    }
+
+    public Socket createSocket(String host, int port,
+        InetAddress clientAddress, int clientPort)
+    throws IOException, UnknownHostException
+    {
+        return new Socket(host, port, clientAddress, clientPort);
+    }
+
+    public Socket createSocket(InetAddress address, int port,
+        InetAddress clientAddress, int clientPort)
+    throws IOException
+    {
+        return new Socket(address, port, clientAddress, clientPort);
+    }
+}
diff --git a/javax/net/ssl/CertPathTrustManagerParameters.java b/javax/net/ssl/CertPathTrustManagerParameters.java
new file mode 100644
index 0000000..22a5315
--- /dev/null
+++ b/javax/net/ssl/CertPathTrustManagerParameters.java
@@ -0,0 +1,71 @@
+/*
+ * 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 javax.net.ssl;
+
+import java.security.cert.CertPathParameters;
+
+/**
+ * A wrapper for CertPathParameters. This class is used to pass validation
+ * settings to CertPath based {@link TrustManager}s using the
+ * {@link TrustManagerFactory#init(ManagerFactoryParameters)
+ * TrustManagerFactory.init()} method.
+ *
+ * <p>Instances of this class are immutable.
+ *
+ * @see X509TrustManager
+ * @see TrustManagerFactory
+ * @see java.security.cert.CertPathParameters
+ *
+ * @since   1.5
+ * @author  Andreas Sterbenz
+ */
+public class CertPathTrustManagerParameters implements ManagerFactoryParameters {
+
+    private final CertPathParameters parameters;
+
+    /**
+     * Construct new CertPathTrustManagerParameters from the specified
+     * parameters. The parameters are cloned to protect against subsequent
+     * modification.
+     *
+     * @param parameters the CertPathParameters to be used
+     *
+     * @throws NullPointerException if parameters is null
+     */
+    public CertPathTrustManagerParameters(CertPathParameters parameters) {
+        this.parameters = (CertPathParameters)parameters.clone();
+    }
+
+    /**
+     * Return a clone of the CertPathParameters encapsulated by this class.
+     *
+     * @return a clone of the CertPathParameters encapsulated by this class.
+     */
+    public CertPathParameters getParameters() {
+        return (CertPathParameters)parameters.clone();
+    }
+
+}
diff --git a/javax/net/ssl/ExtendedSSLSession.java b/javax/net/ssl/ExtendedSSLSession.java
new file mode 100644
index 0000000..70f98ce
--- /dev/null
+++ b/javax/net/ssl/ExtendedSSLSession.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2010, 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 javax.net.ssl;
+
+import java.util.List;
+
+/**
+ * Extends the <code>SSLSession</code> interface to support additional
+ * session attributes.
+ *
+ * @since 1.7
+ */
+public abstract class ExtendedSSLSession implements SSLSession {
+    /**
+     * Obtains an array of supported signature algorithms that the local side
+     * is willing to use.
+     * <p>
+     * Note: this method is used to indicate to the peer which signature
+     * algorithms may be used for digital signatures in TLS 1.2. It is
+     * not meaningful for TLS versions prior to 1.2.
+     * <p>
+     * The signature algorithm name must be a standard Java Security
+     * name (such as "SHA1withRSA", "SHA256withECDSA", and so on).
+     * See Appendix A in the <a href=
+     * "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
+     * Java Cryptography Architecture API Specification &amp; Reference </a>
+     * for information about standard algorithm names.
+     * <p>
+     * Note: the local supported signature algorithms should conform to
+     * the algorithm constraints specified by
+     * {@link SSLParameters#getAlgorithmConstraints getAlgorithmConstraints()}
+     * method in <code>SSLParameters</code>.
+     *
+     * @return An array of supported signature algorithms, in descending
+     *     order of preference.  The return value is an empty array if
+     *     no signature algorithm is supported.
+     *
+     * @see SSLParameters#getAlgorithmConstraints
+     */
+    public abstract String[] getLocalSupportedSignatureAlgorithms();
+
+    /**
+     * Obtains an array of supported signature algorithms that the peer is
+     * able to use.
+     * <p>
+     * Note: this method is used to indicate to the local side which signature
+     * algorithms may be used for digital signatures in TLS 1.2. It is
+     * not meaningful for TLS versions prior to 1.2.
+     * <p>
+     * The signature algorithm name must be a standard Java Security
+     * name (such as "SHA1withRSA", "SHA256withECDSA", and so on).
+     * See Appendix A in the <a href=
+     * "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
+     * Java Cryptography Architecture API Specification &amp; Reference </a>
+     * for information about standard algorithm names.
+     *
+     * @return An array of supported signature algorithms, in descending
+     *     order of preference.  The return value is an empty array if
+     *     the peer has not sent the supported signature algorithms.
+     *
+     * @see X509KeyManager
+     * @see X509ExtendedKeyManager
+     */
+    public abstract String[] getPeerSupportedSignatureAlgorithms();
+
+    /**
+     * Obtains a {@link List} containing all {@link SNIServerName}s
+     * of the requested Server Name Indication (SNI) extension.
+     * <P>
+     * In server mode, unless the return {@link List} is empty,
+     * the server should use the requested server names to guide its
+     * selection of an appropriate authentication certificate, and/or
+     * other aspects of security policy.
+     * <P>
+     * In client mode, unless the return {@link List} is empty,
+     * the client should use the requested server names to guide its
+     * endpoint identification of the peer's identity, and/or
+     * other aspects of security policy.
+     *
+     * @return a non-null immutable list of {@link SNIServerName}s of the
+     *         requested server name indications. The returned list may be
+     *         empty if no server name indications were requested.
+     * @throws UnsupportedOperationException if the underlying provider
+     *         does not implement the operation
+     *
+     * @see SNIServerName
+     * @see X509ExtendedTrustManager
+     * @see X509ExtendedKeyManager
+     *
+     * @since 1.8
+     */
+    public List<SNIServerName> getRequestedServerNames() {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/javax/net/ssl/HandshakeCompletedEvent.java b/javax/net/ssl/HandshakeCompletedEvent.java
new file mode 100644
index 0000000..f6abafa
--- /dev/null
+++ b/javax/net/ssl/HandshakeCompletedEvent.java
@@ -0,0 +1,235 @@
+/*
+ * 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 javax.net.ssl;
+
+import java.util.EventObject;
+import java.security.cert.Certificate;
+import java.security.Principal;
+import java.security.cert.X509Certificate;
+
+/**
+ * This event indicates that an SSL handshake completed on a given
+ * SSL connection.  All of the core information about that handshake's
+ * result is captured through an "SSLSession" object.  As a convenience,
+ * this event class provides direct access to some important session
+ * attributes.
+ *
+ * <P> The source of this event is the SSLSocket on which handshaking
+ * just completed.
+ *
+ * @see SSLSocket
+ * @see HandshakeCompletedListener
+ * @see SSLSession
+ *
+ * @since 1.4
+ * @author David Brownell
+ */
+public class HandshakeCompletedEvent extends EventObject
+{
+    private static final long serialVersionUID = 7914963744257769778L;
+
+    private transient SSLSession session;
+
+    /**
+     * Constructs a new HandshakeCompletedEvent.
+     *
+     * @param sock the SSLSocket acting as the source of the event
+     * @param s the SSLSession this event is associated with
+     */
+    public HandshakeCompletedEvent(SSLSocket sock, SSLSession s)
+    {
+        super(sock);
+        session = s;
+    }
+
+
+    /**
+     * Returns the session that triggered this event.
+     *
+     * @return the <code>SSLSession</code> for this handshake
+     */
+    public SSLSession getSession()
+    {
+        return session;
+    }
+
+
+    /**
+     * Returns the cipher suite in use by the session which was produced
+     * by the handshake.  (This is a convenience method for
+     * getting the ciphersuite from the SSLsession.)
+     *
+     * @return the name of the cipher suite negotiated during this session.
+     */
+    public String getCipherSuite()
+    {
+        return session.getCipherSuite();
+    }
+
+
+    /**
+     * Returns the certificate(s) that were sent to the peer during
+     * handshaking.
+     * Note: This method is useful only when using certificate-based
+     * cipher suites.
+     *
+     * When multiple certificates are available for use in a
+     * handshake, the implementation chooses what it considers the
+     * "best" certificate chain available, and transmits that to
+     * the other side.  This method allows the caller to know
+     * which certificate chain was actually used.
+     *
+     * @return an ordered array of certificates, with the local
+     *          certificate first followed by any
+     *          certificate authorities.  If no certificates were sent,
+     *          then null is returned.
+     * @see #getLocalPrincipal()
+     */
+    public java.security.cert.Certificate [] getLocalCertificates()
+    {
+        return session.getLocalCertificates();
+    }
+
+
+    /**
+     * Returns the identity of the peer which was established as part
+     * of defining the session.
+     * 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 ordered array of the peer certificates,
+     *          with the peer's own certificate first followed by
+     *          any certificate authorities.
+     * @exception SSLPeerUnverifiedException if the peer is not verified.
+     * @see #getPeerPrincipal()
+     */
+    public java.security.cert.Certificate [] getPeerCertificates()
+            throws SSLPeerUnverifiedException
+    {
+        return session.getPeerCertificates();
+    }
+
+
+    /**
+     * Returns the identity of the peer which was identified as part
+     * of defining the session.
+     * 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.
+     *
+     * <p><em>Note: this method exists for compatibility with previous
+     * releases. New applications should use
+     * {@link #getPeerCertificates} instead.</em></p>
+     *
+     * @return an ordered array of peer X.509 certificates,
+     *          with the peer's own certificate first followed by any
+     *          certificate authorities.  (The certificates are in
+     *          the original JSSE
+     *          {@link javax.security.cert.X509Certificate} format).
+     * @exception SSLPeerUnverifiedException if the peer is not verified.
+     * @see #getPeerPrincipal()
+     */
+    public javax.security.cert.X509Certificate [] getPeerCertificateChain()
+            throws SSLPeerUnverifiedException
+    {
+        return session.getPeerCertificateChain();
+    }
+
+    /**
+     * Returns the identity of the peer which was established as part of
+     * defining the session.
+     *
+     * @return the peer'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's identity has not
+     *          been verified
+     *
+     * @see #getPeerCertificates()
+     * @see #getLocalPrincipal()
+     *
+     * @since 1.5
+     */
+    public Principal getPeerPrincipal()
+            throws SSLPeerUnverifiedException
+    {
+        Principal principal;
+        try {
+            principal = session.getPeerPrincipal();
+        } catch (AbstractMethodError e) {
+            // if the provider does not support it, fallback to peer certs.
+            // return the X500Principal of the end-entity cert.
+            Certificate[] certs = getPeerCertificates();
+            principal = ((X509Certificate)certs[0]).getSubjectX500Principal();
+        }
+        return principal;
+    }
+
+    /**
+     * Returns the principal that was sent to the peer during handshaking.
+     *
+     * @return the principal sent to the peer. 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 #getLocalCertificates()
+     * @see #getPeerPrincipal()
+     *
+     * @since 1.5
+     */
+    public Principal getLocalPrincipal()
+    {
+        Principal principal;
+        try {
+            principal = session.getLocalPrincipal();
+        } catch (AbstractMethodError e) {
+            principal = null;
+            // if the provider does not support it, fallback to local certs.
+            // return the X500Principal of the end-entity cert.
+            Certificate[] certs = getLocalCertificates();
+            if (certs != null) {
+                principal =
+                        ((X509Certificate)certs[0]).getSubjectX500Principal();
+            }
+        }
+        return principal;
+    }
+
+    /**
+     * Returns the socket which is the source of this event.
+     * (This is a convenience function, to let applications
+     * write code without type casts.)
+     *
+     * @return the socket on which the connection was made.
+     */
+    public SSLSocket getSocket()
+    {
+        return (SSLSocket) getSource();
+    }
+}
diff --git a/javax/net/ssl/HandshakeCompletedListener.java b/javax/net/ssl/HandshakeCompletedListener.java
new file mode 100644
index 0000000..cd4f4d7
--- /dev/null
+++ b/javax/net/ssl/HandshakeCompletedListener.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1997, 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 javax.net.ssl;
+
+import java.util.EventListener;
+
+/**
+ * This interface is implemented by any class which wants to receive
+ * notifications about the completion of an SSL protocol handshake
+ * on a given SSL connection.
+ *
+ * <P> When an SSL handshake completes, new security parameters will
+ * have been established.  Those parameters always include the security
+ * keys used to protect messages.  They may also include parameters
+ * associated with a new <em>session</em> such as authenticated
+ * peer identity and a new SSL cipher suite.
+ *
+ * @since 1.4
+ * @author David Brownell
+ */
+public interface HandshakeCompletedListener extends EventListener
+{
+    /**
+     * This method is invoked on registered objects
+     * when a SSL handshake is completed.
+     *
+     * @param event the event identifying when the SSL Handshake
+     *          completed on a given SSL connection
+     */
+    void handshakeCompleted(HandshakeCompletedEvent event);
+}
diff --git a/javax/net/ssl/HostnameVerifier.java b/javax/net/ssl/HostnameVerifier.java
new file mode 100644
index 0000000..d876877
--- /dev/null
+++ b/javax/net/ssl/HostnameVerifier.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2001, 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 javax.net.ssl;
+
+// Android-changed: Clarified use of HostnameVerifier on Android.
+/**
+ * This class is the base interface for hostname verification.
+ * <P>
+ * During handshaking, the
+ * verification mechanism can call back to implementers of this
+ * interface to determine if this connection should be allowed.
+ * <p>
+ * For more information of the use of this interface on Android, see
+ * {@link HttpsURLConnection#setDefaultHostnameVerifier(HostnameVerifier)}.
+ * <P>
+ * The policies can be certificate-based
+ * or may depend on other authentication schemes.
+ *
+ * @author Brad R. Wetmore
+ * @since 1.4
+ */
+
+public interface HostnameVerifier {
+    /**
+     * Verify that the host name is an acceptable match with
+     * the server's authentication scheme.
+     *
+     * @param hostname the host name
+     * @param session SSLSession used on the connection to host
+     * @return true if the host name is acceptable
+     */
+    public boolean verify(String hostname, SSLSession session);
+}
diff --git a/javax/net/ssl/HttpsURLConnection.java b/javax/net/ssl/HttpsURLConnection.java
new file mode 100644
index 0000000..c3e3c30
--- /dev/null
+++ b/javax/net/ssl/HttpsURLConnection.java
@@ -0,0 +1,455 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1999, 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 javax.net.ssl;
+
+import java.net.URL;
+import java.net.HttpURLConnection;
+import java.security.Principal;
+import java.security.cert.X509Certificate;
+import libcore.api.CorePlatformApi;
+
+/**
+ * <code>HttpsURLConnection</code> extends <code>HttpURLConnection</code>
+ * with support for https-specific features.
+ * <P>
+ * See <A HREF="http://www.w3.org/pub/WWW/Protocols/">
+ * http://www.w3.org/pub/WWW/Protocols/</A> and
+ * <A HREF="http://www.ietf.org/"> RFC 2818 </A>
+ * for more details on the
+ * https specification.
+ * <P>
+ * This class uses <code>HostnameVerifier</code> and
+ * <code>SSLSocketFactory</code>.
+ * There are default implementations defined for both classes.
+ * However, the implementations can be replaced on a per-class (static) or
+ * per-instance basis.  All new <code>HttpsURLConnection</code>s instances
+ * will be assigned
+ * the "default" static values at instance creation, but they can be overriden
+ * by calling the appropriate per-instance set method(s) before
+ * <code>connect</code>ing.
+ *
+ * @since 1.4
+ */
+abstract public
+class HttpsURLConnection extends HttpURLConnection
+{
+    /**
+     * Creates an <code>HttpsURLConnection</code> using the
+     * URL specified.
+     *
+     * @param url the URL
+     */
+    protected HttpsURLConnection(URL url) {
+        super(url);
+    }
+
+    /**
+     * Returns the cipher suite in use on this connection.
+     *
+     * @return the cipher suite
+     * @throws IllegalStateException if this method is called before
+     *          the connection has been established.
+     */
+    public abstract String getCipherSuite();
+
+    /**
+     * Returns the certificate(s) that were sent to the server during
+     * handshaking.
+     * <P>
+     * Note: This method is useful only when using certificate-based
+     * cipher suites.
+     * <P>
+     * When multiple certificates are available for use in a
+     * handshake, the implementation chooses what it considers the
+     * "best" certificate chain available, and transmits that to
+     * the other side.  This method allows the caller to know
+     * which certificate chain was actually sent.
+     *
+     * @return an ordered array of certificates,
+     *          with the client's own certificate first followed by any
+     *          certificate authorities.  If no certificates were sent,
+     *          then null is returned.
+     * @throws IllegalStateException if this method is called before
+     *          the connection has been established.
+     * @see #getLocalPrincipal()
+     */
+    public abstract java.security.cert.Certificate [] getLocalCertificates();
+
+    /**
+     * Returns the server's certificate chain which was established
+     * as part of defining the session.
+     * <P>
+     * 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 ordered array of server certificates,
+     *          with the peer's own certificate first followed by
+     *          any certificate authorities.
+     * @throws SSLPeerUnverifiedException if the peer is not verified.
+     * @throws IllegalStateException if this method is called before
+     *          the connection has been established.
+     * @see #getPeerPrincipal()
+     */
+    public abstract java.security.cert.Certificate [] getServerCertificates()
+            throws SSLPeerUnverifiedException;
+
+    /**
+     * Returns the server's principal which was established as part of
+     * defining the session.
+     * <P>
+     * Note: Subclasses should override this method. If not overridden, it
+     * will default to returning the X500Principal of the server's end-entity
+     * certificate for certificate-based ciphersuites, or throw an
+     * SSLPeerUnverifiedException for non-certificate based ciphersuites,
+     * such as Kerberos.
+     *
+     * @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
+     * @throws IllegalStateException if this method is called before
+     *          the connection has been established.
+     *
+     * @see #getServerCertificates()
+     * @see #getLocalPrincipal()
+     *
+     * @since 1.5
+     */
+    public Principal getPeerPrincipal()
+            throws SSLPeerUnverifiedException {
+
+        java.security.cert.Certificate[] certs = getServerCertificates();
+        return ((X509Certificate)certs[0]).getSubjectX500Principal();
+    }
+
+    /**
+     * Returns the principal that was sent to the server during handshaking.
+     * <P>
+     * Note: Subclasses should override this method. If not overridden, it
+     * will default to returning the X500Principal of the end-entity certificate
+     * that was sent to the server for certificate-based ciphersuites or,
+     * return null for non-certificate based ciphersuites, such as Kerberos.
+     *
+     * @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.
+     *
+     * @throws IllegalStateException if this method is called before
+     *          the connection has been established.
+     *
+     * @see #getLocalCertificates()
+     * @see #getPeerPrincipal()
+     *
+     * @since 1.5
+     */
+    public Principal getLocalPrincipal() {
+
+        java.security.cert.Certificate[] certs = getLocalCertificates();
+        if (certs != null) {
+            return ((X509Certificate)certs[0]).getSubjectX500Principal();
+        } else {
+            return null;
+        }
+    }
+
+    // BEGIN Android-changed: Use holder class idiom for a lazily-created OkHttp hostname verifier.
+    // The RI default hostname verifier is a static member of the class, which means
+    // it's created when the class is initialized.  As well, its default verifier
+    // just fails all verification attempts, whereas we use OkHttp's verifier.
+    /*
+     * Holds the default instance so class preloading doesn't create an instance of
+     * it.
+     */
+    private static final String OK_HOSTNAME_VERIFIER_CLASS
+        = "com.android.okhttp.internal.tls.OkHostnameVerifier";
+    private static class NoPreloadHolder {
+        public static HostnameVerifier defaultHostnameVerifier;
+        static {
+            try {
+                /**
+                  * <code>HostnameVerifier</code> provides a callback mechanism so that
+                  * implementers of this interface can supply a policy for
+                  * handling the case where the host to connect to and
+                  * the server name from the certificate mismatch.
+                  */
+                defaultHostnameVerifier = (HostnameVerifier)
+                        Class.forName(OK_HOSTNAME_VERIFIER_CLASS)
+                        .getField("INSTANCE").get(null);
+            } catch (Exception e) {
+                throw new AssertionError("Failed to obtain okhttp HostnameVerifier", e);
+            }
+        }
+    }
+
+    /**
+     * The <code>hostnameVerifier</code> for this object.
+     */
+    protected HostnameVerifier hostnameVerifier = NoPreloadHolder.defaultHostnameVerifier;
+    // END Android-changed: Use holder class idiom for a lazily-created OkHttp hostname verifier.
+
+    // Android-changed: Modified the documentation to explain side effects / discourage method use.
+    /**
+     * Sets the default <code>HostnameVerifier</code> inherited by a
+     * new instance of this class.
+     * <p>
+     * Developers are <em>strongly</em> discouraged from changing the default
+     * {@code HostnameVerifier} as {@link #getDefaultHostnameVerifier()} is used by several
+     * classes for hostname verification on Android.
+     * <table>
+     *     <tr>
+     *         <th>User</th>
+     *         <th>Effect</th>
+     *     </tr>
+     *     <tr>
+     *         <td>Android's default {@link TrustManager}, as used with Android's default
+     *         {@link SSLContext}, {@link SSLSocketFactory} and {@link SSLSocket} implementations.
+     *         </td>
+     *         <td>The {@code HostnameVerifier} is used to verify the peer's
+     *         certificate hostname after connecting if {@code
+     *         SSLParameters.setEndpointIdentificationAlgorithm("HTTPS")} has been called.
+     *         Instances use the <em>current</em> default {@code HostnameVerifier} at verification
+     *         time.</td>
+     *     </tr>
+     *     <tr>
+     *         <td>{@link android.net.SSLCertificateSocketFactory}</td>
+     *         <td>The current default {@code HostnameVerifier} is used from various {@code
+     *         createSocket} methods. See {@link android.net.SSLCertificateSocketFactory} for
+     *         details; for example {@link
+     *         android.net.SSLCertificateSocketFactory#createSocket(String, int)}.
+     *         </td>
+     *     </tr>
+     *     <tr>
+     *         <td>Android's default {@link HttpsURLConnection} implementation.</td>
+     *         <td>The {@code HostnameVerifier} is used after a successful TLS handshake to verify
+     *         the URI host against the TLS session server. Instances use the default {@code
+     *         HostnameVerifier} set <em>when they were created</em> unless overridden with {@link
+     *         #setHostnameVerifier(HostnameVerifier)}.
+     *         Android's <code>HttpsURLConnection</code> relies on the {@code HostnameVerifier}
+     *         for the <em>entire</em> hostname verification step.</td>
+     *     </tr>
+     * </table>
+     * <p>
+     * If this method is not called, the default <code>HostnameVerifier</code> will check the
+     * hostname according to RFC 2818.
+     *
+     * @param v the default host name verifier
+     * @throws IllegalArgumentException if the <code>HostnameVerifier</code>
+     *          parameter is null.
+     * @throws SecurityException if a security manager exists and its
+     *         <code>checkPermission</code> method does not allow
+     *         <code>SSLPermission("setHostnameVerifier")</code>
+     * @see #getDefaultHostnameVerifier()
+     */
+    public static void setDefaultHostnameVerifier(HostnameVerifier v) {
+        if (v == null) {
+            throw new IllegalArgumentException(
+                "no default HostnameVerifier specified");
+        }
+
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(new SSLPermission("setHostnameVerifier"));
+        }
+        // Android-changed: Use holder class idiom for a lazily-created OkHttp hostname verifier.
+        // defaultHostnameVerifier = v;
+        NoPreloadHolder.defaultHostnameVerifier = v;
+    }
+
+    /**
+     * Gets the default <code>HostnameVerifier</code> that is inherited
+     * by new instances of this class.
+     *
+     * @return the default host name verifier
+     * @see #setDefaultHostnameVerifier(HostnameVerifier)
+     */
+    public static HostnameVerifier getDefaultHostnameVerifier() {
+        // Android-changed: Use holder class idiom for a lazily-created OkHttp hostname verifier.
+        // return defaultHostnameVerifier;
+        return NoPreloadHolder.defaultHostnameVerifier;
+    }
+
+    // Android-changed: Modified the documentation to explain Android behavior.
+    /**
+     * Sets the <code>HostnameVerifier</code> for this instance.
+     * <P>
+     * New instances of this class inherit the default static hostname
+     * verifier set by {@link #setDefaultHostnameVerifier(HostnameVerifier)
+     * setDefaultHostnameVerifier}.  Calls to this method replace
+     * this object's <code>HostnameVerifier</code>.
+     * <p>
+     * Android's <code>HttpsURLConnection</code> relies on the {@code HostnameVerifier}
+     * for the <em>entire</em> hostname verification step.
+     *
+     * @param v the host name verifier
+     * @throws IllegalArgumentException if the <code>HostnameVerifier</code>
+     *  parameter is null.
+     * @see #getHostnameVerifier()
+     * @see #setDefaultHostnameVerifier(HostnameVerifier)
+     */
+    public void setHostnameVerifier(HostnameVerifier v) {
+        if (v == null) {
+            throw new IllegalArgumentException(
+                "no HostnameVerifier specified");
+        }
+
+        hostnameVerifier = v;
+    }
+
+    // BEGIN Android-added: Core platform API to obtain a strict hostname verifier
+    /**
+     * Obtains a stricter <code>HostnameVerifier</code>.
+     *
+     * The <code>HostnameVerifier</code> returned by this method will reject certificates
+     * with wildcards for top-level domains such "*.com".
+     *
+     * @see com.squareup.okhttp.internal.tls.OkHostnameVerifier
+     *
+     * @hide
+     */
+    @CorePlatformApi
+    public static HostnameVerifier getStrictHostnameVerifier() {
+        try {
+            return (HostnameVerifier) Class
+                .forName(OK_HOSTNAME_VERIFIER_CLASS)
+                .getMethod("strictInstance")
+                .invoke(null);
+        } catch (Exception e) {
+            return null;
+        }
+     }
+    // END Android-added: Core platform API to obtain a strict hostname verifier
+
+    /**
+     * Gets the <code>HostnameVerifier</code> in place on this instance.
+     *
+     * @return the host name verifier
+     * @see #setHostnameVerifier(HostnameVerifier)
+     * @see #setDefaultHostnameVerifier(HostnameVerifier)
+     */
+    public HostnameVerifier getHostnameVerifier() {
+        return hostnameVerifier;
+    }
+
+    private static SSLSocketFactory defaultSSLSocketFactory = null;
+
+    /**
+     * The <code>SSLSocketFactory</code> inherited when an instance
+     * of this class is created.
+     */
+    private SSLSocketFactory sslSocketFactory = getDefaultSSLSocketFactory();
+
+    /**
+     * Sets the default <code>SSLSocketFactory</code> inherited by new
+     * instances of this class.
+     * <P>
+     * The socket factories are used when creating sockets for secure
+     * https URL connections.
+     *
+     * @param sf the default SSL socket factory
+     * @throws IllegalArgumentException if the SSLSocketFactory
+     *          parameter is null.
+     * @throws SecurityException if a security manager exists and its
+     *         <code>checkSetFactory</code> method does not allow
+     *         a socket factory to be specified.
+     * @see #getDefaultSSLSocketFactory()
+     */
+    public static void setDefaultSSLSocketFactory(SSLSocketFactory sf) {
+        if (sf == null) {
+            throw new IllegalArgumentException(
+                "no default SSLSocketFactory specified");
+        }
+
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkSetFactory();
+        }
+        defaultSSLSocketFactory = sf;
+    }
+
+    /**
+     * Gets the default static <code>SSLSocketFactory</code> that is
+     * inherited by new instances of this class.
+     * <P>
+     * The socket factories are used when creating sockets for secure
+     * https URL connections.
+     *
+     * @return the default <code>SSLSocketFactory</code>
+     * @see #setDefaultSSLSocketFactory(SSLSocketFactory)
+     */
+    public static SSLSocketFactory getDefaultSSLSocketFactory() {
+        if (defaultSSLSocketFactory == null) {
+            defaultSSLSocketFactory =
+                (SSLSocketFactory)SSLSocketFactory.getDefault();
+        }
+        return defaultSSLSocketFactory;
+    }
+
+    /**
+     * Sets the <code>SSLSocketFactory</code> to be used when this instance
+     * creates sockets for secure https URL connections.
+     * <P>
+     * New instances of this class inherit the default static
+     * <code>SSLSocketFactory</code> set by
+     * {@link #setDefaultSSLSocketFactory(SSLSocketFactory)
+     * setDefaultSSLSocketFactory}.  Calls to this method replace
+     * this object's <code>SSLSocketFactory</code>.
+     *
+     * @param sf the SSL socket factory
+     * @throws IllegalArgumentException if the <code>SSLSocketFactory</code>
+     *          parameter is null.
+     * @throws SecurityException if a security manager exists and its
+     *         <code>checkSetFactory</code> method does not allow
+     *         a socket factory to be specified.
+     * @see #getSSLSocketFactory()
+     */
+    public void setSSLSocketFactory(SSLSocketFactory sf) {
+        if (sf == null) {
+            throw new IllegalArgumentException(
+                "no SSLSocketFactory specified");
+        }
+
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkSetFactory();
+        }
+        sslSocketFactory = sf;
+    }
+
+    /**
+     * Gets the SSL socket factory to be used when creating sockets
+     * for secure https URL connections.
+     *
+     * @return the <code>SSLSocketFactory</code>
+     * @see #setSSLSocketFactory(SSLSocketFactory)
+     */
+    public SSLSocketFactory getSSLSocketFactory() {
+        return sslSocketFactory;
+    }
+}
diff --git a/javax/net/ssl/KeyManager.java b/javax/net/ssl/KeyManager.java
new file mode 100644
index 0000000..80aab39
--- /dev/null
+++ b/javax/net/ssl/KeyManager.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 1999, 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 javax.net.ssl;
+
+/**
+ * This is the base interface for JSSE key managers.
+ * <P>
+ * <code>KeyManager</code>s are responsible for managing the
+ * key material which is used to authenticate the local SSLSocket
+ * to its peer.  If no key material is available, the socket will
+ * be unable to present authentication credentials.
+ * <P>
+ * <code>KeyManager</code>s are created by either
+ * using a <code>KeyManagerFactory</code>,
+ * or by implementing one of the <code>KeyManager</code> subclasses.
+ *
+ * @since 1.4
+ * @see KeyManagerFactory
+ */
+public interface KeyManager {
+}
diff --git a/javax/net/ssl/KeyManagerFactory.java b/javax/net/ssl/KeyManagerFactory.java
new file mode 100644
index 0000000..7ae790c
--- /dev/null
+++ b/javax/net/ssl/KeyManagerFactory.java
@@ -0,0 +1,307 @@
+/*
+ * Copyright (c) 1999, 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 javax.net.ssl;
+
+import java.security.Security;
+import java.security.*;
+
+import sun.security.jca.GetInstance;
+
+/**
+ * This class acts as a factory for key managers based on a
+ * source of key material. Each key manager manages a specific
+ * type of key material for use by secure sockets. The key
+ * material is based on a KeyStore and/or provider specific sources.
+ *
+ * <p> Android provides the following <code>KeyManagerFactory</code> 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>
+ *
+ * @since 1.4
+ * @see KeyManager
+ */
+public class KeyManagerFactory {
+    // The provider
+    private Provider provider;
+
+    // The provider implementation (delegate)
+    private KeyManagerFactorySpi factorySpi;
+
+    // The name of the key management algorithm.
+    private String algorithm;
+
+    /**
+     * Obtains the default KeyManagerFactory algorithm name.
+     *
+     * <p>The default algorithm can be changed at runtime by setting
+     * the value of the {@code ssl.KeyManagerFactory.algorithm}
+     * security property to the desired algorithm name.
+     *
+     * @see java.security.Security security properties
+     * @return the default algorithm name as specified by the
+     *          {@code ssl.KeyManagerFactory.algorithm} security property, or an
+     *          implementation-specific default if no such property exists.
+     */
+    public final static String getDefaultAlgorithm() {
+        String type;
+        type = AccessController.doPrivileged(new PrivilegedAction<String>() {
+            @Override
+            public String run() {
+                return Security.getProperty(
+                    "ssl.KeyManagerFactory.algorithm");
+            }
+        });
+        if (type == null) {
+            type = "SunX509";
+        }
+        return type;
+    }
+
+    /**
+     * Creates a KeyManagerFactory object.
+     *
+     * @param factorySpi the delegate
+     * @param provider the provider
+     * @param algorithm the algorithm
+     */
+    protected KeyManagerFactory(KeyManagerFactorySpi factorySpi,
+                                Provider provider, String algorithm) {
+        this.factorySpi = factorySpi;
+        this.provider = provider;
+        this.algorithm = algorithm;
+    }
+
+    /**
+     * Returns the algorithm name of this <code>KeyManagerFactory</code> object.
+     *
+     * <p>This is the same name that was specified in one of the
+     * <code>getInstance</code> calls that created this
+     * <code>KeyManagerFactory</code> object.
+     *
+     * @return the algorithm name of this <code>KeyManagerFactory</code> object.
+     */
+    public final String getAlgorithm() {
+        return this.algorithm;
+    }
+
+    /**
+     * Returns a <code>KeyManagerFactory</code> object that acts as a
+     * factory for key managers.
+     *
+     * <p> This method traverses the list of registered security Providers,
+     * starting with the most preferred Provider.
+     * A new KeyManagerFactory object encapsulating the
+     * KeyManagerFactorySpi 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 requested algorithm.
+     *          See the <a href=
+     *  "{@docRoot}/../technotes/guides/security/jsse/JSSERefGuide.html">
+     *          Java Secure Socket Extension Reference Guide </a>
+     *          for information about standard algorithm names.
+     *
+     * @return the new <code>KeyManagerFactory</code> object.
+     *
+     * @exception NoSuchAlgorithmException if no Provider supports a
+     *          KeyManagerFactorySpi implementation for the
+     *          specified algorithm.
+     * @exception NullPointerException if <code>algorithm</code> is null.
+     *
+     * @see java.security.Provider
+     */
+    public static final KeyManagerFactory getInstance(String algorithm)
+            throws NoSuchAlgorithmException {
+        GetInstance.Instance instance = GetInstance.getInstance
+                ("KeyManagerFactory", KeyManagerFactorySpi.class,
+                algorithm);
+        return new KeyManagerFactory((KeyManagerFactorySpi)instance.impl,
+                instance.provider, algorithm);
+    }
+
+    /**
+     * Returns a <code>KeyManagerFactory</code> object that acts as a
+     * factory for key managers.
+     *
+     * <p> A new KeyManagerFactory object encapsulating the
+     * KeyManagerFactorySpi 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 name of the requested algorithm.
+     *          See the <a href=
+     *  "{@docRoot}/../technotes/guides/security/jsse/JSSERefGuide.html">
+     *          Java Secure Socket Extension Reference Guide </a>
+     *          for information about standard algorithm names.
+     *
+     * @param provider the name of the provider.
+     *
+     * @return the new <code>KeyManagerFactory</code> object.
+     *
+     * @throws NoSuchAlgorithmException if a KeyManagerFactorySpi
+     *          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.
+     *
+     * @throws IllegalArgumentException if the provider name is null or empty.
+     * @throws NullPointerException if <code>algorithm</code> is null.
+     *
+     * @see java.security.Provider
+     */
+    public static final KeyManagerFactory getInstance(String algorithm,
+            String provider) throws NoSuchAlgorithmException,
+            NoSuchProviderException {
+        GetInstance.Instance instance = GetInstance.getInstance
+                ("KeyManagerFactory", KeyManagerFactorySpi.class,
+                algorithm, provider);
+        return new KeyManagerFactory((KeyManagerFactorySpi)instance.impl,
+                instance.provider, algorithm);
+    }
+
+    /**
+     * Returns a <code>KeyManagerFactory</code> object that acts as a
+     * factory for key managers.
+     *
+     * <p> A new KeyManagerFactory object encapsulating the
+     * KeyManagerFactorySpi 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 name of the requested algorithm.
+     *          See the <a href=
+     *  "{@docRoot}/../technotes/guides/security/jsse/JSSERefGuide.html">
+     *          Java Secure Socket Extension Reference Guide </a>
+     *          for information about standard algorithm names.
+     *
+     * @param provider an instance of the provider.
+     *
+     * @return the new <code>KeyManagerFactory</code> object.
+     *
+     * @throws NoSuchAlgorithmException if a KeyManagerFactorySpi
+     *          implementation for the specified algorithm is not available
+     *          from the specified Provider object.
+     *
+     * @throws IllegalArgumentException if provider is null.
+     * @throws NullPointerException if <code>algorithm</code> is null.
+     *
+     * @see java.security.Provider
+     */
+    public static final KeyManagerFactory getInstance(String algorithm,
+            Provider provider) throws NoSuchAlgorithmException {
+        GetInstance.Instance instance = GetInstance.getInstance
+                ("KeyManagerFactory", KeyManagerFactorySpi.class,
+                algorithm, provider);
+        return new KeyManagerFactory((KeyManagerFactorySpi)instance.impl,
+                instance.provider, algorithm);
+    }
+
+    /**
+     * Returns the provider of this <code>KeyManagerFactory</code> object.
+     *
+     * @return the provider of this <code>KeyManagerFactory</code> object
+     */
+    public final Provider getProvider() {
+        return this.provider;
+    }
+
+
+    /**
+     * Initializes this factory with a source of key material.
+     * <P>
+     * The provider typically uses a KeyStore for obtaining
+     * key material for use during secure socket negotiations.
+     * The KeyStore is generally password-protected.
+     * <P>
+     * For more flexible initialization, please see
+     * {@link #init(ManagerFactoryParameters)}.
+     * <P>
+     *
+     * @param ks the key store or null
+     * @param password the password for recovering keys in the KeyStore
+     * @throws KeyStoreException if this operation fails
+     * @throws NoSuchAlgorithmException if the specified algorithm is not
+     *          available from the specified provider.
+     * @throws UnrecoverableKeyException if the key cannot be recovered
+     *          (e.g. the given password is wrong).
+     */
+    public final void init(KeyStore ks, char[] password) throws
+            KeyStoreException, NoSuchAlgorithmException,
+            UnrecoverableKeyException {
+        factorySpi.engineInit(ks, password);
+    }
+
+
+    /**
+     * Initializes this factory with a source of provider-specific
+     * key material.
+     * <P>
+     * In some cases, initialization parameters other than a keystore
+     * and password may be needed by a provider.  Users of that
+     * particular provider are expected to pass an implementation of
+     * the appropriate <CODE>ManagerFactoryParameters</CODE> as
+     * defined by the provider.  The provider can then call the
+     * specified methods in the <CODE>ManagerFactoryParameters</CODE>
+     * implementation to obtain the needed information.
+     *
+     * @param spec an implementation of a provider-specific parameter
+     *          specification
+     * @throws InvalidAlgorithmParameterException if an error is encountered
+     */
+    public final void init(ManagerFactoryParameters spec) throws
+            InvalidAlgorithmParameterException {
+        factorySpi.engineInit(spec);
+    }
+
+
+    /**
+     * Returns one key manager for each type of key material.
+     *
+     * @return the key managers
+     * @throws IllegalStateException if the KeyManagerFactory is not initialized
+     */
+    public final KeyManager[] getKeyManagers() {
+        return factorySpi.engineGetKeyManagers();
+    }
+}
diff --git a/javax/net/ssl/KeyManagerFactorySpi.java b/javax/net/ssl/KeyManagerFactorySpi.java
new file mode 100644
index 0000000..539309f
--- /dev/null
+++ b/javax/net/ssl/KeyManagerFactorySpi.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 1999, 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 javax.net.ssl;
+
+import java.security.*;
+
+/**
+ * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>)
+ * for the <code>KeyManagerFactory</code> class.
+ *
+ * <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 key manager factory.
+ *
+ * @since 1.4
+ * @see KeyManagerFactory
+ * @see KeyManager
+ */
+public abstract class KeyManagerFactorySpi {
+    /**
+     * Initializes this factory with a source of key material.
+     *
+     * @param ks the key store or null
+     * @param password the password for recovering keys
+     * @throws KeyStoreException if this operation fails
+     * @throws NoSuchAlgorithmException if the specified algorithm is not
+     *          available from the specified provider.
+     * @throws UnrecoverableKeyException if the key cannot be recovered
+     * @see KeyManagerFactory#init(KeyStore, char[])
+     */
+    protected abstract void engineInit(KeyStore ks, char[] password) throws
+        KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException;
+
+    /**
+     * Initializes this factory with a source of key material.
+     * <P>
+     * In some cases, initialization parameters other than a keystore
+     * and password may be needed by a provider.  Users of that
+     * particular provider are expected to pass an implementation of
+     * the appropriate <CODE>ManagerFactoryParameters</CODE> as
+     * defined by the provider.  The provider can then call the
+     * specified methods in the ManagerFactoryParameters
+     * implementation to obtain the needed information.
+     *
+     * @param spec an implementation of a provider-specific parameter
+     *          specification
+     * @throws InvalidAlgorithmParameterException if there is problem
+     *          with the parameters
+     * @see KeyManagerFactory#init(ManagerFactoryParameters spec)
+     */
+    protected abstract void engineInit(ManagerFactoryParameters spec)
+        throws InvalidAlgorithmParameterException;
+
+    /**
+     * Returns one key manager for each type of key material.
+     *
+     * @return the key managers
+     * @throws IllegalStateException
+     *         if the KeyManagerFactorySpi is not initialized
+     */
+    protected abstract KeyManager[] engineGetKeyManagers();
+}
diff --git a/javax/net/ssl/KeyStoreBuilderParameters.java b/javax/net/ssl/KeyStoreBuilderParameters.java
new file mode 100644
index 0000000..678b0a2
--- /dev/null
+++ b/javax/net/ssl/KeyStoreBuilderParameters.java
@@ -0,0 +1,88 @@
+/*
+ * 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 javax.net.ssl;
+
+import java.util.*;
+
+import java.security.KeyStore.*;
+
+/**
+ * A parameters object for X509KeyManagers that encapsulates a List
+ * of KeyStore.Builders.
+ *
+ * @see java.security.KeyStore.Builder
+ * @see X509KeyManager
+ *
+ * @author  Andreas Sterbenz
+ * @since   1.5
+ */
+public class KeyStoreBuilderParameters implements ManagerFactoryParameters {
+
+    private final List<Builder> parameters;
+
+    /**
+     * Construct new KeyStoreBuilderParameters from the specified
+     * {@linkplain java.security.KeyStore.Builder}.
+     *
+     * @param builder the Builder object
+     * @exception NullPointerException if builder is null
+     */
+    public KeyStoreBuilderParameters(Builder builder) {
+        parameters = Collections.singletonList(Objects.requireNonNull(builder));
+    }
+
+    /**
+     * Construct new KeyStoreBuilderParameters from a List
+     * of {@linkplain java.security.KeyStore.Builder}s. Note that the list
+     * is cloned to protect against subsequent modification.
+     *
+     * @param parameters the List of Builder objects
+     * @exception NullPointerException if parameters is null
+     * @exception IllegalArgumentException if parameters is an empty list
+     */
+    public KeyStoreBuilderParameters(List<Builder> parameters) {
+        if (parameters.isEmpty()) {
+            throw new IllegalArgumentException();
+        }
+
+        this.parameters = Collections.unmodifiableList(
+            new ArrayList<Builder>(parameters));
+    }
+
+    /**
+     * Return the unmodifiable List of the
+     * {@linkplain java.security.KeyStore.Builder}s
+     * encapsulated by this object.
+     *
+     * @return the unmodifiable List of the
+     * {@linkplain java.security.KeyStore.Builder}s
+     * encapsulated by this object.
+     */
+    public List<Builder> getParameters() {
+        return parameters;
+    }
+
+}
diff --git a/javax/net/ssl/ManagerFactoryParameters.java b/javax/net/ssl/ManagerFactoryParameters.java
new file mode 100644
index 0000000..81bdf71
--- /dev/null
+++ b/javax/net/ssl/ManagerFactoryParameters.java
@@ -0,0 +1,46 @@
+/*
+ * 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 javax.net.ssl;
+
+/**
+ * This class is the base interface for providing
+ * algorithm-specific information to a KeyManagerFactory or
+ * TrustManagerFactory.
+ * <P>
+ * In some cases, initialization parameters other than keystores
+ * may be needed by a provider.  Users of that particular provider
+ * are expected to pass an implementation of the appropriate
+ * sub-interface of this class as defined by the
+ * provider.  The provider can then call the specified methods in
+ * the <CODE>ManagerFactoryParameters</CODE> implementation to obtain the
+ * needed information.
+ *
+ * @author Brad R. Wetmore
+ * @since 1.4
+ */
+
+public interface ManagerFactoryParameters {
+}
diff --git a/javax/net/ssl/SNIHostName.java b/javax/net/ssl/SNIHostName.java
new file mode 100644
index 0000000..d5e7141
--- /dev/null
+++ b/javax/net/ssl/SNIHostName.java
@@ -0,0 +1,396 @@
+/*
+ * 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 javax.net.ssl;
+
+import java.net.IDN;
+import java.nio.ByteBuffer;
+import java.nio.charset.CodingErrorAction;
+import java.nio.charset.StandardCharsets;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CharacterCodingException;
+import java.util.Locale;
+import java.util.Objects;
+import java.util.regex.Pattern;
+
+/**
+ * Instances of this class represent a server name of type
+ * {@link StandardConstants#SNI_HOST_NAME host_name} in a Server Name
+ * Indication (SNI) extension.
+ * <P>
+ * As described in section 3, "Server Name Indication", of
+ * <A HREF="http://www.ietf.org/rfc/rfc6066.txt">TLS Extensions (RFC 6066)</A>,
+ * "HostName" contains the fully qualified DNS hostname of the server, as
+ * understood by the client.  The encoded server name value of a hostname is
+ * represented as a byte string using ASCII encoding without a trailing dot.
+ * This allows the support of Internationalized Domain Names (IDN) through
+ * the use of A-labels (the ASCII-Compatible Encoding (ACE) form of a valid
+ * string of Internationalized Domain Names for Applications (IDNA)) defined
+ * in <A HREF="http://www.ietf.org/rfc/rfc5890.txt">RFC 5890</A>.
+ * <P>
+ * Note that {@code SNIHostName} objects are immutable.
+ *
+ * @see SNIServerName
+ * @see StandardConstants#SNI_HOST_NAME
+ *
+ * @since 1.8
+ */
+public final class SNIHostName extends SNIServerName {
+
+    // the decoded string value of the server name
+    private final String hostname;
+
+    /**
+     * Creates an {@code SNIHostName} using the specified hostname.
+     * <P>
+     * Note that per <A HREF="http://www.ietf.org/rfc/rfc6066.txt">RFC 6066</A>,
+     * the encoded server name value of a hostname is
+     * {@link StandardCharsets#US_ASCII}-compliant.  In this method,
+     * {@code hostname} can be a user-friendly Internationalized Domain Name
+     * (IDN).  {@link IDN#toASCII(String, int)} is used to enforce the
+     * restrictions on ASCII characters in hostnames (see
+     * <A HREF="http://www.ietf.org/rfc/rfc3490.txt">RFC 3490</A>,
+     * <A HREF="http://www.ietf.org/rfc/rfc1122.txt">RFC 1122</A>,
+     * <A HREF="http://www.ietf.org/rfc/rfc1123.txt">RFC 1123</A>) and
+     * translate the {@code hostname} into ASCII Compatible Encoding (ACE), as:
+     * <pre>
+     *     IDN.toASCII(hostname, IDN.USE_STD3_ASCII_RULES);
+     * </pre>
+     * <P>
+     * The {@code hostname} argument is illegal if it:
+     * <ul>
+     * <li> {@code hostname} is empty,</li>
+     * <li> {@code hostname} ends with a trailing dot,</li>
+     * <li> {@code hostname} is not a valid Internationalized
+     *      Domain Name (IDN) compliant with the RFC 3490 specification.</li>
+     * </ul>
+     * @param  hostname
+     *         the hostname of this server name
+     *
+     * @throws NullPointerException if {@code hostname} is {@code null}
+     * @throws IllegalArgumentException if {@code hostname} is illegal
+     */
+    public SNIHostName(String hostname) {
+        // IllegalArgumentException will be thrown if {@code hostname} is
+        // not a valid IDN.
+        super(StandardConstants.SNI_HOST_NAME,
+                (hostname = IDN.toASCII(
+                    Objects.requireNonNull(hostname,
+                        "Server name value of host_name cannot be null"),
+                    IDN.USE_STD3_ASCII_RULES))
+                .getBytes(StandardCharsets.US_ASCII));
+
+        this.hostname = hostname;
+
+        // check the validity of the string hostname
+        checkHostName();
+    }
+
+    /**
+     * Creates an {@code SNIHostName} using the specified encoded value.
+     * <P>
+     * This method is normally used to parse the encoded name value in a
+     * requested SNI extension.
+     * <P>
+     * Per <A HREF="http://www.ietf.org/rfc/rfc6066.txt">RFC 6066</A>,
+     * the encoded name value of a hostname is
+     * {@link StandardCharsets#US_ASCII}-compliant.  However, in the previous
+     * version of the SNI extension (
+     * <A HREF="http://www.ietf.org/rfc/rfc4366.txt">RFC 4366</A>),
+     * the encoded hostname is represented as a byte string using UTF-8
+     * encoding.  For the purpose of version tolerance, this method allows
+     * that the charset of {@code encoded} argument can be
+     * {@link StandardCharsets#UTF_8}, as well as
+     * {@link StandardCharsets#US_ASCII}.  {@link IDN#toASCII(String)} is used
+     * to translate the {@code encoded} argument into ASCII Compatible
+     * Encoding (ACE) hostname.
+     * <P>
+     * It is strongly recommended that this constructor is only used to parse
+     * the encoded name value in a requested SNI extension.  Otherwise, to
+     * comply with <A HREF="http://www.ietf.org/rfc/rfc6066.txt">RFC 6066</A>,
+     * please always use {@link StandardCharsets#US_ASCII}-compliant charset
+     * and enforce the restrictions on ASCII characters in hostnames (see
+     * <A HREF="http://www.ietf.org/rfc/rfc3490.txt">RFC 3490</A>,
+     * <A HREF="http://www.ietf.org/rfc/rfc1122.txt">RFC 1122</A>,
+     * <A HREF="http://www.ietf.org/rfc/rfc1123.txt">RFC 1123</A>)
+     * for {@code encoded} argument, or use
+     * {@link SNIHostName#SNIHostName(String)} instead.
+     * <P>
+     * The {@code encoded} argument is illegal if it:
+     * <ul>
+     * <li> {@code encoded} is empty,</li>
+     * <li> {@code encoded} ends with a trailing dot,</li>
+     * <li> {@code encoded} is not encoded in
+     *      {@link StandardCharsets#US_ASCII} or
+     *      {@link StandardCharsets#UTF_8}-compliant charset,</li>
+     * <li> {@code encoded} is not a valid Internationalized
+     *      Domain Name (IDN) compliant with the RFC 3490 specification.</li>
+     * </ul>
+     *
+     * <P>
+     * Note that the {@code encoded} byte array is cloned
+     * to protect against subsequent modification.
+     *
+     * @param  encoded
+     *         the encoded hostname of this server name
+     *
+     * @throws NullPointerException if {@code encoded} is {@code null}
+     * @throws IllegalArgumentException if {@code encoded} is illegal
+     */
+    public SNIHostName(byte[] encoded) {
+        // NullPointerException will be thrown if {@code encoded} is null
+        super(StandardConstants.SNI_HOST_NAME, encoded);
+
+        // Compliance: RFC 4366 requires that the hostname is represented
+        // as a byte string using UTF_8 encoding [UTF8]
+        try {
+            // Please don't use {@link String} constructors because they
+            // do not report coding errors.
+            CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder()
+                    .onMalformedInput(CodingErrorAction.REPORT)
+                    .onUnmappableCharacter(CodingErrorAction.REPORT);
+
+            this.hostname = IDN.toASCII(
+                    decoder.decode(ByteBuffer.wrap(encoded)).toString());
+        } catch (RuntimeException | CharacterCodingException e) {
+            throw new IllegalArgumentException(
+                        "The encoded server name value is invalid", e);
+        }
+
+        // check the validity of the string hostname
+        checkHostName();
+    }
+
+    /**
+     * Returns the {@link StandardCharsets#US_ASCII}-compliant hostname of
+     * this {@code SNIHostName} object.
+     * <P>
+     * Note that, per
+     * <A HREF="http://www.ietf.org/rfc/rfc6066.txt">RFC 6066</A>, the
+     * returned hostname may be an internationalized domain name that
+     * contains A-labels. See
+     * <A HREF="http://www.ietf.org/rfc/rfc5890.txt">RFC 5890</A>
+     * for more information about the detailed A-label specification.
+     *
+     * @return the {@link StandardCharsets#US_ASCII}-compliant hostname
+     *         of this {@code SNIHostName} object
+     */
+    public String getAsciiName() {
+        return hostname;
+    }
+
+    /**
+     * Compares this server name to the specified object.
+     * <P>
+     * Per <A HREF="http://www.ietf.org/rfc/rfc6066.txt">RFC 6066</A>, DNS
+     * hostnames are case-insensitive.  Two server hostnames are equal if,
+     * and only if, they have the same name type, and the hostnames are
+     * equal in a case-independent comparison.
+     *
+     * @param  other
+     *         the other server name object to compare with.
+     * @return true if, and only if, the {@code other} is considered
+     *         equal to this instance
+     */
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        }
+
+        if (other instanceof SNIHostName) {
+            return hostname.equalsIgnoreCase(((SNIHostName)other).hostname);
+        }
+
+        return false;
+    }
+
+    /**
+     * Returns a hash code value for this {@code SNIHostName}.
+     * <P>
+     * The hash code value is generated using the case-insensitive hostname
+     * of this {@code SNIHostName}.
+     *
+     * @return a hash code value for this {@code SNIHostName}.
+     */
+    @Override
+    public int hashCode() {
+        int result = 17;        // 17/31: prime number to decrease collisions
+        result = 31 * result + hostname.toUpperCase(Locale.ENGLISH).hashCode();
+
+        return result;
+    }
+
+    /**
+     * Returns a string representation of the object, including the DNS
+     * hostname in this {@code SNIHostName} object.
+     * <P>
+     * The exact details of the representation are unspecified and subject
+     * to change, but the following may be regarded as typical:
+     * <pre>
+     *     "type=host_name (0), value={@literal <hostname>}"
+     * </pre>
+     * The "{@literal <hostname>}" is an ASCII representation of the hostname,
+     * which may contains A-labels.  For example, a returned value of an pseudo
+     * hostname may look like:
+     * <pre>
+     *     "type=host_name (0), value=www.example.com"
+     * </pre>
+     * or
+     * <pre>
+     *     "type=host_name (0), value=xn--fsqu00a.xn--0zwm56d"
+     * </pre>
+     * <P>
+     * Please NOTE that the exact details of the representation are unspecified
+     * and subject to change.
+     *
+     * @return a string representation of the object.
+     */
+    @Override
+    public String toString() {
+        return "type=host_name (0), value=" + hostname;
+    }
+
+    /**
+     * Creates an {@link SNIMatcher} object for {@code SNIHostName}s.
+     * <P>
+     * This method can be used by a server to verify the acceptable
+     * {@code SNIHostName}s.  For example,
+     * <pre>
+     *     SNIMatcher matcher =
+     *         SNIHostName.createSNIMatcher("www\\.example\\.com");
+     * </pre>
+     * will accept the hostname "www.example.com".
+     * <pre>
+     *     SNIMatcher matcher =
+     *         SNIHostName.createSNIMatcher("www\\.example\\.(com|org)");
+     * </pre>
+     * will accept hostnames "www.example.com" and "www.example.org".
+     *
+     * @param  regex
+     *         the <a href="{@docRoot}/java/util/regex/Pattern.html#sum">
+     *         regular expression pattern</a>
+     *         representing the hostname(s) to match
+     * @return a {@code SNIMatcher} object for {@code SNIHostName}s
+     * @throws NullPointerException if {@code regex} is
+     *         {@code null}
+     * @throws java.util.regex.PatternSyntaxException if the regular expression's
+     *         syntax is invalid
+     */
+    public static SNIMatcher createSNIMatcher(String regex) {
+        if (regex == null) {
+            throw new NullPointerException(
+                "The regular expression cannot be null");
+        }
+
+        return new SNIHostNameMatcher(regex);
+    }
+
+    // check the validity of the string hostname
+    private void checkHostName() {
+        if (hostname.isEmpty()) {
+            throw new IllegalArgumentException(
+                "Server name value of host_name cannot be empty");
+        }
+
+        if (hostname.endsWith(".")) {
+            throw new IllegalArgumentException(
+                "Server name value of host_name cannot have the trailing dot");
+        }
+    }
+
+    private final static class SNIHostNameMatcher extends SNIMatcher {
+
+        // the compiled representation of a regular expression.
+        private final Pattern pattern;
+
+        /**
+         * Creates an SNIHostNameMatcher object.
+         *
+         * @param  regex
+         *         the <a href="{@docRoot}/java/util/regex/Pattern.html#sum">
+         *         regular expression pattern</a>
+         *         representing the hostname(s) to match
+         * @throws NullPointerException if {@code regex} is
+         *         {@code null}
+         * @throws PatternSyntaxException if the regular expression's syntax
+         *         is invalid
+         */
+        SNIHostNameMatcher(String regex) {
+            super(StandardConstants.SNI_HOST_NAME);
+            pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
+        }
+
+        /**
+         * Attempts to match the given {@link SNIServerName}.
+         *
+         * @param  serverName
+         *         the {@link SNIServerName} instance on which this matcher
+         *         performs match operations
+         *
+         * @return {@code true} if, and only if, the matcher matches the
+         *         given {@code serverName}
+         *
+         * @throws NullPointerException if {@code serverName} is {@code null}
+         * @throws IllegalArgumentException if {@code serverName} is
+         *         not of {@code StandardConstants#SNI_HOST_NAME} type
+         *
+         * @see SNIServerName
+         */
+        @Override
+        public boolean matches(SNIServerName serverName) {
+            if (serverName == null) {
+                throw new NullPointerException(
+                    "The SNIServerName argument cannot be null");
+            }
+
+            SNIHostName hostname;
+            if (!(serverName instanceof SNIHostName)) {
+                if (serverName.getType() != StandardConstants.SNI_HOST_NAME) {
+                    throw new IllegalArgumentException(
+                        "The server name type is not host_name");
+                }
+
+                try {
+                    hostname = new SNIHostName(serverName.getEncoded());
+                } catch (NullPointerException | IllegalArgumentException e) {
+                    return false;
+                }
+            } else {
+                hostname = (SNIHostName)serverName;
+            }
+
+            // Let's first try the ascii name matching
+            String asciiName = hostname.getAsciiName();
+            if (pattern.matcher(asciiName).matches()) {
+                return true;
+            }
+
+            // May be an internationalized domain name, check the Unicode
+            // representations.
+            return pattern.matcher(IDN.toUnicode(asciiName)).matches();
+        }
+    }
+}
diff --git a/javax/net/ssl/SNIMatcher.java b/javax/net/ssl/SNIMatcher.java
new file mode 100644
index 0000000..a6c9ab9
--- /dev/null
+++ b/javax/net/ssl/SNIMatcher.java
@@ -0,0 +1,105 @@
+/*
+ * 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 javax.net.ssl;
+
+/**
+ * Instances of this class represent a matcher that performs match
+ * operations on an {@link SNIServerName} instance.
+ * <P>
+ * Servers can use Server Name Indication (SNI) information to decide if
+ * specific {@link SSLSocket} or {@link SSLEngine} instances should accept
+ * a connection.  For example, when multiple "virtual" or "name-based"
+ * servers are hosted on a single underlying network address, the server
+ * application can use SNI information to determine whether this server is
+ * the exact server that the client wants to access.  Instances of this
+ * class can be used by a server to verify the acceptable server names of
+ * a particular type, such as host names.
+ * <P>
+ * {@code SNIMatcher} objects are immutable.  Subclasses should not provide
+ * methods that can change the state of an instance once it has been created.
+ *
+ * @see SNIServerName
+ * @see SNIHostName
+ * @see SSLParameters#getSNIMatchers()
+ * @see SSLParameters#setSNIMatchers(Collection)
+ *
+ * @since 1.8
+ */
+public abstract class SNIMatcher {
+
+    // the type of the server name that this matcher performs on
+    private final int type;
+
+    /**
+     * Creates an {@code SNIMatcher} using the specified server name type.
+     *
+     * @param  type
+     *         the type of the server name that this matcher performs on
+     *
+     * @throws IllegalArgumentException if {@code type} is not in the range
+     *         of 0 to 255, inclusive.
+     */
+    protected SNIMatcher(int type) {
+        if (type < 0) {
+            throw new IllegalArgumentException(
+                "Server name type cannot be less than zero");
+        } else if (type > 255) {
+            throw new IllegalArgumentException(
+                "Server name type cannot be greater than 255");
+        }
+
+        this.type = type;
+    }
+
+    /**
+     * Returns the server name type of this {@code SNIMatcher} object.
+     *
+     * @return the server name type of this {@code SNIMatcher} object.
+     *
+     * @see SNIServerName
+     */
+    public final int getType() {
+        return type;
+    }
+
+    /**
+     * Attempts to match the given {@link SNIServerName}.
+     *
+     * @param  serverName
+     *         the {@link SNIServerName} instance on which this matcher
+     *         performs match operations
+     *
+     * @return {@code true} if, and only if, the matcher matches the
+     *         given {@code serverName}
+     *
+     * @throws NullPointerException if {@code serverName} is {@code null}
+     * @throws IllegalArgumentException if {@code serverName} is
+     *         not of the given server name type of this matcher
+     *
+     * @see SNIServerName
+     */
+    public abstract boolean matches(SNIServerName serverName);
+}
diff --git a/javax/net/ssl/SNIServerName.java b/javax/net/ssl/SNIServerName.java
new file mode 100644
index 0000000..1ef9d05
--- /dev/null
+++ b/javax/net/ssl/SNIServerName.java
@@ -0,0 +1,213 @@
+/*
+ * 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 javax.net.ssl;
+
+import java.util.Arrays;
+
+/**
+ * Instances of this class represent a server name in a Server Name
+ * Indication (SNI) extension.
+ * <P>
+ * The SNI extension is a feature that extends the SSL/TLS protocols to
+ * indicate what server name the client is attempting to connect to during
+ * handshaking.  See section 3, "Server Name Indication", of <A
+ * HREF="http://www.ietf.org/rfc/rfc6066.txt">TLS Extensions (RFC 6066)</A>.
+ * <P>
+ * {@code SNIServerName} objects are immutable.  Subclasses should not provide
+ * methods that can change the state of an instance once it has been created.
+ *
+ * @see SSLParameters#getServerNames()
+ * @see SSLParameters#setServerNames(List)
+ *
+ * @since 1.8
+ */
+public abstract class SNIServerName {
+
+    // the type of the server name
+    private final int type;
+
+    // the encoded value of the server name
+    private final byte[] encoded;
+
+    // the hex digitals
+    private static final char[] HEXES = "0123456789ABCDEF".toCharArray();
+
+    /**
+     * Creates an {@code SNIServerName} using the specified name type and
+     * encoded value.
+     * <P>
+     * Note that the {@code encoded} byte array is cloned to protect against
+     * subsequent modification.
+     *
+     * @param  type
+     *         the type of the server name
+     * @param  encoded
+     *         the encoded value of the server name
+     *
+     * @throws IllegalArgumentException if {@code type} is not in the range
+     *         of 0 to 255, inclusive.
+     * @throws NullPointerException if {@code encoded} is null
+     */
+    protected SNIServerName(int type, byte[] encoded) {
+        if (type < 0) {
+            throw new IllegalArgumentException(
+                "Server name type cannot be less than zero");
+        } else if (type > 255) {
+            throw new IllegalArgumentException(
+                "Server name type cannot be greater than 255");
+        }
+        this.type = type;
+
+        if (encoded == null) {
+            throw new NullPointerException(
+                "Server name encoded value cannot be null");
+        }
+        this.encoded = encoded.clone();
+    }
+
+
+    /**
+     * Returns the name type of this server name.
+     *
+     * @return the name type of this server name
+     */
+    public final int getType() {
+        return type;
+    }
+
+    /**
+     * Returns a copy of the encoded server name value of this server name.
+     *
+     * @return a copy of the encoded server name value of this server name
+     */
+    public final byte[] getEncoded() {
+        return encoded.clone();
+    }
+
+    /**
+     * Indicates whether some other object is "equal to" this server name.
+     *
+     * @return true if, and only if, {@code other} is of the same class
+     *         of this object, and has the same name type and
+     *         encoded value as this server name.
+     */
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        }
+
+        if (this.getClass() != other.getClass()) {
+            return false;
+        }
+
+        SNIServerName that = (SNIServerName)other;
+        return (this.type == that.type) &&
+                    Arrays.equals(this.encoded, that.encoded);
+    }
+
+    /**
+     * Returns a hash code value for this server name.
+     * <P>
+     * The hash code value is generated using the name type and encoded
+     * value of this server name.
+     *
+     * @return a hash code value for this server name.
+     */
+    @Override
+    public int hashCode() {
+        int result = 17;    // 17/31: prime number to decrease collisions
+        result = 31 * result + type;
+        result = 31 * result + Arrays.hashCode(encoded);
+
+        return result;
+    }
+
+    /**
+     * Returns a string representation of this server name, including the server
+     * name type and the encoded server name value in this
+     * {@code SNIServerName} object.
+     * <P>
+     * The exact details of the representation are unspecified and subject
+     * to change, but the following may be regarded as typical:
+     * <pre>
+     *     "type={@literal <name type>}, value={@literal <name value>}"
+     * </pre>
+     * <P>
+     * In this class, the format of "{@literal <name type>}" is
+     * "[LITERAL] (INTEGER)", where the optional "LITERAL" is the literal
+     * name, and INTEGER is the integer value of the name type.  The format
+     * of "{@literal <name value>}" is "XX:...:XX", where "XX" is the
+     * hexadecimal digit representation of a byte value. For example, a
+     * returned value of an pseudo server name may look like:
+     * <pre>
+     *     "type=(31), value=77:77:77:2E:65:78:61:6D:70:6C:65:2E:63:6E"
+     * </pre>
+     * or
+     * <pre>
+     *     "type=host_name (0), value=77:77:77:2E:65:78:61:6D:70:6C:65:2E:63:6E"
+     * </pre>
+     *
+     * <P>
+     * Please NOTE that the exact details of the representation are unspecified
+     * and subject to change, and subclasses may override the method with
+     * their own formats.
+     *
+     * @return a string representation of this server name
+     */
+    @Override
+    public String toString() {
+        if (type == StandardConstants.SNI_HOST_NAME) {
+            return "type=host_name (0), value=" + toHexString(encoded);
+        } else {
+            return "type=(" + type + "), value=" + toHexString(encoded);
+        }
+    }
+
+    // convert byte array to hex string
+    private static String toHexString(byte[] bytes) {
+        if (bytes.length == 0) {
+            return "(empty)";
+        }
+
+        StringBuilder sb = new StringBuilder(bytes.length * 3 - 1);
+        boolean isInitial = true;
+        for (byte b : bytes) {
+            if (isInitial) {
+                isInitial = false;
+            } else {
+                sb.append(':');
+            }
+
+            int k = b & 0xFF;
+            sb.append(HEXES[k >>> 4]);
+            sb.append(HEXES[k & 0xF]);
+        }
+
+        return sb.toString();
+    }
+}
+
diff --git a/javax/net/ssl/SSLContext.java b/javax/net/ssl/SSLContext.java
new file mode 100644
index 0000000..eb7322c
--- /dev/null
+++ b/javax/net/ssl/SSLContext.java
@@ -0,0 +1,483 @@
+/*
+ * Copyright (c) 1999, 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 javax.net.ssl;
+
+import java.security.*;
+import java.util.*;
+
+import sun.security.jca.GetInstance;
+
+/**
+ * Instances of this class represent a secure socket protocol
+ * implementation which acts as a factory for secure socket
+ * factories or <code>SSLEngine</code>s. This class is initialized
+ * with an optional set of key and trust managers and source of
+ * secure random bytes.
+ *
+ * <p> Android provides the following <code>SSLContext</code> protocols:
+ * <table>
+ *   <thead>
+ *     <tr>
+ *       <th>Algorithm</th>
+ *       <th>Supported API Levels</th>
+ *     </tr>
+ *   </thead>
+ *   <tbody>
+ *     <tr>
+ *       <td>Default</td>
+ *       <td>10+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>SSL</td>
+ *       <td>10+</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>SSLv3</td>
+ *       <td>10-25</td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLSv1</td>
+ *       <td>10+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLSv1.1</td>
+ *       <td>16+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLSv1.2</td>
+ *       <td>16+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLSv1.3</td>
+ *       <td>29+</td>
+ *     </tr>
+ *   </tbody>
+ * </table>
+ *
+ * This protocol is described in the <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#SSLContext">
+ * SSLContext section</a> of the
+ * Java Cryptography Architecture Standard Algorithm Name Documentation.
+ *
+ * @since 1.4
+ */
+public class SSLContext {
+    private final Provider provider;
+
+    private final SSLContextSpi contextSpi;
+
+    private final String protocol;
+
+    /**
+     * Creates an SSLContext object.
+     *
+     * @param contextSpi the delegate
+     * @param provider the provider
+     * @param protocol the protocol
+     */
+    protected SSLContext(SSLContextSpi contextSpi, Provider provider,
+            String protocol) {
+        this.contextSpi = contextSpi;
+        this.provider = provider;
+        this.protocol = protocol;
+    }
+
+    private static SSLContext defaultContext;
+
+    /**
+     * Returns the default SSL context.
+     *
+     * <p>If a default context was set using the {@link #setDefault
+     * SSLContext.setDefault()} method, it is returned. Otherwise, the first
+     * call of this method triggers the call
+     * <code>SSLContext.getInstance("Default")</code>.
+     * If successful, that object is made the default SSL context and returned.
+     *
+     * <p>The default context is immediately
+     * usable and does not require {@linkplain #init initialization}.
+     *
+     * @return the default SSL context
+     * @throws NoSuchAlgorithmException if the
+     *   {@link SSLContext#getInstance SSLContext.getInstance()} call fails
+     * @since 1.6
+     */
+    public static synchronized SSLContext getDefault()
+            throws NoSuchAlgorithmException {
+        if (defaultContext == null) {
+            defaultContext = SSLContext.getInstance("Default");
+        }
+        return defaultContext;
+    }
+
+    // Android-changed: Additional text to strongly discouraged changing the default.
+    /**
+     * Sets the default SSL context. It will be returned by subsequent calls
+     * to {@link #getDefault}. The default context must be immediately usable
+     * and not require {@linkplain #init initialization}.
+     * <p>
+     * Developers are <em>strongly</em> discouraged from changing the default {@code SSLContext} as
+     * it is used as the Android default for secure communication by APIs like
+     * {@link SSLSocketFactory#getDefault()}, {@link SSLServerSocketFactory#getDefault()} and
+     * {@link HttpsURLConnection}.
+     *
+     * @param context the SSLContext
+     * @throws  NullPointerException if context is null
+     * @throws  SecurityException if a security manager exists and its
+     *          <code>checkPermission</code> method does not allow
+     *          <code>SSLPermission("setDefaultSSLContext")</code>
+     * @since 1.6
+     */
+    public static synchronized void setDefault(SSLContext context) {
+        if (context == null) {
+            throw new NullPointerException();
+        }
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(new SSLPermission("setDefaultSSLContext"));
+        }
+        defaultContext = context;
+    }
+
+    /**
+     * Returns a <code>SSLContext</code> object that implements the
+     * specified secure socket protocol.
+     *
+     * <p> This method traverses the list of registered security Providers,
+     * starting with the most preferred Provider.
+     * A new SSLContext object encapsulating the
+     * SSLContextSpi implementation from the first
+     * Provider that supports the specified protocol is returned.
+     *
+     * <p> Note that the list of registered providers may be retrieved via
+     * the {@link Security#getProviders() Security.getProviders()} method.
+     *
+     * @param protocol the standard name of the requested protocol.
+     *          See the SSLContext section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#SSLContext">
+     *          Java Cryptography Architecture Standard Algorithm Name
+     *          Documentation</a>
+     *          for information about standard protocol names.
+     *
+     * @return the new <code>SSLContext</code> object.
+     *
+     * @exception NoSuchAlgorithmException if no Provider supports a
+     *          SSLContextSpi implementation for the
+     *          specified protocol.
+     * @exception NullPointerException if protocol is null.
+     *
+     * @see java.security.Provider
+     */
+    public static SSLContext getInstance(String protocol)
+            throws NoSuchAlgorithmException {
+        GetInstance.Instance instance = GetInstance.getInstance
+                ("SSLContext", SSLContextSpi.class, protocol);
+        return new SSLContext((SSLContextSpi)instance.impl, instance.provider,
+                protocol);
+    }
+
+    /**
+     * Returns a <code>SSLContext</code> object that implements the
+     * specified secure socket protocol.
+     *
+     * <p> A new SSLContext object encapsulating the
+     * SSLContextSpi 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 protocol the standard name of the requested protocol.
+     *          See the SSLContext section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#SSLContext">
+     *          Java Cryptography Architecture Standard Algorithm Name
+     *          Documentation</a>
+     *          for information about standard protocol names.
+     *
+     * @param provider the name of the provider.
+     *
+     * @return the new <code>SSLContext</code> object.
+     *
+     * @throws NoSuchAlgorithmException if a SSLContextSpi
+     *          implementation for the specified protocol is not
+     *          available from the specified provider.
+     *
+     * @throws NoSuchProviderException if the specified provider is not
+     *          registered in the security provider list.
+     *
+     * @throws IllegalArgumentException if the provider name is null or empty.
+     * @throws NullPointerException if protocol is null.
+     *
+     * @see java.security.Provider
+     */
+    public static SSLContext getInstance(String protocol, String provider)
+            throws NoSuchAlgorithmException, NoSuchProviderException {
+        GetInstance.Instance instance = GetInstance.getInstance
+                ("SSLContext", SSLContextSpi.class, protocol, provider);
+        return new SSLContext((SSLContextSpi)instance.impl, instance.provider,
+                protocol);
+    }
+
+    /**
+     * Returns a <code>SSLContext</code> object that implements the
+     * specified secure socket protocol.
+     *
+     * <p> A new SSLContext object encapsulating the
+     * SSLContextSpi 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 protocol the standard name of the requested protocol.
+     *          See the SSLContext section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#SSLContext">
+     *          Java Cryptography Architecture Standard Algorithm Name
+     *          Documentation</a>
+     *          for information about standard protocol names.
+     *
+     * @param provider an instance of the provider.
+     *
+     * @return the new <code>SSLContext</code> object.
+     *
+     * @throws NoSuchAlgorithmException if a SSLContextSpi
+     *          implementation for the specified protocol is not available
+     *          from the specified Provider object.
+     *
+     * @throws IllegalArgumentException if the provider is null.
+     * @throws NullPointerException if protocol is null.
+     *
+     * @see java.security.Provider
+     */
+    public static SSLContext getInstance(String protocol, Provider provider)
+            throws NoSuchAlgorithmException {
+        GetInstance.Instance instance = GetInstance.getInstance
+                ("SSLContext", SSLContextSpi.class, protocol, provider);
+        return new SSLContext((SSLContextSpi)instance.impl, instance.provider,
+                protocol);
+    }
+
+    /**
+     * Returns the protocol name of this <code>SSLContext</code> object.
+     *
+     * <p>This is the same name that was specified in one of the
+     * <code>getInstance</code> calls that created this
+     * <code>SSLContext</code> object.
+     *
+     * @return the protocol name of this <code>SSLContext</code> object.
+     */
+    public final String getProtocol() {
+        return this.protocol;
+    }
+
+    /**
+     * Returns the provider of this <code>SSLContext</code> object.
+     *
+     * @return the provider of this <code>SSLContext</code> object
+     */
+    public final Provider getProvider() {
+        return this.provider;
+    }
+
+    /**
+     * Initializes this context. Either of the first two parameters
+     * may be null in which case the installed security providers will
+     * be searched for the highest priority implementation of the
+     * appropriate factory. Likewise, the secure random parameter may
+     * be null in which case the default implementation will be used.
+     * <P>
+     * Only the first instance of a particular key and/or trust manager
+     * implementation type in the array is used.  (For example, only
+     * the first javax.net.ssl.X509KeyManager in the array will be used.)
+     *
+     * @param km the sources of authentication keys or null
+     * @param tm the sources of peer authentication trust decisions or null
+     * @param random the source of randomness for this generator or null
+     * @throws KeyManagementException if this operation fails
+     */
+    public final void init(KeyManager[] km, TrustManager[] tm,
+                                SecureRandom random)
+        throws KeyManagementException {
+        contextSpi.engineInit(km, tm, random);
+    }
+
+    /**
+     * Returns a <code>SocketFactory</code> object for this
+     * context.
+     *
+     * @return the <code>SocketFactory</code> object
+     * @throws IllegalStateException if the SSLContextImpl requires
+     *          initialization and the <code>init()</code> has not been called
+     */
+    public final SSLSocketFactory getSocketFactory() {
+        return contextSpi.engineGetSocketFactory();
+    }
+
+    /**
+     * Returns a <code>ServerSocketFactory</code> object for
+     * this context.
+     *
+     * @return the <code>ServerSocketFactory</code> object
+     * @throws IllegalStateException if the SSLContextImpl requires
+     *          initialization and the <code>init()</code> has not been called
+     */
+    public final SSLServerSocketFactory getServerSocketFactory() {
+        return contextSpi.engineGetServerSocketFactory();
+    }
+
+    /**
+     * Creates a new <code>SSLEngine</code> using this context.
+     * <P>
+     * Applications using this factory method are providing no hints
+     * for an internal session reuse strategy. If hints are desired,
+     * {@link #createSSLEngine(String, int)} should be used
+     * instead.
+     * <P>
+     * Some cipher suites (such as Kerberos) require remote hostname
+     * information, in which case this factory method should not be used.
+     *
+     * @return  the <code>SSLEngine</code> object
+     * @throws  UnsupportedOperationException if the underlying provider
+     *          does not implement the operation.
+     * @throws  IllegalStateException if the SSLContextImpl requires
+     *          initialization and the <code>init()</code> has not been called
+     * @since   1.5
+     */
+    public final SSLEngine createSSLEngine() {
+        try {
+            return contextSpi.engineCreateSSLEngine();
+        } catch (AbstractMethodError e) {
+            UnsupportedOperationException unsup =
+                new UnsupportedOperationException(
+                    "Provider: " + getProvider() +
+                    " doesn't support this operation");
+            unsup.initCause(e);
+            throw unsup;
+        }
+    }
+
+    /**
+     * Creates a new <code>SSLEngine</code> using this context using
+     * advisory peer information.
+     * <P>
+     * Applications using this factory method are providing hints
+     * for an internal session reuse strategy.
+     * <P>
+     * Some cipher suites (such as Kerberos) require remote hostname
+     * information, in which case peerHost needs to be specified.
+     *
+     * @param   peerHost the non-authoritative name of the host
+     * @param   peerPort the non-authoritative port
+     * @return  the new <code>SSLEngine</code> object
+     * @throws  UnsupportedOperationException if the underlying provider
+     *          does not implement the operation.
+     * @throws  IllegalStateException if the SSLContextImpl requires
+     *          initialization and the <code>init()</code> has not been called
+     * @since   1.5
+     */
+    public final SSLEngine createSSLEngine(String peerHost, int peerPort) {
+        try {
+            return contextSpi.engineCreateSSLEngine(peerHost, peerPort);
+        } catch (AbstractMethodError e) {
+            UnsupportedOperationException unsup =
+                new UnsupportedOperationException(
+                    "Provider: " + getProvider() +
+                    " does not support this operation");
+            unsup.initCause(e);
+            throw unsup;
+        }
+    }
+
+    /**
+     * Returns the server session context, which represents the set of
+     * SSL sessions available for use during the handshake phase of
+     * server-side SSL sockets.
+     * <P>
+     * This context may be unavailable in some environments, in which
+     * case this method returns null. For example, when the underlying
+     * SSL provider does not provide an implementation of SSLSessionContext
+     * interface, this method returns null. A non-null session context
+     * is returned otherwise.
+     *
+     * @return server session context bound to this SSL context
+     */
+    public final SSLSessionContext getServerSessionContext() {
+        return contextSpi.engineGetServerSessionContext();
+    }
+
+    /**
+     * Returns the client session context, which represents the set of
+     * SSL sessions available for use during the handshake phase of
+     * client-side SSL sockets.
+     * <P>
+     * This context may be unavailable in some environments, in which
+     * case this method returns null. For example, when the underlying
+     * SSL provider does not provide an implementation of SSLSessionContext
+     * interface, this method returns null. A non-null session context
+     * is returned otherwise.
+     *
+     * @return client session context bound to this SSL context
+     */
+    public final SSLSessionContext getClientSessionContext() {
+        return contextSpi.engineGetClientSessionContext();
+    }
+
+    /**
+     * Returns a copy of the SSLParameters indicating the default
+     * settings for this SSL context.
+     *
+     * <p>The parameters will always have the ciphersuites and protocols
+     * arrays set to non-null values.
+     *
+     * @return a copy of the SSLParameters object with the default settings
+     * @throws UnsupportedOperationException if the default SSL parameters
+     *   could not be obtained.
+     * @since 1.6
+     */
+    public final SSLParameters getDefaultSSLParameters() {
+        return contextSpi.engineGetDefaultSSLParameters();
+    }
+
+    /**
+     * Returns a copy of the SSLParameters indicating the supported
+     * settings for this SSL context.
+     *
+     * <p>The parameters will always have the ciphersuites and protocols
+     * arrays set to non-null values.
+     *
+     * @return a copy of the SSLParameters object with the supported
+     *   settings
+     * @throws UnsupportedOperationException if the supported SSL parameters
+     *   could not be obtained.
+     * @since 1.6
+     */
+    public final SSLParameters getSupportedSSLParameters() {
+        return contextSpi.engineGetSupportedSSLParameters();
+    }
+
+}
diff --git a/javax/net/ssl/SSLContextSpi.java b/javax/net/ssl/SSLContextSpi.java
new file mode 100644
index 0000000..269ed85
--- /dev/null
+++ b/javax/net/ssl/SSLContextSpi.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 1999, 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 javax.net.ssl;
+
+import java.security.*;
+
+/**
+ * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>)
+ * for the <code>SSLContext</code> class.
+ *
+ * <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 SSL context.
+ *
+ * @since 1.4
+ * @see SSLContext
+ */
+public abstract class SSLContextSpi {
+    /**
+     * Initializes this context.
+     *
+     * @param km the sources of authentication keys
+     * @param tm the sources of peer authentication trust decisions
+     * @param sr the source of randomness
+     * @throws KeyManagementException if this operation fails
+     * @see SSLContext#init(KeyManager [], TrustManager [], SecureRandom)
+     */
+    protected abstract void engineInit(KeyManager[] km, TrustManager[] tm,
+        SecureRandom sr) throws KeyManagementException;
+
+    /**
+     * Returns a <code>SocketFactory</code> object for this
+     * context.
+     *
+     * @return the <code>SocketFactory</code> object
+     * @throws IllegalStateException if the SSLContextImpl requires
+     *         initialization and the <code>engineInit()</code>
+     *         has not been called
+     * @see javax.net.ssl.SSLContext#getSocketFactory()
+     */
+    protected abstract SSLSocketFactory engineGetSocketFactory();
+
+    /**
+     * Returns a <code>ServerSocketFactory</code> object for
+     * this context.
+     *
+     * @return the <code>ServerSocketFactory</code> object
+     * @throws IllegalStateException if the SSLContextImpl requires
+     *         initialization and the <code>engineInit()</code>
+     *         has not been called
+     * @see javax.net.ssl.SSLContext#getServerSocketFactory()
+     */
+    protected abstract SSLServerSocketFactory engineGetServerSocketFactory();
+
+    /**
+     * Creates a new <code>SSLEngine</code> using this context.
+     * <P>
+     * Applications using this factory method are providing no hints
+     * for an internal session reuse strategy. If hints are desired,
+     * {@link #engineCreateSSLEngine(String, int)} should be used
+     * instead.
+     * <P>
+     * Some cipher suites (such as Kerberos) require remote hostname
+     * information, in which case this factory method should not be used.
+     *
+     * @return  the <code>SSLEngine</code> Object
+     * @throws IllegalStateException if the SSLContextImpl requires
+     *         initialization and the <code>engineInit()</code>
+     *         has not been called
+     *
+     * @see     SSLContext#createSSLEngine()
+     *
+     * @since   1.5
+     */
+    protected abstract SSLEngine engineCreateSSLEngine();
+
+    /**
+     * Creates a <code>SSLEngine</code> using this context.
+     * <P>
+     * Applications using this factory method are providing hints
+     * for an internal session reuse strategy.
+     * <P>
+     * Some cipher suites (such as Kerberos) require remote hostname
+     * information, in which case peerHost needs to be specified.
+     *
+     * @param host the non-authoritative name of the host
+     * @param port the non-authoritative port
+     * @return  the <code>SSLEngine</code> Object
+     * @throws IllegalStateException if the SSLContextImpl requires
+     *         initialization and the <code>engineInit()</code>
+     *         has not been called
+     *
+     * @see     SSLContext#createSSLEngine(String, int)
+     *
+     * @since   1.5
+     */
+    protected abstract SSLEngine engineCreateSSLEngine(String host, int port);
+
+    /**
+     * Returns a server <code>SSLSessionContext</code> object for
+     * this context.
+     *
+     * @return the <code>SSLSessionContext</code> object
+     * @see javax.net.ssl.SSLContext#getServerSessionContext()
+     */
+    protected abstract SSLSessionContext engineGetServerSessionContext();
+
+    /**
+     * Returns a client <code>SSLSessionContext</code> object for
+     * this context.
+     *
+     * @return the <code>SSLSessionContext</code> object
+     * @see javax.net.ssl.SSLContext#getClientSessionContext()
+     */
+    protected abstract SSLSessionContext engineGetClientSessionContext();
+
+    private SSLSocket getDefaultSocket() {
+        try {
+            SSLSocketFactory factory = engineGetSocketFactory();
+            return (SSLSocket)factory.createSocket();
+        } catch (java.io.IOException e) {
+            throw new UnsupportedOperationException("Could not obtain parameters", e);
+        }
+    }
+
+    /**
+     * Returns a copy of the SSLParameters indicating the default
+     * settings for this SSL context.
+     *
+     * <p>The parameters will always have the ciphersuite and protocols
+     * arrays set to non-null values.
+     *
+     * <p>The default implementation obtains the parameters from an
+     * SSLSocket created by calling the
+     * {@linkplain javax.net.SocketFactory#createSocket
+     * SocketFactory.createSocket()} method of this context's SocketFactory.
+     *
+     * @return a copy of the SSLParameters object with the default settings
+     * @throws UnsupportedOperationException if the default SSL parameters
+     *   could not be obtained.
+     *
+     * @since 1.6
+     */
+    protected SSLParameters engineGetDefaultSSLParameters() {
+        SSLSocket socket = getDefaultSocket();
+        return socket.getSSLParameters();
+    }
+
+    /**
+     * Returns a copy of the SSLParameters indicating the maximum supported
+     * settings for this SSL context.
+     *
+     * <p>The parameters will always have the ciphersuite and protocols
+     * arrays set to non-null values.
+     *
+     * <p>The default implementation obtains the parameters from an
+     * SSLSocket created by calling the
+     * {@linkplain javax.net.SocketFactory#createSocket
+     * SocketFactory.createSocket()} method of this context's SocketFactory.
+     *
+     * @return a copy of the SSLParameters object with the maximum supported
+     *   settings
+     * @throws UnsupportedOperationException if the supported SSL parameters
+     *   could not be obtained.
+     *
+     * @since 1.6
+     */
+    protected SSLParameters engineGetSupportedSSLParameters() {
+        SSLSocket socket = getDefaultSocket();
+        SSLParameters params = new SSLParameters();
+        params.setCipherSuites(socket.getSupportedCipherSuites());
+        params.setProtocols(socket.getSupportedProtocols());
+        return params;
+    }
+
+}
diff --git a/javax/net/ssl/SSLEngine.java b/javax/net/ssl/SSLEngine.java
new file mode 100644
index 0000000..76f8f66
--- /dev/null
+++ b/javax/net/ssl/SSLEngine.java
@@ -0,0 +1,2081 @@
+/*
+ * Copyright (c) 2003, 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 javax.net.ssl;
+
+import java.nio.ByteBuffer;
+import java.nio.ReadOnlyBufferException;
+import java.util.List;
+import java.util.function.BiFunction;
+
+
+/**
+ * A class which enables secure communications using protocols such as
+ * the Secure Sockets Layer (SSL) or
+ * <A HREF="http://www.ietf.org/rfc/rfc2246.txt"> IETF RFC 2246 "Transport
+ * Layer Security" (TLS) </A> protocols, but is transport independent.
+ * <P>
+ * The secure communications modes include: <UL>
+ *
+ *      <LI> <em>Integrity Protection</em>.  SSL/TLS protects against
+ *      modification of messages by an active wiretapper.
+ *
+ *      <LI> <em>Authentication</em>.  In most modes, SSL/TLS provides
+ *      peer authentication.  Servers are usually authenticated, and
+ *      clients may be authenticated as requested by servers.
+ *
+ *      <LI> <em>Confidentiality (Privacy Protection)</em>.  In most
+ *      modes, SSL/TLS encrypts data being sent between client and
+ *      server.  This protects the confidentiality of data, so that
+ *      passive wiretappers won't see sensitive data such as financial
+ *      information or personal information of many kinds.
+ *
+ *      </UL>
+ *
+ * These kinds of protection are specified by a "cipher suite", which
+ * is a combination of cryptographic algorithms used by a given SSL
+ * connection.  During the negotiation process, the two endpoints must
+ * agree on a cipher suite that is available in both environments.  If
+ * there is no such suite in common, no SSL connection can be
+ * established, and no data can be exchanged.
+ * <P>
+ * The cipher suite used is established by a negotiation process called
+ * "handshaking".  The goal of this process is to create or rejoin a
+ * "session", which may protect many connections over time.  After
+ * handshaking has completed, you can access session attributes by
+ * using the {@link #getSession()} method.
+ * <P>
+ * The <code>SSLSocket</code> class provides much of the same security
+ * functionality, but all of the inbound and outbound data is
+ * automatically transported using the underlying {@link
+ * java.net.Socket Socket}, which by design uses a blocking model.
+ * While this is appropriate for many applications, this model does not
+ * provide the scalability required by large servers.
+ * <P>
+ * The primary distinction of an <code>SSLEngine</code> is that it
+ * operates on inbound and outbound byte streams, independent of the
+ * transport mechanism.  It is the responsibility of the
+ * <code>SSLEngine</code> user to arrange for reliable I/O transport to
+ * the peer.  By separating the SSL/TLS abstraction from the I/O
+ * transport mechanism, the <code>SSLEngine</code> can be used for a
+ * wide variety of I/O types, such as {@link
+ * java.nio.channels.spi.AbstractSelectableChannel#configureBlocking(boolean)
+ * non-blocking I/O (polling)}, {@link java.nio.channels.Selector
+ * selectable non-blocking I/O}, {@link java.net.Socket Socket} and the
+ * traditional Input/OutputStreams, local {@link java.nio.ByteBuffer
+ * ByteBuffers} or byte arrays, <A
+ * HREF="http://www.jcp.org/en/jsr/detail?id=203"> future asynchronous
+ * I/O models </A>, and so on.
+ * <P>
+ * At a high level, the <code>SSLEngine</code> appears thus:
+ *
+ * <pre>
+ *                   app data
+ *
+ *                |           ^
+ *                |     |     |
+ *                v     |     |
+ *           +----+-----|-----+----+
+ *           |          |          |
+ *           |       SSL|Engine    |
+ *   wrap()  |          |          |  unwrap()
+ *           | OUTBOUND | INBOUND  |
+ *           |          |          |
+ *           +----+-----|-----+----+
+ *                |     |     ^
+ *                |     |     |
+ *                v           |
+ *
+ *                   net data
+ * </pre>
+ * Application data (also known as plaintext or cleartext) is data which
+ * is produced or consumed by an application.  Its counterpart is
+ * network data, which consists of either handshaking and/or ciphertext
+ * (encrypted) data, and destined to be transported via an I/O
+ * mechanism.  Inbound data is data which has been received from the
+ * peer, and outbound data is destined for the peer.
+ * <P>
+ * (In the context of an <code>SSLEngine</code>, the term "handshake
+ * data" is taken to mean any data exchanged to establish and control a
+ * secure connection.  Handshake data includes the SSL/TLS messages
+ * "alert", "change_cipher_spec," and "handshake.")
+ * <P>
+ * There are five distinct phases to an <code>SSLEngine</code>.
+ *
+ * <OL>
+ *     <li> Creation - The <code>SSLEngine</code> has been created and
+ *     initialized, but has not yet been used.  During this phase, an
+ *     application may set any <code>SSLEngine</code>-specific settings
+ *     (enabled cipher suites, whether the <code>SSLEngine</code> should
+ *     handshake in client or server mode, and so on).  Once
+ *     handshaking has begun, though, any new settings (except
+ *     client/server mode, see below) will be used for
+ *     the next handshake.
+ *
+ *     <li> Initial Handshake - The initial handshake is a procedure by
+ *     which the two peers exchange communication parameters until an
+ *     SSLSession is established.  Application data can not be sent during
+ *     this phase.
+ *
+ *     <li> Application Data - Once the communication parameters have
+ *     been established and the handshake is complete, application data
+ *     may flow through the <code>SSLEngine</code>.  Outbound
+ *     application messages are encrypted and integrity protected,
+ *     and inbound messages reverse the process.
+ *
+ *     <li>  Rehandshaking - Either side may request a renegotiation of
+ *     the session at any time during the Application Data phase.  New
+ *     handshaking data can be intermixed among the application data.
+ *     Before starting the rehandshake phase, the application may
+ *     reset the SSL/TLS communication parameters such as the list of
+ *     enabled ciphersuites and whether to use client authentication,
+ *     but can not change between client/server modes.  As before, once
+ *     handshaking has begun, any new <code>SSLEngine</code>
+ *     configuration settings will not be used until the next
+ *     handshake.
+ *
+ *     <li>  Closure - When the connection is no longer needed, the
+ *     application should close the <code>SSLEngine</code> and should
+ *     send/receive any remaining messages to the peer before
+ *     closing the underlying transport mechanism.  Once an engine is
+ *     closed, it is not reusable:  a new <code>SSLEngine</code> must
+ *     be created.
+ * </OL>
+ * An <code>SSLEngine</code> is created by calling {@link
+ * SSLContext#createSSLEngine()} from an initialized
+ * <code>SSLContext</code>.  Any configuration
+ * parameters should be set before making the first call to
+ * <code>wrap()</code>, <code>unwrap()</code>, or
+ * <code>beginHandshake()</code>.  These methods all trigger the
+ * initial handshake.
+ * <P>
+ * Data moves through the engine by calling {@link #wrap(ByteBuffer,
+ * ByteBuffer) wrap()} or {@link #unwrap(ByteBuffer, ByteBuffer)
+ * unwrap()} on outbound or inbound data, respectively.  Depending on
+ * the state of the <code>SSLEngine</code>, a <code>wrap()</code> call
+ * may consume application data from the source buffer and may produce
+ * network data in the destination buffer.  The outbound data
+ * may contain application and/or handshake data.  A call to
+ * <code>unwrap()</code> will examine the source buffer and may
+ * advance the handshake if the data is handshaking information, or
+ * may place application data in the destination buffer if the data
+ * is application.  The state of the underlying SSL/TLS algorithm
+ * will determine when data is consumed and produced.
+ * <P>
+ * Calls to <code>wrap()</code> and <code>unwrap()</code> return an
+ * <code>SSLEngineResult</code> which indicates the status of the
+ * operation, and (optionally) how to interact with the engine to make
+ * progress.
+ * <P>
+ * The <code>SSLEngine</code> produces/consumes complete SSL/TLS
+ * packets only, and does not store application data internally between
+ * calls to <code>wrap()/unwrap()</code>.  Thus input and output
+ * <code>ByteBuffer</code>s must be sized appropriately to hold the
+ * maximum record that can be produced.  Calls to {@link
+ * SSLSession#getPacketBufferSize()} and {@link
+ * SSLSession#getApplicationBufferSize()} should be used to determine
+ * the appropriate buffer sizes.  The size of the outbound application
+ * data buffer generally does not matter.  If buffer conditions do not
+ * allow for the proper consumption/production of data, the application
+ * must determine (via {@link SSLEngineResult}) and correct the
+ * problem, and then try the call again.
+ * <P>
+ * For example, <code>unwrap()</code> will return a {@link
+ * SSLEngineResult.Status#BUFFER_OVERFLOW} result if the engine
+ * determines that there is not enough destination buffer space available.
+ * Applications should call {@link SSLSession#getApplicationBufferSize()}
+ * and compare that value with the space available in the destination buffer,
+ * enlarging the buffer if necessary.  Similarly, if <code>unwrap()</code>
+ * were to return a {@link SSLEngineResult.Status#BUFFER_UNDERFLOW}, the
+ * application should call {@link SSLSession#getPacketBufferSize()} to ensure
+ * that the source buffer has enough room to hold a record (enlarging if
+ * necessary), and then obtain more inbound data.
+ *
+ * <pre>{@code
+ *   SSLEngineResult r = engine.unwrap(src, dst);
+ *   switch (r.getStatus()) {
+ *   BUFFER_OVERFLOW:
+ *       // Could attempt to drain the dst buffer of any already obtained
+ *       // data, but we'll just increase it to the size needed.
+ *       int appSize = engine.getSession().getApplicationBufferSize();
+ *       ByteBuffer b = ByteBuffer.allocate(appSize + dst.position());
+ *       dst.flip();
+ *       b.put(dst);
+ *       dst = b;
+ *       // retry the operation.
+ *       break;
+ *   BUFFER_UNDERFLOW:
+ *       int netSize = engine.getSession().getPacketBufferSize();
+ *       // Resize buffer if needed.
+ *       if (netSize > dst.capacity()) {
+ *           ByteBuffer b = ByteBuffer.allocate(netSize);
+ *           src.flip();
+ *           b.put(src);
+ *           src = b;
+ *       }
+ *       // Obtain more inbound network data for src,
+ *       // then retry the operation.
+ *       break;
+ *   // other cases: CLOSED, OK.
+ *   }
+ * }</pre>
+ *
+ * <P>
+ * Unlike <code>SSLSocket</code>, all methods of SSLEngine are
+ * non-blocking.  <code>SSLEngine</code> implementations may
+ * require the results of tasks that may take an extended period of
+ * time to complete, or may even block.  For example, a TrustManager
+ * may need to connect to a remote certificate validation service,
+ * or a KeyManager might need to prompt a user to determine which
+ * certificate to use as part of client authentication.  Additionally,
+ * creating cryptographic signatures and verifying them can be slow,
+ * seemingly blocking.
+ * <P>
+ * For any operation which may potentially block, the
+ * <code>SSLEngine</code> will create a {@link java.lang.Runnable}
+ * delegated task.  When <code>SSLEngineResult</code> indicates that a
+ * delegated task result is needed, the application must call {@link
+ * #getDelegatedTask()} to obtain an outstanding delegated task and
+ * call its {@link java.lang.Runnable#run() run()} method (possibly using
+ * a different thread depending on the compute strategy).  The
+ * application should continue obtaining delegated tasks until no more
+ * exist, and try the original operation again.
+ * <P>
+ * At the end of a communication session, applications should properly
+ * close the SSL/TLS link.  The SSL/TLS protocols have closure handshake
+ * messages, and these messages should be communicated to the peer
+ * before releasing the <code>SSLEngine</code> and closing the
+ * underlying transport mechanism.  A close can be initiated by one of:
+ * an SSLException, an inbound closure handshake message, or one of the
+ * close methods.  In all cases, closure handshake messages are
+ * generated by the engine, and <code>wrap()</code> should be repeatedly
+ * called until the resulting <code>SSLEngineResult</code>'s status
+ * returns "CLOSED", or {@link #isOutboundDone()} returns true.  All
+ * data obtained from the <code>wrap()</code> method should be sent to the
+ * peer.
+ * <P>
+ * {@link #closeOutbound()} is used to signal the engine that the
+ * application will not be sending any more data.
+ * <P>
+ * A peer will signal its intent to close by sending its own closure
+ * handshake message.  After this message has been received and
+ * processed by the local <code>SSLEngine</code>'s <code>unwrap()</code>
+ * call, the application can detect the close by calling
+ * <code>unwrap()</code> and looking for a <code>SSLEngineResult</code>
+ * with status "CLOSED", or if {@link #isInboundDone()} returns true.
+ * If for some reason the peer closes the communication link without
+ * sending the proper SSL/TLS closure message, the application can
+ * detect the end-of-stream and can signal the engine via {@link
+ * #closeInbound()} that there will no more inbound messages to
+ * process.  Some applications might choose to require orderly shutdown
+ * messages from a peer, in which case they can check that the closure
+ * was generated by a handshake message and not by an end-of-stream
+ * condition.
+ * <P>
+ * There are two groups of cipher suites which you will need to know
+ * about when managing cipher suites:
+ *
+ * <UL>
+ *      <LI> <em>Supported</em> cipher suites:  all the suites which are
+ *      supported by the SSL implementation.  This list is reported
+ *      using {@link #getSupportedCipherSuites()}.
+ *
+ *      <LI> <em>Enabled</em> cipher suites, which may be fewer than
+ *      the full set of supported suites.  This group is set using the
+ *      {@link #setEnabledCipherSuites(String [])} method, and
+ *      queried using the {@link #getEnabledCipherSuites()} method.
+ *      Initially, a default set of cipher suites will be enabled on a
+ *      new engine that represents the minimum suggested
+ *      configuration.
+ * </UL>
+ *
+ * Implementation defaults require that only cipher suites which
+ * authenticate servers and provide confidentiality be enabled by
+ * default.  Only if both sides explicitly agree to unauthenticated
+ * and/or non-private (unencrypted) communications will such a
+ * cipher suite be selected.
+ * <P>
+ * Each SSL/TLS connection must have one client and one server, thus
+ * each endpoint must decide which role to assume.  This choice determines
+ * who begins the handshaking process as well as which type of messages
+ * should be sent by each party.  The method {@link
+ * #setUseClientMode(boolean)} configures the mode.  Once the initial
+ * handshaking has started, an <code>SSLEngine</code> can not switch
+ * between client and server modes, even when performing renegotiations.
+ * <P>
+ * Applications might choose to process delegated tasks in different
+ * threads.  When an <code>SSLEngine</code>
+ * is created, the current {@link java.security.AccessControlContext}
+ * is saved.  All future delegated tasks will be processed using this
+ * context:  that is, all access control decisions will be made using the
+ * context captured at engine creation.
+ *
+ * <HR>
+ *
+ * <B>Concurrency Notes</B>:
+ * There are two concurrency issues to be aware of:
+ *
+ * <OL>
+ *      <li>The <code>wrap()</code> and <code>unwrap()</code> methods
+ *      may execute concurrently of each other.
+ *
+ *      <li> The SSL/TLS protocols employ ordered packets.
+ *      Applications must take care to ensure that generated packets
+ *      are delivered in sequence.  If packets arrive
+ *      out-of-order, unexpected or fatal results may occur.
+ * <P>
+ *      For example:
+ *
+ *      <pre>
+ *              synchronized (outboundLock) {
+ *                  sslEngine.wrap(src, dst);
+ *                  outboundQueue.put(dst);
+ *              }
+ *      </pre>
+ *
+ *      As a corollary, two threads must not attempt to call the same method
+ *      (either <code>wrap()</code> or <code>unwrap()</code>) concurrently,
+ *      because there is no way to guarantee the eventual packet ordering.
+ * </OL>
+ *
+ * <h3>Default configuration for different Android versions</h3>
+ * <p>{@code SSLEngine} instances obtained from the default {@link SSLContext} are configured as
+ * follows:
+ *
+ * <style type="text/css">
+ *   tr.deprecated {
+ *     background-color: #ccc;
+ *     color: #999;
+ *     font-style: italic;
+ *   }
+ * </style>
+ *
+ * <h4>Protocols</h4>
+ * <table>
+ *     <thead>
+ *         <tr>
+ *             <th>Protocol</th>
+ *             <th>Supported (API Levels)</th>
+ *             <th>Enabled by default (API Levels)</th>
+ *         </tr>
+ *     </thead>
+ *     <tbody>
+ *         <tr class="deprecated">
+ *             <td>SSLv3</td>
+ *             <td>1&ndash;25</td>
+ *             <td>1&ndash;22</td>
+ *         </tr>
+ *         <tr>
+ *             <td>TLSv1</td>
+ *             <td>1+</td>
+ *             <td>1+</td>
+ *         </tr>
+ *         <tr>
+ *             <td>TLSv1.1</td>
+ *             <td>20+</td>
+ *             <td>20+</td>
+ *         </tr>
+ *         <tr>
+ *             <td>TLSv1.2</td>
+ *             <td>20+</td>
+ *             <td>20+</td>
+ *         </tr>
+ *         <tr>
+ *             <td>TLSv1.3</td>
+ *             <td>29+</td>
+ *             <td>29+</td>
+ *         </tr>
+ *     </tbody>
+ * </table>
+ *
+ * <h4>Cipher suites</h4>
+ * <table>
+ *   <thead>
+ *     <tr>
+ *       <th>Cipher suite</th>
+ *       <th>Supported (API Levels)</th>
+ *       <th>Enabled by default (API Levels)</th>
+ *     </tr>
+ *   </thead>
+ *   <tbody>
+ *     <tr class="deprecated">
+ *       <td>SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA</td>
+ *       <td>9-22</td>
+ *       <td>9-19</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA</td>
+ *       <td>9-22</td>
+ *       <td>9-19</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>SSL_DHE_DSS_WITH_DES_CBC_SHA</td>
+ *       <td>9-22</td>
+ *       <td>9-19</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA</td>
+ *       <td>9-22</td>
+ *       <td>9-19</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA</td>
+ *       <td>9-22</td>
+ *       <td>9-19</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>SSL_DHE_RSA_WITH_DES_CBC_SHA</td>
+ *       <td>9-22</td>
+ *       <td>9-19</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA</td>
+ *       <td>9-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>SSL_DH_anon_EXPORT_WITH_RC4_40_MD5</td>
+ *       <td>9-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>SSL_DH_anon_WITH_3DES_EDE_CBC_SHA</td>
+ *       <td>9-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>SSL_DH_anon_WITH_DES_CBC_SHA</td>
+ *       <td>9-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>SSL_DH_anon_WITH_RC4_128_MD5</td>
+ *       <td>9-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>SSL_RSA_EXPORT_WITH_DES40_CBC_SHA</td>
+ *       <td>9-22</td>
+ *       <td>9-19</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>SSL_RSA_EXPORT_WITH_RC4_40_MD5</td>
+ *       <td>9-22</td>
+ *       <td>9-19</td>
+ *     </tr>
+ *     <tr>
+ *       <td>SSL_RSA_WITH_3DES_EDE_CBC_SHA</td>
+ *       <td>9+</td>
+ *       <td>9-19</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>SSL_RSA_WITH_DES_CBC_SHA</td>
+ *       <td>9-22</td>
+ *       <td>9-19</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>SSL_RSA_WITH_NULL_MD5</td>
+ *       <td>9-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>SSL_RSA_WITH_NULL_SHA</td>
+ *       <td>9-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>SSL_RSA_WITH_RC4_128_MD5</td>
+ *       <td>9-25</td>
+ *       <td>9-19</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>SSL_RSA_WITH_RC4_128_SHA</td>
+ *       <td>9-25</td>
+ *       <td>9-23</td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_AES_128_GCM_SHA256</td>
+ *       <td>29+</td>
+ *       <td>29+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_AES_256_GCM_SHA384</td>
+ *       <td>29+</td>
+ *       <td>29+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_CHACHA20_POLY1305_SHA256</td>
+ *       <td>29+</td>
+ *       <td>29+</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA</td>
+ *       <td>1-8</td>
+ *       <td>1-8</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA</td>
+ *       <td>1-8</td>
+ *       <td>1-8</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DHE_DSS_WITH_AES_128_CBC_SHA</td>
+ *       <td>9-22</td>
+ *       <td>9-22</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DHE_DSS_WITH_AES_128_CBC_SHA256</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DHE_DSS_WITH_AES_128_GCM_SHA256</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DHE_DSS_WITH_AES_256_CBC_SHA</td>
+ *       <td>9-22</td>
+ *       <td>20-22</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DHE_DSS_WITH_AES_256_CBC_SHA256</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DHE_DSS_WITH_AES_256_GCM_SHA384</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DHE_DSS_WITH_DES_CBC_SHA</td>
+ *       <td>1-8</td>
+ *       <td>1-8</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA</td>
+ *       <td>1-8</td>
+ *       <td>1-8</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA</td>
+ *       <td>1-8</td>
+ *       <td>1-8</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DHE_RSA_WITH_AES_128_CBC_SHA</td>
+ *       <td>9-25</td>
+ *       <td>9-25</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DHE_RSA_WITH_AES_128_CBC_SHA256</td>
+ *       <td>20-25</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DHE_RSA_WITH_AES_128_GCM_SHA256</td>
+ *       <td>20-25</td>
+ *       <td>20-25</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DHE_RSA_WITH_AES_256_CBC_SHA</td>
+ *       <td>9-25</td>
+ *       <td>20-25</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DHE_RSA_WITH_AES_256_CBC_SHA256</td>
+ *       <td>20-25</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DHE_RSA_WITH_AES_256_GCM_SHA384</td>
+ *       <td>20-25</td>
+ *       <td>20-25</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DHE_RSA_WITH_DES_CBC_SHA</td>
+ *       <td>1-8</td>
+ *       <td>1-8</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA</td>
+ *       <td>1-8</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA</td>
+ *       <td>1-8</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DH_DSS_WITH_DES_CBC_SHA</td>
+ *       <td>1-8</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA</td>
+ *       <td>1-8</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA</td>
+ *       <td>1-8</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DH_RSA_WITH_DES_CBC_SHA</td>
+ *       <td>1-8</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA</td>
+ *       <td>1-8</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DH_anon_WITH_3DES_EDE_CBC_SHA</td>
+ *       <td>1-8</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DH_anon_WITH_AES_128_CBC_SHA</td>
+ *       <td>9-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DH_anon_WITH_AES_128_CBC_SHA256</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DH_anon_WITH_AES_128_GCM_SHA256</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DH_anon_WITH_AES_256_CBC_SHA</td>
+ *       <td>9-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DH_anon_WITH_AES_256_CBC_SHA256</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DH_anon_WITH_AES_256_GCM_SHA384</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DH_anon_WITH_DES_CBC_SHA</td>
+ *       <td>1-8</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA</td>
+ *       <td>20+</td>
+ *       <td>20+</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256</td>
+ *       <td>20-28</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256</td>
+ *       <td>20+</td>
+ *       <td>20+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA</td>
+ *       <td>20+</td>
+ *       <td>20+</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384</td>
+ *       <td>20-28</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384</td>
+ *       <td>20+</td>
+ *       <td>20+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256</td>
+ *       <td>24+</td>
+ *       <td>24+</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDHE_ECDSA_WITH_NULL_SHA</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDHE_ECDSA_WITH_RC4_128_SHA</td>
+ *       <td>20-25</td>
+ *       <td>20-23</td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA</td>
+ *       <td>21+</td>
+ *       <td>21+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA</td>
+ *       <td>21+</td>
+ *       <td>21+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256</td>
+ *       <td>24+</td>
+ *       <td>24+</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA</td>
+ *       <td>20+</td>
+ *       <td>20+</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256</td>
+ *       <td>20-28</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256</td>
+ *       <td>20+</td>
+ *       <td>20+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA</td>
+ *       <td>20+</td>
+ *       <td>20+</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384</td>
+ *       <td>20-28</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384</td>
+ *       <td>20+</td>
+ *       <td>20+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256</td>
+ *       <td>24+</td>
+ *       <td>24+</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDHE_RSA_WITH_NULL_SHA</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDHE_RSA_WITH_RC4_128_SHA</td>
+ *       <td>20-25</td>
+ *       <td>20-23</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_ECDSA_WITH_NULL_SHA</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_ECDSA_WITH_RC4_128_SHA</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_RSA_WITH_AES_128_CBC_SHA</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_RSA_WITH_AES_256_CBC_SHA</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_RSA_WITH_NULL_SHA</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_RSA_WITH_RC4_128_SHA</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_anon_WITH_AES_128_CBC_SHA</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_anon_WITH_AES_256_CBC_SHA</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_anon_WITH_NULL_SHA</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_anon_WITH_RC4_128_SHA</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_EMPTY_RENEGOTIATION_INFO_SCSV</td>
+ *       <td>20+</td>
+ *       <td>20+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_FALLBACK_SCSV</td>
+ *       <td>21+</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_NULL_WITH_NULL_NULL</td>
+ *       <td>1-8</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_PSK_WITH_3DES_EDE_CBC_SHA</td>
+ *       <td>21-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_PSK_WITH_AES_128_CBC_SHA</td>
+ *       <td>21+</td>
+ *       <td>21+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_PSK_WITH_AES_256_CBC_SHA</td>
+ *       <td>21+</td>
+ *       <td>21+</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_PSK_WITH_RC4_128_SHA</td>
+ *       <td>21-25</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_RSA_EXPORT_WITH_DES40_CBC_SHA</td>
+ *       <td>1-8</td>
+ *       <td>1-8</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_RSA_WITH_3DES_EDE_CBC_SHA</td>
+ *       <td>1-8</td>
+ *       <td>1-8</td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_RSA_WITH_AES_128_CBC_SHA</td>
+ *       <td>9+</td>
+ *       <td>9+</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_RSA_WITH_AES_128_CBC_SHA256</td>
+ *       <td>20-28</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_RSA_WITH_AES_128_GCM_SHA256</td>
+ *       <td>20+</td>
+ *       <td>20+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_RSA_WITH_AES_256_CBC_SHA</td>
+ *       <td>9+</td>
+ *       <td>20+</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_RSA_WITH_AES_256_CBC_SHA256</td>
+ *       <td>20-28</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_RSA_WITH_AES_256_GCM_SHA384</td>
+ *       <td>20+</td>
+ *       <td>20+</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_RSA_WITH_DES_CBC_SHA</td>
+ *       <td>1-8</td>
+ *       <td>1-8</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_RSA_WITH_NULL_MD5</td>
+ *       <td>1-8</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_RSA_WITH_NULL_SHA</td>
+ *       <td>1-8</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_RSA_WITH_NULL_SHA256</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *   </tbody>
+ * </table>
+ *
+ * <p><em>NOTE</em>: PSK cipher suites are enabled by default only if the {@code SSLContext} through
+ * which the engine was created has been initialized with a {@code PSKKeyManager}.
+ *
+ * @see SSLContext
+ * @see SSLSocket
+ * @see SSLServerSocket
+ * @see SSLSession
+ * @see java.net.Socket
+ *
+ * @since 1.5
+ * @author Brad R. Wetmore
+ */
+
+public abstract class SSLEngine {
+
+    private String peerHost = null;
+    private int peerPort = -1;
+
+    /**
+     * Constructor for an <code>SSLEngine</code> providing no hints
+     * for an internal session reuse strategy.
+     *
+     * @see     SSLContext#createSSLEngine()
+     * @see     SSLSessionContext
+     */
+    protected SSLEngine() {
+    }
+
+    /**
+     * Constructor for an <code>SSLEngine</code>.
+     * <P>
+     * <code>SSLEngine</code> implementations may use the
+     * <code>peerHost</code> and <code>peerPort</code> parameters as hints
+     * for their internal session reuse strategy.
+     * <P>
+     * Some cipher suites (such as Kerberos) require remote hostname
+     * information. Implementations of this class should use this
+     * constructor to use Kerberos.
+     * <P>
+     * The parameters are not authenticated by the
+     * <code>SSLEngine</code>.
+     *
+     * @param   peerHost the name of the peer host
+     * @param   peerPort the port number of the peer
+     * @see     SSLContext#createSSLEngine(String, int)
+     * @see     SSLSessionContext
+     */
+    protected SSLEngine(String peerHost, int peerPort) {
+        this.peerHost = peerHost;
+        this.peerPort = peerPort;
+    }
+
+    /**
+     * Returns the host name of the peer.
+     * <P>
+     * Note that the value is not authenticated, and should not be
+     * relied upon.
+     *
+     * @return  the host name of the peer, or null if nothing is
+     *          available.
+     */
+    public String getPeerHost() {
+        return peerHost;
+    }
+
+    /**
+     * Returns the port number of the peer.
+     * <P>
+     * Note that the value is not authenticated, and should not be
+     * relied upon.
+     *
+     * @return  the port number of the peer, or -1 if nothing is
+     *          available.
+     */
+    public int getPeerPort() {
+        return peerPort;
+    }
+
+    /**
+     * Attempts to encode a buffer of plaintext application data into
+     * SSL/TLS network data.
+     * <P>
+     * An invocation of this method behaves in exactly the same manner
+     * as the invocation:
+     * <blockquote><pre>
+     * {@link #wrap(ByteBuffer [], int, int, ByteBuffer)
+     *     engine.wrap(new ByteBuffer [] { src }, 0, 1, dst);}
+     * </pre></blockquote>
+     *
+     * @param   src
+     *          a <code>ByteBuffer</code> containing outbound application data
+     * @param   dst
+     *          a <code>ByteBuffer</code> to hold outbound network data
+     * @return  an <code>SSLEngineResult</code> describing the result
+     *          of this operation.
+     * @throws  SSLException
+     *          A problem was encountered while processing the
+     *          data that caused the <code>SSLEngine</code> to abort.
+     *          See the class description for more information on
+     *          engine closure.
+     * @throws  ReadOnlyBufferException
+     *          if the <code>dst</code> buffer is read-only.
+     * @throws  IllegalArgumentException
+     *          if either <code>src</code> or <code>dst</code>
+     *          is null.
+     * @throws  IllegalStateException if the client/server mode
+     *          has not yet been set.
+     * @see     #wrap(ByteBuffer [], int, int, ByteBuffer)
+     */
+    public SSLEngineResult wrap(ByteBuffer src,
+            ByteBuffer dst) throws SSLException {
+        return wrap(new ByteBuffer [] { src }, 0, 1, dst);
+    }
+
+    /**
+     * Attempts to encode plaintext bytes from a sequence of data
+     * buffers into SSL/TLS network data.
+     * <P>
+     * An invocation of this method behaves in exactly the same manner
+     * as the invocation:
+     * <blockquote><pre>
+     * {@link #wrap(ByteBuffer [], int, int, ByteBuffer)
+     *     engine.wrap(srcs, 0, srcs.length, dst);}
+     * </pre></blockquote>
+     *
+     * @param   srcs
+     *          an array of <code>ByteBuffers</code> containing the
+     *          outbound application data
+     * @param   dst
+     *          a <code>ByteBuffer</code> to hold outbound network data
+     * @return  an <code>SSLEngineResult</code> describing the result
+     *          of this operation.
+     * @throws  SSLException
+     *          A problem was encountered while processing the
+     *          data that caused the <code>SSLEngine</code> to abort.
+     *          See the class description for more information on
+     *          engine closure.
+     * @throws  ReadOnlyBufferException
+     *          if the <code>dst</code> buffer is read-only.
+     * @throws  IllegalArgumentException
+     *          if either <code>srcs</code> or <code>dst</code>
+     *          is null, or if any element in <code>srcs</code> is null.
+     * @throws  IllegalStateException if the client/server mode
+     *          has not yet been set.
+     * @see     #wrap(ByteBuffer [], int, int, ByteBuffer)
+     */
+    public SSLEngineResult wrap(ByteBuffer [] srcs,
+            ByteBuffer dst) throws SSLException {
+        if (srcs == null) {
+            throw new IllegalArgumentException("src == null");
+        }
+        return wrap(srcs, 0, srcs.length, dst);
+    }
+
+
+    /**
+     * Attempts to encode plaintext bytes from a subsequence of data
+     * buffers into SSL/TLS network data.  This <i>"gathering"</i>
+     * operation encodes, in a single invocation, a sequence of bytes
+     * from one or more of a given sequence of buffers.  Gathering
+     * wraps 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.  See
+     * {@link java.nio.channels.GatheringByteChannel} for more
+     * information on gathering, and {@link
+     * java.nio.channels.GatheringByteChannel#write(ByteBuffer[],
+     * int, int)} for more information on the subsequence
+     * behavior.
+     * <P>
+     * Depending on the state of the SSLEngine, this method may produce
+     * network data without consuming any application data (for example,
+     * it may generate handshake data.)
+     * <P>
+     * The application is responsible for reliably transporting the
+     * network data to the peer, and for ensuring that data created by
+     * multiple calls to wrap() is transported in the same order in which
+     * it was generated.  The application must properly synchronize
+     * multiple calls to this method.
+     * <P>
+     * If this <code>SSLEngine</code> has not yet started its initial
+     * handshake, this method will automatically start the handshake.
+     * <P>
+     * This method will attempt to produce SSL/TLS records, and will
+     * consume as much source data as possible, but will never consume
+     * more than the sum of the bytes remaining in each buffer.  Each
+     * <code>ByteBuffer</code>'s position is updated to reflect the
+     * amount of data consumed or produced.  The limits remain the
+     * same.
+     * <P>
+     * The underlying memory used by the <code>srcs</code> and
+     * <code>dst ByteBuffer</code>s must not be the same.
+     * <P>
+     * See the class description for more information on engine closure.
+     *
+     * @param   srcs
+     *          an array of <code>ByteBuffers</code> containing the
+     *          outbound application data
+     * @param   offset
+     *          The offset within the buffer array of the first buffer from
+     *          which bytes are to be retrieved; it must be non-negative
+     *          and no larger than <code>srcs.length</code>
+     * @param   length
+     *          The maximum number of buffers to be accessed; it must be
+     *          non-negative and no larger than
+     *          <code>srcs.length</code>&nbsp;-&nbsp;<code>offset</code>
+     * @param   dst
+     *          a <code>ByteBuffer</code> to hold outbound network data
+     * @return  an <code>SSLEngineResult</code> describing the result
+     *          of this operation.
+     * @throws  SSLException
+     *          A problem was encountered while processing the
+     *          data that caused the <code>SSLEngine</code> to abort.
+     *          See the class description for more information on
+     *          engine closure.
+     * @throws  IndexOutOfBoundsException
+     *          if the preconditions on the <code>offset</code> and
+     *          <code>length</code> parameters do not hold.
+     * @throws  ReadOnlyBufferException
+     *          if the <code>dst</code> buffer is read-only.
+     * @throws  IllegalArgumentException
+     *          if either <code>srcs</code> or <code>dst</code>
+     *          is null, or if any element in the <code>srcs</code>
+     *          subsequence specified is null.
+     * @throws  IllegalStateException if the client/server mode
+     *          has not yet been set.
+     * @see     java.nio.channels.GatheringByteChannel
+     * @see     java.nio.channels.GatheringByteChannel#write(
+     *              ByteBuffer[], int, int)
+     */
+    public abstract SSLEngineResult wrap(ByteBuffer [] srcs, int offset,
+            int length, ByteBuffer dst) throws SSLException;
+
+    /**
+     * Attempts to decode SSL/TLS network data into a plaintext
+     * application data buffer.
+     * <P>
+     * An invocation of this method behaves in exactly the same manner
+     * as the invocation:
+     * <blockquote><pre>
+     * {@link #unwrap(ByteBuffer, ByteBuffer [], int, int)
+     *     engine.unwrap(src, new ByteBuffer [] { dst }, 0, 1);}
+     * </pre></blockquote>
+     *
+     * @param   src
+     *          a <code>ByteBuffer</code> containing inbound network data.
+     * @param   dst
+     *          a <code>ByteBuffer</code> to hold inbound application data.
+     * @return  an <code>SSLEngineResult</code> describing the result
+     *          of this operation.
+     * @throws  SSLException
+     *          A problem was encountered while processing the
+     *          data that caused the <code>SSLEngine</code> to abort.
+     *          See the class description for more information on
+     *          engine closure.
+     * @throws  ReadOnlyBufferException
+     *          if the <code>dst</code> buffer is read-only.
+     * @throws  IllegalArgumentException
+     *          if either <code>src</code> or <code>dst</code>
+     *          is null.
+     * @throws  IllegalStateException if the client/server mode
+     *          has not yet been set.
+     * @see     #unwrap(ByteBuffer, ByteBuffer [], int, int)
+     */
+    public SSLEngineResult unwrap(ByteBuffer src,
+            ByteBuffer dst) throws SSLException {
+        return unwrap(src, new ByteBuffer [] { dst }, 0, 1);
+    }
+
+    /**
+     * Attempts to decode SSL/TLS network data into a sequence of plaintext
+     * application data buffers.
+     * <P>
+     * An invocation of this method behaves in exactly the same manner
+     * as the invocation:
+     * <blockquote><pre>
+     * {@link #unwrap(ByteBuffer, ByteBuffer [], int, int)
+     *     engine.unwrap(src, dsts, 0, dsts.length);}
+     * </pre></blockquote>
+     *
+     * @param   src
+     *          a <code>ByteBuffer</code> containing inbound network data.
+     * @param   dsts
+     *          an array of <code>ByteBuffer</code>s to hold inbound
+     *          application data.
+     * @return  an <code>SSLEngineResult</code> describing the result
+     *          of this operation.
+     * @throws  SSLException
+     *          A problem was encountered while processing the
+     *          data that caused the <code>SSLEngine</code> to abort.
+     *          See the class description for more information on
+     *          engine closure.
+     * @throws  ReadOnlyBufferException
+     *          if any of the <code>dst</code> buffers are read-only.
+     * @throws  IllegalArgumentException
+     *          if either <code>src</code> or <code>dsts</code>
+     *          is null, or if any element in <code>dsts</code> is null.
+     * @throws  IllegalStateException if the client/server mode
+     *          has not yet been set.
+     * @see     #unwrap(ByteBuffer, ByteBuffer [], int, int)
+     */
+    public SSLEngineResult unwrap(ByteBuffer src,
+            ByteBuffer [] dsts) throws SSLException {
+        if (dsts == null) {
+            throw new IllegalArgumentException("dsts == null");
+        }
+        return unwrap(src, dsts, 0, dsts.length);
+    }
+
+    /**
+     * Attempts to decode SSL/TLS network data into a subsequence of
+     * plaintext application data buffers.  This <i>"scattering"</i>
+     * operation decodes, in a single invocation, a sequence of bytes
+     * into one or more of a given sequence of buffers.  Scattering
+     * unwraps 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.  See
+     * {@link java.nio.channels.ScatteringByteChannel} for more
+     * information on scattering, and {@link
+     * java.nio.channels.ScatteringByteChannel#read(ByteBuffer[],
+     * int, int)} for more information on the subsequence
+     * behavior.
+     * <P>
+     * Depending on the state of the SSLEngine, this method may consume
+     * network data without producing any application data (for example,
+     * it may consume handshake data.)
+     * <P>
+     * The application is responsible for reliably obtaining the network
+     * data from the peer, and for invoking unwrap() on the data in the
+     * order it was received.  The application must properly synchronize
+     * multiple calls to this method.
+     * <P>
+     * If this <code>SSLEngine</code> has not yet started its initial
+     * handshake, this method will automatically start the handshake.
+     * <P>
+     * This method will attempt to consume one complete SSL/TLS network
+     * packet, but will never consume more than the sum of the bytes
+     * remaining in the buffers.  Each <code>ByteBuffer</code>'s
+     * position is updated to reflect the amount of data consumed or
+     * produced.  The limits remain the same.
+     * <P>
+     * The underlying memory used by the <code>src</code> and
+     * <code>dsts ByteBuffer</code>s must not be the same.
+     * <P>
+     * The inbound network buffer may be modified as a result of this
+     * call:  therefore if the network data packet is required for some
+     * secondary purpose, the data should be duplicated before calling this
+     * method.  Note:  the network data will not be useful to a second
+     * SSLEngine, as each SSLEngine contains unique random state which
+     * influences the SSL/TLS messages.
+     * <P>
+     * See the class description for more information on engine closure.
+     *
+     * @param   src
+     *          a <code>ByteBuffer</code> containing inbound network data.
+     * @param   dsts
+     *          an array of <code>ByteBuffer</code>s to hold inbound
+     *          application data.
+     * @param   offset
+     *          The offset within the buffer array of the first buffer from
+     *          which bytes are to be transferred; it must be non-negative
+     *          and no larger than <code>dsts.length</code>.
+     * @param   length
+     *          The maximum number of buffers to be accessed; it must be
+     *          non-negative and no larger than
+     *          <code>dsts.length</code>&nbsp;-&nbsp;<code>offset</code>.
+     * @return  an <code>SSLEngineResult</code> describing the result
+     *          of this operation.
+     * @throws  SSLException
+     *          A problem was encountered while processing the
+     *          data that caused the <code>SSLEngine</code> to abort.
+     *          See the class description for more information on
+     *          engine closure.
+     * @throws  IndexOutOfBoundsException
+     *          If the preconditions on the <code>offset</code> and
+     *          <code>length</code> parameters do not hold.
+     * @throws  ReadOnlyBufferException
+     *          if any of the <code>dst</code> buffers are read-only.
+     * @throws  IllegalArgumentException
+     *          if either <code>src</code> or <code>dsts</code>
+     *          is null, or if any element in the <code>dsts</code>
+     *          subsequence specified is null.
+     * @throws  IllegalStateException if the client/server mode
+     *          has not yet been set.
+     * @see     java.nio.channels.ScatteringByteChannel
+     * @see     java.nio.channels.ScatteringByteChannel#read(
+     *              ByteBuffer[], int, int)
+     */
+    public abstract SSLEngineResult unwrap(ByteBuffer src,
+            ByteBuffer [] dsts, int offset, int length) throws SSLException;
+
+
+    /**
+     * Returns a delegated <code>Runnable</code> task for
+     * this <code>SSLEngine</code>.
+     * <P>
+     * <code>SSLEngine</code> operations may require the results of
+     * operations that block, or may take an extended period of time to
+     * complete.  This method is used to obtain an outstanding {@link
+     * java.lang.Runnable} operation (task).  Each task must be assigned
+     * a thread (possibly the current) to perform the {@link
+     * java.lang.Runnable#run() run} operation.  Once the
+     * <code>run</code> method returns, the <code>Runnable</code> object
+     * is no longer needed and may be discarded.
+     * <P>
+     * Delegated tasks run in the <code>AccessControlContext</code>
+     * in place when this object was created.
+     * <P>
+     * A call to this method will return each outstanding task
+     * exactly once.
+     * <P>
+     * Multiple delegated tasks can be run in parallel.
+     *
+     * @return  a delegated <code>Runnable</code> task, or null
+     *          if none are available.
+     */
+    public abstract Runnable getDelegatedTask();
+
+
+    /**
+     * Signals that no more inbound network data will be sent
+     * to this <code>SSLEngine</code>.
+     * <P>
+     * If the application initiated the closing process by calling
+     * {@link #closeOutbound()}, under some circumstances it is not
+     * required that the initiator wait for the peer's corresponding
+     * close message.  (See section 7.2.1 of the TLS specification (<A
+     * HREF="http://www.ietf.org/rfc/rfc2246.txt">RFC 2246</A>) for more
+     * information on waiting for closure alerts.)  In such cases, this
+     * method need not be called.
+     * <P>
+     * But if the application did not initiate the closure process, or
+     * if the circumstances above do not apply, this method should be
+     * called whenever the end of the SSL/TLS data stream is reached.
+     * This ensures closure of the inbound side, and checks that the
+     * peer followed the SSL/TLS close procedure properly, thus
+     * detecting possible truncation attacks.
+     * <P>
+     * This method is idempotent:  if the inbound side has already
+     * been closed, this method does not do anything.
+     * <P>
+     * {@link #wrap(ByteBuffer, ByteBuffer) wrap()} should be
+     * called to flush any remaining handshake data.
+     *
+     * @throws  SSLException
+     *          if this engine has not received the proper SSL/TLS close
+     *          notification message from the peer.
+     *
+     * @see     #isInboundDone()
+     * @see     #isOutboundDone()
+     */
+    public abstract void closeInbound() throws SSLException;
+
+
+    /**
+     * Returns whether {@link #unwrap(ByteBuffer, ByteBuffer)} will
+     * accept any more inbound data messages.
+     *
+     * @return  true if the <code>SSLEngine</code> will not
+     *          consume anymore network data (and by implication,
+     *          will not produce any more application data.)
+     * @see     #closeInbound()
+     */
+    public abstract boolean isInboundDone();
+
+
+    /**
+     * Signals that no more outbound application data will be sent
+     * on this <code>SSLEngine</code>.
+     * <P>
+     * This method is idempotent:  if the outbound side has already
+     * been closed, this method does not do anything.
+     * <P>
+     * {@link #wrap(ByteBuffer, ByteBuffer)} should be
+     * called to flush any remaining handshake data.
+     *
+     * @see     #isOutboundDone()
+     */
+    public abstract void closeOutbound();
+
+
+    /**
+     * Returns whether {@link #wrap(ByteBuffer, ByteBuffer)} will
+     * produce any more outbound data messages.
+     * <P>
+     * Note that during the closure phase, a <code>SSLEngine</code> may
+     * generate handshake closure data that must be sent to the peer.
+     * <code>wrap()</code> must be called to generate this data.  When
+     * this method returns true, no more outbound data will be created.
+     *
+     * @return  true if the <code>SSLEngine</code> will not produce
+     *          any more network data
+     *
+     * @see     #closeOutbound()
+     * @see     #closeInbound()
+     */
+    public abstract boolean isOutboundDone();
+
+
+    // Android-changed: Added warnings about misuse
+    /**
+     * Returns the names of the cipher suites which could be enabled for use
+     * on this engine.  Normally, only a subset of these will actually
+     * be enabled by default, since this list may include cipher suites which
+     * do not meet quality of service requirements for those defaults.  Such
+     * cipher suites might be useful in specialized applications.
+     *
+     * <p class="caution">Applications should not blindly enable all supported
+     * cipher suites.  The supported cipher suites can include signaling cipher suite
+     * values that can cause connection problems if enabled inappropriately.
+     *
+     * <p>The proper way to use this method is to either check if a specific cipher
+     * suite is supported via {@code Arrays.asList(getSupportedCipherSuites()).contains(...)}
+     * or to filter a desired list of cipher suites to only the supported ones via
+     * {@code desiredSuiteSet.retainAll(Arrays.asList(getSupportedCipherSuites()))}.
+     *
+     * @return  an array of cipher suite names
+     * @see     #getEnabledCipherSuites()
+     * @see     #setEnabledCipherSuites(String [])
+     */
+    public abstract String [] getSupportedCipherSuites();
+
+
+    /**
+     * Returns the names of the SSL cipher suites which are currently
+     * enabled for use on this engine.  When an SSLEngine is first
+     * created, all enabled cipher suites support a minimum quality of
+     * service.  Thus, in some environments this value might be empty.
+     * <P>
+     * Even if a suite has been enabled, it might never be used.  (For
+     * example, the peer does not support it, the requisite
+     * certificates/private keys for the suite are not available, or an
+     * anonymous suite is enabled but authentication is required.)
+     *
+     * @return  an array of cipher suite names
+     * @see     #getSupportedCipherSuites()
+     * @see     #setEnabledCipherSuites(String [])
+     */
+    public abstract String [] getEnabledCipherSuites();
+
+
+    /**
+     * Sets the cipher suites enabled for use on this engine.
+     * <P>
+     * Each cipher suite in the <code>suites</code> parameter must have
+     * been listed by getSupportedCipherSuites(), or the method will
+     * fail.  Following a successful call to this method, only suites
+     * listed in the <code>suites</code> parameter are enabled for use.
+     * <P>
+     * See {@link #getEnabledCipherSuites()} for more information
+     * on why a specific cipher suite may never be used on a engine.
+     *
+     * @param   suites Names of all the cipher suites to enable
+     * @throws  IllegalArgumentException when one or more of the ciphers
+     *          named by the parameter is not supported, or when the
+     *          parameter is null.
+     * @see     #getSupportedCipherSuites()
+     * @see     #getEnabledCipherSuites()
+     */
+    public abstract void setEnabledCipherSuites(String suites []);
+
+
+    /**
+     * Returns the names of the protocols which could be enabled for use
+     * with this <code>SSLEngine</code>.
+     *
+     * @return  an array of protocols supported
+     */
+    public abstract String [] getSupportedProtocols();
+
+
+    /**
+     * Returns the names of the protocol versions which are currently
+     * enabled for use with this <code>SSLEngine</code>.
+     *
+     * @return  an array of protocols
+     * @see     #setEnabledProtocols(String [])
+     */
+    public abstract String [] getEnabledProtocols();
+
+
+    // Android-added: Added paragraph about contiguous protocols.
+    /**
+     * Set the protocol versions enabled for use on this engine.
+     * <P>
+     * The protocols must have been listed by getSupportedProtocols()
+     * as being supported.  Following a successful call to this method,
+     * only protocols listed in the <code>protocols</code> parameter
+     * are enabled for use.
+     * <p>
+     * Because of the way the protocol version is negotiated, connections
+     * will only be able to use a member of the lowest set of contiguous
+     * enabled protocol versions.  For example, enabling TLSv1.2 and TLSv1
+     * will result in connections only being able to use TLSv1.
+     *
+     * @param   protocols Names of all the protocols to enable.
+     * @throws  IllegalArgumentException when one or more of
+     *          the protocols named by the parameter is not supported or
+     *          when the protocols parameter is null.
+     * @see     #getEnabledProtocols()
+     */
+    public abstract void setEnabledProtocols(String protocols[]);
+
+
+    /**
+     * Returns the <code>SSLSession</code> in use in this
+     * <code>SSLEngine</code>.
+     * <P>
+     * These can be long lived, and frequently correspond to an entire
+     * login session for some user.  The session specifies a particular
+     * cipher suite which is being actively used by all connections in
+     * that session, as well as the identities of the session's client
+     * and server.
+     * <P>
+     * Unlike {@link SSLSocket#getSession()}
+     * this method does not block until handshaking is complete.
+     * <P>
+     * Until the initial handshake has completed, this method returns
+     * a session object which reports an invalid cipher suite of
+     * "SSL_NULL_WITH_NULL_NULL".
+     *
+     * @return  the <code>SSLSession</code> for this <code>SSLEngine</code>
+     * @see     SSLSession
+     */
+    public abstract SSLSession getSession();
+
+
+    /**
+     * Returns the {@code SSLSession} being constructed during a SSL/TLS
+     * handshake.
+     * <p>
+     * TLS protocols may negotiate parameters that are needed when using
+     * an instance of this class, but before the {@code SSLSession} has
+     * been completely initialized and made available via {@code getSession}.
+     * For example, the list of valid signature algorithms may restrict
+     * the type of certificates that can used during TrustManager
+     * decisions, or the maximum TLS fragment packet sizes can be
+     * resized to better support the network environment.
+     * <p>
+     * This method provides early access to the {@code SSLSession} being
+     * constructed.  Depending on how far the handshake has progressed,
+     * some data may not yet be available for use.  For example, if a
+     * remote server will be sending a Certificate chain, but that chain
+     * has yet not been processed, the {@code getPeerCertificates}
+     * method of {@code SSLSession} will throw a
+     * SSLPeerUnverifiedException.  Once that chain has been processed,
+     * {@code getPeerCertificates} will return the proper value.
+     *
+     * @see SSLSocket
+     * @see SSLSession
+     * @see ExtendedSSLSession
+     * @see X509ExtendedKeyManager
+     * @see X509ExtendedTrustManager
+     *
+     * @return null if this instance is not currently handshaking, or
+     *         if the current handshake has not progressed far enough to
+     *         create a basic SSLSession.  Otherwise, this method returns the
+     *         {@code SSLSession} currently being negotiated.
+     * @throws UnsupportedOperationException if the underlying provider
+     *         does not implement the operation.
+     *
+     * @since 1.7
+     */
+    public SSLSession getHandshakeSession() {
+        throw new UnsupportedOperationException();
+    }
+
+
+    /**
+     * Initiates handshaking (initial or renegotiation) on this SSLEngine.
+     * <P>
+     * This method is not needed for the initial handshake, as the
+     * <code>wrap()</code> and <code>unwrap()</code> methods will
+     * implicitly call this method if handshaking has not already begun.
+     * <P>
+     * Note that the peer may also request a session renegotiation with
+     * this <code>SSLEngine</code> by sending the appropriate
+     * session renegotiate handshake message.
+     * <P>
+     * Unlike the {@link SSLSocket#startHandshake()
+     * SSLSocket#startHandshake()} method, this method does not block
+     * until handshaking is completed.
+     * <P>
+     * To force a complete SSL/TLS session renegotiation, the current
+     * session should be invalidated prior to calling this method.
+     * <P>
+     * Some protocols may not support multiple handshakes on an existing
+     * engine and may throw an <code>SSLException</code>.
+     *
+     * @throws  SSLException
+     *          if a problem was encountered while signaling the
+     *          <code>SSLEngine</code> to begin a new handshake.
+     *          See the class description for more information on
+     *          engine closure.
+     * @throws  IllegalStateException if the client/server mode
+     *          has not yet been set.
+     * @see     SSLSession#invalidate()
+     */
+    public abstract void beginHandshake() throws SSLException;
+
+
+    /**
+     * Returns the current handshake status for this <code>SSLEngine</code>.
+     *
+     * @return  the current <code>SSLEngineResult.HandshakeStatus</code>.
+     */
+    public abstract SSLEngineResult.HandshakeStatus getHandshakeStatus();
+
+
+    /**
+     * Configures the engine to use client (or server) mode when
+     * handshaking.
+     * <P>
+     * This method must be called before any handshaking occurs.
+     * Once handshaking has begun, the mode can not be reset for the
+     * life of this engine.
+     * <P>
+     * Servers normally authenticate themselves, and clients
+     * are not required to do so.
+     *
+     * @param   mode true if the engine should start its handshaking
+     *          in "client" mode
+     * @throws  IllegalArgumentException if a mode change is attempted
+     *          after the initial handshake has begun.
+     * @see     #getUseClientMode()
+     */
+    public abstract void setUseClientMode(boolean mode);
+
+
+    /**
+     * Returns true if the engine is set to use client mode when
+     * handshaking.
+     *
+     * @return  true if the engine should do handshaking
+     *          in "client" mode
+     * @see     #setUseClientMode(boolean)
+     */
+    public abstract boolean getUseClientMode();
+
+
+    /**
+     * Configures the engine to <i>require</i> client authentication.  This
+     * option is only useful for engines in the server mode.
+     * <P>
+     * An engine's client authentication setting is one of the following:
+     * <ul>
+     * <li> client authentication required
+     * <li> client authentication requested
+     * <li> no client authentication desired
+     * </ul>
+     * <P>
+     * Unlike {@link #setWantClientAuth(boolean)}, if this option is set and
+     * the client chooses not to provide authentication information
+     * about itself, <i>the negotiations will stop and the engine will
+     * begin its closure procedure</i>.
+     * <P>
+     * Calling this method overrides any previous setting made by
+     * this method or {@link #setWantClientAuth(boolean)}.
+     *
+     * @param   need set to true if client authentication is required,
+     *          or false if no client authentication is desired.
+     * @see     #getNeedClientAuth()
+     * @see     #setWantClientAuth(boolean)
+     * @see     #getWantClientAuth()
+     * @see     #setUseClientMode(boolean)
+     */
+    public abstract void setNeedClientAuth(boolean need);
+
+
+    /**
+     * Returns true if the engine will <i>require</i> client authentication.
+     * This option is only useful to engines in the server mode.
+     *
+     * @return  true if client authentication is required,
+     *          or false if no client authentication is desired.
+     * @see     #setNeedClientAuth(boolean)
+     * @see     #setWantClientAuth(boolean)
+     * @see     #getWantClientAuth()
+     * @see     #setUseClientMode(boolean)
+     */
+    public abstract boolean getNeedClientAuth();
+
+
+    /**
+     * Configures the engine to <i>request</i> client authentication.
+     * This option is only useful for engines in the server mode.
+     * <P>
+     * An engine's client authentication setting is one of the following:
+     * <ul>
+     * <li> client authentication required
+     * <li> client authentication requested
+     * <li> no client authentication desired
+     * </ul>
+     * <P>
+     * Unlike {@link #setNeedClientAuth(boolean)}, if this option is set and
+     * the client chooses not to provide authentication information
+     * about itself, <i>the negotiations will continue</i>.
+     * <P>
+     * Calling this method overrides any previous setting made by
+     * this method or {@link #setNeedClientAuth(boolean)}.
+     *
+     * @param   want set to true if client authentication is requested,
+     *          or false if no client authentication is desired.
+     * @see     #getWantClientAuth()
+     * @see     #setNeedClientAuth(boolean)
+     * @see     #getNeedClientAuth()
+     * @see     #setUseClientMode(boolean)
+     */
+    public abstract void setWantClientAuth(boolean want);
+
+
+    /**
+     * Returns true if the engine will <i>request</i> client authentication.
+     * This option is only useful for engines in the server mode.
+     *
+     * @return  true if client authentication is requested,
+     *          or false if no client authentication is desired.
+     * @see     #setNeedClientAuth(boolean)
+     * @see     #getNeedClientAuth()
+     * @see     #setWantClientAuth(boolean)
+     * @see     #setUseClientMode(boolean)
+     */
+    public abstract boolean getWantClientAuth();
+
+
+    /**
+     * Controls whether new SSL sessions may be established by this engine.
+     * If session creations are not allowed, and there are no
+     * existing sessions to resume, there will be no successful
+     * handshaking.
+     *
+     * @param   flag true indicates that sessions may be created; this
+     *          is the default.  false indicates that an existing session
+     *          must be resumed
+     * @see     #getEnableSessionCreation()
+     */
+    public abstract void setEnableSessionCreation(boolean flag);
+
+
+    /**
+     * Returns true if new SSL sessions may be established by this engine.
+     *
+     * @return  true indicates that sessions may be created; this
+     *          is the default.  false indicates that an existing session
+     *          must be resumed
+     * @see     #setEnableSessionCreation(boolean)
+     */
+    public abstract boolean getEnableSessionCreation();
+
+    /**
+     * Returns the SSLParameters in effect for this SSLEngine.
+     * The ciphersuites and protocols of the returned SSLParameters
+     * are always non-null.
+     *
+     * @return the SSLParameters in effect for this SSLEngine.
+     * @since 1.6
+     */
+    public SSLParameters getSSLParameters() {
+        SSLParameters params = new SSLParameters();
+        params.setCipherSuites(getEnabledCipherSuites());
+        params.setProtocols(getEnabledProtocols());
+        if (getNeedClientAuth()) {
+            params.setNeedClientAuth(true);
+        } else if (getWantClientAuth()) {
+            params.setWantClientAuth(true);
+        }
+        return params;
+    }
+
+    /**
+     * Applies SSLParameters to this engine.
+     *
+     * <p>This means:
+     * <ul>
+     * <li>If {@code params.getCipherSuites()} is non-null,
+     *   {@code setEnabledCipherSuites()} is called with that value.</li>
+     * <li>If {@code params.getProtocols()} is non-null,
+     *   {@code setEnabledProtocols()} is called with that value.</li>
+     * <li>If {@code params.getNeedClientAuth()} or
+     *   {@code params.getWantClientAuth()} return {@code true},
+     *   {@code setNeedClientAuth(true)} and
+     *   {@code setWantClientAuth(true)} are called, respectively;
+     *   otherwise {@code setWantClientAuth(false)} is called.</li>
+     * <li>If {@code params.getServerNames()} is non-null, the engine will
+     *   configure its server names with that value.</li>
+     * <li>If {@code params.getSNIMatchers()} is non-null, the engine will
+     *   configure its SNI matchers with that value.</li>
+     * </ul>
+     *
+     * @param params the parameters
+     * @throws IllegalArgumentException if the setEnabledCipherSuites() or
+     *    the setEnabledProtocols() call fails
+     * @since 1.6
+     */
+    public void setSSLParameters(SSLParameters params) {
+        String[] s;
+        s = params.getCipherSuites();
+        if (s != null) {
+            setEnabledCipherSuites(s);
+        }
+        s = params.getProtocols();
+        if (s != null) {
+            setEnabledProtocols(s);
+        }
+        if (params.getNeedClientAuth()) {
+            setNeedClientAuth(true);
+        } else if (params.getWantClientAuth()) {
+            setWantClientAuth(true);
+        } else {
+            setWantClientAuth(false);
+        }
+    }
+
+    // BEGIN Android-added: Integrate ALPN-related methods from OpenJDK 9+181
+    // Also removed references to DTLS in documentation; Android doesn't support DTLS.
+    /**
+     * Returns the most recent application protocol value negotiated for this
+     * connection.
+     * <p>
+     * If supported by the underlying SSL/TLS implementation,
+     * application name negotiation mechanisms such as <a
+     * href="http://www.ietf.org/rfc/rfc7301.txt"> RFC 7301 </a>, the
+     * Application-Layer Protocol Negotiation (ALPN), can negotiate
+     * application-level values between peers.
+     * <p>
+     * @implSpec
+     * The implementation in this class throws
+     * {@code UnsupportedOperationException} and performs no other action.
+     *
+     * @return null if it has not yet been determined if application
+     *         protocols might be used for this connection, an empty
+     *         {@code String} if application protocols values will not
+     *         be used, or a non-empty application protocol {@code String}
+     *         if a value was successfully negotiated.
+     * @throws UnsupportedOperationException if the underlying provider
+     *         does not implement the operation.
+     * @since 9
+     */
+    public String getApplicationProtocol() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Returns the application protocol value negotiated on a SSL/TLS
+     * handshake currently in progress.
+     * <p>
+     * Like {@link #getHandshakeSession()},
+     * a connection may be in the middle of a handshake. The
+     * application protocol may or may not yet be available.
+     * <p>
+     * @implSpec
+     * The implementation in this class throws
+     * {@code UnsupportedOperationException} and performs no other action.
+     *
+     * @return null if it has not yet been determined if application
+     *         protocols might be used for this handshake, an empty
+     *         {@code String} if application protocols values will not
+     *         be used, or a non-empty application protocol {@code String}
+     *         if a value was successfully negotiated.
+     * @throws UnsupportedOperationException if the underlying provider
+     *         does not implement the operation.
+     * @since 9
+     */
+    public String getHandshakeApplicationProtocol() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Registers a callback function that selects an application protocol
+     * value for a SSL/TLS handshake.
+     * The function overrides any values supplied using
+     * {@link SSLParameters#setApplicationProtocols
+     * SSLParameters.setApplicationProtocols} and it supports the following
+     * type parameters:
+     * <blockquote>
+     * <dl>
+     * <dt> {@code SSLEngine}
+     * <dd> The function's first argument allows the current {@code SSLEngine}
+     *      to be inspected, including the handshake session and configuration
+     *      settings.
+     * <dt> {@code List<String>}
+     * <dd> The function's second argument lists the application protocol names
+     *      advertised by the TLS peer.
+     * <dt> {@code String}
+     * <dd> The function's result is an application protocol name, or null to
+     *      indicate that none of the advertised names are acceptable.
+     *      If the return value is an empty {@code String} then application
+     *      protocol indications will not be used.
+     *      If the return value is null (no value chosen) or is a value that
+     *      was not advertised by the peer, the underlying protocol will
+     *      determine what action to take. (For example, ALPN will send a
+     *      "no_application_protocol" alert and terminate the connection.)
+     * </dl>
+     * </blockquote>
+     *
+     * For example, the following call registers a callback function that
+     * examines the TLS handshake parameters and selects an application protocol
+     * name:
+     * <pre>{@code
+     *     serverEngine.setHandshakeApplicationProtocolSelector(
+     *         (serverEngine, clientProtocols) -> {
+     *             SSLSession session = serverEngine.getHandshakeSession();
+     *             return chooseApplicationProtocol(
+     *                 serverEngine,
+     *                 clientProtocols,
+     *                 session.getProtocol(),
+     *                 session.getCipherSuite());
+     *         });
+     * }</pre>
+     *
+     * @apiNote
+     * This method should be called by TLS server applications before the TLS
+     * handshake begins. Also, this {@code SSLEngine} should be configured with
+     * parameters that are compatible with the application protocol selected by
+     * the callback function. For example, enabling a poor choice of cipher
+     * suites could result in no suitable application protocol.
+     * See {@link SSLParameters}.
+     *
+     * @implSpec
+     * The implementation in this class throws
+     * {@code UnsupportedOperationException} and performs no other action.
+     *
+     * @param selector the callback function, or null to disable the callback
+     *         functionality.
+     * @throws UnsupportedOperationException if the underlying provider
+     *         does not implement the operation.
+     * @since 9
+     */
+    public void setHandshakeApplicationProtocolSelector(
+            BiFunction<SSLEngine, List<String>, String> selector) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Retrieves the callback function that selects an application protocol
+     * value during a SSL/TLS handshake.
+     * See {@link #setHandshakeApplicationProtocolSelector
+     * setHandshakeApplicationProtocolSelector}
+     * for the function's type parameters.
+     *
+     * @implSpec
+     * The implementation in this class throws
+     * {@code UnsupportedOperationException} and performs no other action.
+     *
+     * @return the callback function, or null if none has been set.
+     * @throws UnsupportedOperationException if the underlying provider
+     *         does not implement the operation.
+     * @since 9
+     */
+    public BiFunction<SSLEngine, List<String>, String>
+            getHandshakeApplicationProtocolSelector() {
+        throw new UnsupportedOperationException();
+    }
+    // END Android-added: Integrate ALPN-related methods from OpenJDK 9+181
+}
diff --git a/javax/net/ssl/SSLEngineResult.java b/javax/net/ssl/SSLEngineResult.java
new file mode 100644
index 0000000..af42f2b
--- /dev/null
+++ b/javax/net/ssl/SSLEngineResult.java
@@ -0,0 +1,240 @@
+/*
+ * 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 javax.net.ssl;
+
+/**
+ * An encapsulation of the result state produced by
+ * <code>SSLEngine</code> I/O calls.
+ *
+ * <p> A <code>SSLEngine</code> provides a means for establishing
+ * secure communication sessions between two peers.  <code>SSLEngine</code>
+ * operations typically consume bytes from an input buffer and produce
+ * bytes in an output buffer.  This class provides operational result
+ * values describing the state of the <code>SSLEngine</code>, including
+ * indications of what operations are needed to finish an
+ * ongoing handshake.  Lastly, it reports the number of bytes consumed
+ * and produced as a result of this operation.
+ *
+ * @see SSLEngine
+ * @see SSLEngine#wrap(ByteBuffer, ByteBuffer)
+ * @see SSLEngine#unwrap(ByteBuffer, ByteBuffer)
+ *
+ * @author Brad R. Wetmore
+ * @since 1.5
+ */
+
+public class SSLEngineResult {
+
+    /**
+     * An <code>SSLEngineResult</code> enum describing the overall result
+     * of the <code>SSLEngine</code> operation.
+     *
+     * The <code>Status</code> value does not reflect the
+     * state of a <code>SSLEngine</code> handshake currently
+     * in progress.  The <code>SSLEngineResult's HandshakeStatus</code>
+     * should be consulted for that information.
+     *
+     * @author Brad R. Wetmore
+     * @since 1.5
+     */
+    public static enum Status {
+
+        /**
+         * The <code>SSLEngine</code> was not able to unwrap the
+         * incoming data because there were not enough source bytes
+         * available to make a complete packet.
+         *
+         * <P>
+         * Repeat the call once more bytes are available.
+         */
+        BUFFER_UNDERFLOW,
+
+        /**
+         * The <code>SSLEngine</code> was not able to process the
+         * operation because there are not enough bytes available in the
+         * destination buffer to hold the result.
+         * <P>
+         * Repeat the call once more bytes are available.
+         *
+         * @see SSLSession#getPacketBufferSize()
+         * @see SSLSession#getApplicationBufferSize()
+         */
+        BUFFER_OVERFLOW,
+
+        /**
+         * The <code>SSLEngine</code> completed the operation, and
+         * is available to process similar calls.
+         */
+        OK,
+
+        /**
+         * The operation just closed this side of the
+         * <code>SSLEngine</code>, or the operation
+         * could not be completed because it was already closed.
+         */
+        CLOSED;
+    }
+
+    /**
+     * An <code>SSLEngineResult</code> enum describing the current
+     * handshaking state of this <code>SSLEngine</code>.
+     *
+     * @author Brad R. Wetmore
+     * @since 1.5
+     */
+    public static enum HandshakeStatus {
+
+        /**
+         * The <code>SSLEngine</code> is not currently handshaking.
+         */
+        NOT_HANDSHAKING,
+
+        /**
+         * The <code>SSLEngine</code> has just finished handshaking.
+         * <P>
+         * This value is only generated by a call to
+         * <code>SSLEngine.wrap()/unwrap()</code> when that call
+         * finishes a handshake.  It is never generated by
+         * <code>SSLEngine.getHandshakeStatus()</code>.
+         *
+         * @see SSLEngine#wrap(ByteBuffer, ByteBuffer)
+         * @see SSLEngine#unwrap(ByteBuffer, ByteBuffer)
+         * @see SSLEngine#getHandshakeStatus()
+         */
+        FINISHED,
+
+        /**
+         * The <code>SSLEngine</code> needs the results of one (or more)
+         * delegated tasks before handshaking can continue.
+         *
+         * @see SSLEngine#getDelegatedTask()
+         */
+        NEED_TASK,
+
+        /**
+         * The <code>SSLEngine</code> must send data to the remote side
+         * before handshaking can continue, so <code>SSLEngine.wrap()</code>
+         * should be called.
+         *
+         * @see SSLEngine#wrap(ByteBuffer, ByteBuffer)
+         */
+        NEED_WRAP,
+
+        /**
+         * The <code>SSLEngine</code> needs to receive data from the
+         * remote side before handshaking can continue.
+         */
+        NEED_UNWRAP;
+    }
+
+
+    private final Status status;
+    private final HandshakeStatus handshakeStatus;
+    private final int bytesConsumed;
+    private final int bytesProduced;
+
+    /**
+     * Initializes a new instance of this class.
+     *
+     * @param   status
+     *          the return value of the operation.
+     *
+     * @param   handshakeStatus
+     *          the current handshaking status.
+     *
+     * @param   bytesConsumed
+     *          the number of bytes consumed from the source ByteBuffer
+     *
+     * @param   bytesProduced
+     *          the number of bytes placed into the destination ByteBuffer
+     *
+     * @throws  IllegalArgumentException
+     *          if the <code>status</code> or <code>handshakeStatus</code>
+     *          arguments are null, or if <code>bytesConsumed</code> or
+     *          <code>bytesProduced</code> is negative.
+     */
+    public SSLEngineResult(Status status, HandshakeStatus handshakeStatus,
+            int bytesConsumed, int bytesProduced) {
+
+        if ((status == null) || (handshakeStatus == null) ||
+                (bytesConsumed < 0) || (bytesProduced < 0)) {
+            throw new IllegalArgumentException("Invalid Parameter(s)");
+        }
+
+        this.status = status;
+        this.handshakeStatus = handshakeStatus;
+        this.bytesConsumed = bytesConsumed;
+        this.bytesProduced = bytesProduced;
+    }
+
+    /**
+     * Gets the return value of this <code>SSLEngine</code> operation.
+     *
+     * @return  the return value
+     */
+    final public Status getStatus() {
+        return status;
+    }
+
+    /**
+     * Gets the handshake status of this <code>SSLEngine</code>
+     * operation.
+     *
+     * @return  the handshake status
+     */
+    final public HandshakeStatus getHandshakeStatus() {
+        return handshakeStatus;
+    }
+
+    /**
+     * Returns the number of bytes consumed from the input buffer.
+     *
+     * @return  the number of bytes consumed.
+     */
+    final public int bytesConsumed() {
+        return bytesConsumed;
+    }
+
+    /**
+     * Returns the number of bytes written to the output buffer.
+     *
+     * @return  the number of bytes produced
+     */
+    final public int bytesProduced() {
+        return bytesProduced;
+    }
+
+    /**
+     * Returns a String representation of this object.
+     */
+    @Override
+    public String toString() {
+        return ("Status = " + status +
+            " HandshakeStatus = " + handshakeStatus +
+            "\nbytesConsumed = " + bytesConsumed +
+            " bytesProduced = " + bytesProduced);
+    }
+}
diff --git a/javax/net/ssl/SSLException.java b/javax/net/ssl/SSLException.java
new file mode 100644
index 0000000..98d8bd3
--- /dev/null
+++ b/javax/net/ssl/SSLException.java
@@ -0,0 +1,88 @@
+/*
+ * 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 javax.net.ssl;
+
+import java.io.IOException;
+
+/**
+ * Indicates some kind of error detected by an SSL subsystem.
+ * This class is the general class of exceptions produced
+ * by failed SSL-related operations.
+ *
+ * @since 1.4
+ * @author David Brownell
+ */
+public
+class SSLException extends IOException
+{
+    private static final long serialVersionUID = 4511006460650708967L;
+
+    /**
+     * Constructs an exception reporting an error found by
+     * an SSL subsystem.
+     *
+     * @param reason describes the problem.
+     */
+    public SSLException(String reason)
+    {
+        super(reason);
+    }
+
+    /**
+     * Creates a <code>SSLException</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 SSLException(String message, Throwable cause) {
+        super(message);
+        initCause(cause);
+    }
+
+    /**
+     * Creates a <code>SSLException</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 SSLException(Throwable cause) {
+        super(cause == null ? null : cause.toString());
+        initCause(cause);
+    }
+}
diff --git a/javax/net/ssl/SSLHandshakeException.java b/javax/net/ssl/SSLHandshakeException.java
new file mode 100644
index 0000000..45d67a8
--- /dev/null
+++ b/javax/net/ssl/SSLHandshakeException.java
@@ -0,0 +1,52 @@
+/*
+ * 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 javax.net.ssl;
+
+
+/**
+ * Indicates that the client and server could not negotiate the
+ * desired level of security.  The connection is no longer usable.
+ *
+ * @since 1.4
+ * @author David Brownell
+ */
+public
+class SSLHandshakeException extends SSLException
+{
+    private static final long serialVersionUID = -5045881315018326890L;
+
+    /**
+     * Constructs an exception reporting an error found by
+     * an SSL subsystem during handshaking.
+     *
+     * @param reason describes the problem.
+     */
+    public SSLHandshakeException(String reason)
+    {
+        super(reason);
+    }
+}
diff --git a/javax/net/ssl/SSLKeyException.java b/javax/net/ssl/SSLKeyException.java
new file mode 100644
index 0000000..bba3f73
--- /dev/null
+++ b/javax/net/ssl/SSLKeyException.java
@@ -0,0 +1,51 @@
+/*
+ * 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 javax.net.ssl;
+
+/**
+ * Reports a bad SSL key.  Normally, this indicates misconfiguration
+ * of the server or client SSL certificate and private key.
+ *
+ * @since 1.4
+ * @author David Brownell
+ */
+public
+class SSLKeyException extends SSLException
+{
+    private static final long serialVersionUID = -8071664081941937874L;
+
+    /**
+     * Constructs an exception reporting a key management error
+     * found by an SSL subsystem.
+     *
+     * @param reason describes the problem.
+     */
+    public SSLKeyException(String reason)
+    {
+        super(reason);
+    }
+}
diff --git a/javax/net/ssl/SSLParameters.java b/javax/net/ssl/SSLParameters.java
new file mode 100644
index 0000000..1b9b3fb
--- /dev/null
+++ b/javax/net/ssl/SSLParameters.java
@@ -0,0 +1,542 @@
+/*
+ * Copyright (c) 2005, 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 javax.net.ssl;
+
+import java.security.AlgorithmConstraints;
+import java.util.Map;
+import java.util.List;
+import java.util.HashMap;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+
+/**
+ * Encapsulates parameters for an SSL/TLS connection. The parameters
+ * are the list of ciphersuites to be accepted in an SSL/TLS handshake,
+ * the list of protocols to be allowed, the endpoint identification
+ * algorithm during SSL/TLS handshaking, the Server Name Indication (SNI),
+ * the algorithm constraints and whether SSL/TLS servers should request
+ * or require client authentication, etc.
+ * <p>
+ * SSLParameters can be created via the constructors in this class.
+ * Objects can also be obtained using the <code>getSSLParameters()</code>
+ * methods in
+ * {@link SSLSocket#getSSLParameters SSLSocket} and
+ * {@link SSLServerSocket#getSSLParameters SSLServerSocket} and
+ * {@link SSLEngine#getSSLParameters SSLEngine} or the
+ * {@link SSLContext#getDefaultSSLParameters getDefaultSSLParameters()} and
+ * {@link SSLContext#getSupportedSSLParameters getSupportedSSLParameters()}
+ * methods in <code>SSLContext</code>.
+ * <p>
+ * SSLParameters can be applied to a connection via the methods
+ * {@link SSLSocket#setSSLParameters SSLSocket.setSSLParameters()} and
+ * {@link SSLServerSocket#setSSLParameters SSLServerSocket.setSSLParameters()}
+ * and {@link SSLEngine#setSSLParameters SSLEngine.setSSLParameters()}.
+ *
+ * @see SSLSocket
+ * @see SSLEngine
+ * @see SSLContext
+ *
+ * @since 1.6
+ */
+public class SSLParameters {
+
+    private String[] cipherSuites;
+    private String[] protocols;
+    private boolean wantClientAuth;
+    private boolean needClientAuth;
+    private String identificationAlgorithm;
+    private AlgorithmConstraints algorithmConstraints;
+    private Map<Integer, SNIServerName> sniNames = null;
+    private Map<Integer, SNIMatcher> sniMatchers = null;
+    private boolean preferLocalCipherSuites;
+    // Android-added: Integrate ALPN-related methods from OpenJDK 9+181
+    private String[] applicationProtocols = new String[0];
+
+    /**
+     * Constructs SSLParameters.
+     * <p>
+     * The values of cipherSuites, protocols, cryptographic algorithm
+     * constraints, endpoint identification algorithm, server names and
+     * server name matchers are set to <code>null</code>, useCipherSuitesOrder,
+     * wantClientAuth and needClientAuth are set to <code>false</code>.
+     */
+    public SSLParameters() {
+        // empty
+    }
+
+    /**
+     * Constructs SSLParameters from the specified array of ciphersuites.
+     * <p>
+     * Calling this constructor is equivalent to calling the no-args
+     * constructor followed by
+     * <code>setCipherSuites(cipherSuites);</code>.
+     *
+     * @param cipherSuites the array of ciphersuites (or null)
+     */
+    public SSLParameters(String[] cipherSuites) {
+        setCipherSuites(cipherSuites);
+    }
+
+    /**
+     * Constructs SSLParameters from the specified array of ciphersuites
+     * and protocols.
+     * <p>
+     * Calling this constructor is equivalent to calling the no-args
+     * constructor followed by
+     * <code>setCipherSuites(cipherSuites); setProtocols(protocols);</code>.
+     *
+     * @param cipherSuites the array of ciphersuites (or null)
+     * @param protocols the array of protocols (or null)
+     */
+    public SSLParameters(String[] cipherSuites, String[] protocols) {
+        setCipherSuites(cipherSuites);
+        setProtocols(protocols);
+    }
+
+    private static String[] clone(String[] s) {
+        return (s == null) ? null : s.clone();
+    }
+
+    /**
+     * Returns a copy of the array of ciphersuites or null if none
+     * have been set.
+     *
+     * @return a copy of the array of ciphersuites or null if none
+     * have been set.
+     */
+    public String[] getCipherSuites() {
+        return clone(cipherSuites);
+    }
+
+    /**
+     * Sets the array of ciphersuites.
+     *
+     * @param cipherSuites the array of ciphersuites (or null)
+     */
+    public void setCipherSuites(String[] cipherSuites) {
+        this.cipherSuites = clone(cipherSuites);
+    }
+
+    /**
+     * Returns a copy of the array of protocols or null if none
+     * have been set.
+     *
+     * @return a copy of the array of protocols or null if none
+     * have been set.
+     */
+    public String[] getProtocols() {
+        return clone(protocols);
+    }
+
+    /**
+     * Sets the array of protocols.
+     *
+     * @param protocols the array of protocols (or null)
+     */
+    public void setProtocols(String[] protocols) {
+        this.protocols = clone(protocols);
+    }
+
+    /**
+     * Returns whether client authentication should be requested.
+     *
+     * @return whether client authentication should be requested.
+     */
+    public boolean getWantClientAuth() {
+        return wantClientAuth;
+    }
+
+    /**
+     * Sets whether client authentication should be requested. Calling
+     * this method clears the <code>needClientAuth</code> flag.
+     *
+     * @param wantClientAuth whether client authentication should be requested
+     */
+    public void setWantClientAuth(boolean wantClientAuth) {
+        this.wantClientAuth = wantClientAuth;
+        this.needClientAuth = false;
+    }
+
+    /**
+     * Returns whether client authentication should be required.
+     *
+     * @return whether client authentication should be required.
+     */
+    public boolean getNeedClientAuth() {
+        return needClientAuth;
+    }
+
+    /**
+     * Sets whether client authentication should be required. Calling
+     * this method clears the <code>wantClientAuth</code> flag.
+     *
+     * @param needClientAuth whether client authentication should be required
+     */
+    public void setNeedClientAuth(boolean needClientAuth) {
+        this.wantClientAuth = false;
+        this.needClientAuth = needClientAuth;
+    }
+
+    /**
+     * Returns the cryptographic algorithm constraints.
+     *
+     * @return the cryptographic algorithm constraints, or null if the
+     *     constraints have not been set
+     *
+     * @see #setAlgorithmConstraints(AlgorithmConstraints)
+     *
+     * @since 1.7
+     */
+    public AlgorithmConstraints getAlgorithmConstraints() {
+        return algorithmConstraints;
+    }
+
+    /**
+     * Sets the cryptographic algorithm constraints, which will be used
+     * in addition to any configured by the runtime environment.
+     * <p>
+     * If the <code>constraints</code> parameter is non-null, every
+     * cryptographic algorithm, key and algorithm parameters used in the
+     * SSL/TLS handshake must be permitted by the constraints.
+     *
+     * @param constraints the algorithm constraints (or null)
+     *
+     * @since 1.7
+     */
+    public void setAlgorithmConstraints(AlgorithmConstraints constraints) {
+        // the constraints object is immutable
+        this.algorithmConstraints = constraints;
+    }
+
+    /**
+     * Gets the endpoint identification algorithm.
+     *
+     * @return the endpoint identification algorithm, or null if none
+     * has been set.
+     *
+     * @see X509ExtendedTrustManager
+     * @see #setEndpointIdentificationAlgorithm(String)
+     *
+     * @since 1.7
+     */
+    public String getEndpointIdentificationAlgorithm() {
+        return identificationAlgorithm;
+    }
+
+    /**
+     * Sets the endpoint identification algorithm.
+     * <p>
+     * If the <code>algorithm</code> parameter is non-null or non-empty, the
+     * endpoint identification/verification procedures must be handled during
+     * SSL/TLS handshaking.  This is to prevent man-in-the-middle attacks.
+     *
+     * @param algorithm The standard string name of the endpoint
+     *     identification algorithm (or null).  See Appendix A in the <a href=
+     *   "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
+     *     Java Cryptography Architecture API Specification &amp; Reference </a>
+     *     for information about standard algorithm names.
+     *
+     * @see X509ExtendedTrustManager
+     *
+     * @since 1.7
+     */
+    public void setEndpointIdentificationAlgorithm(String algorithm) {
+        this.identificationAlgorithm = algorithm;
+    }
+
+    /**
+     * Sets the desired {@link SNIServerName}s of the Server Name
+     * Indication (SNI) parameter.
+     * <P>
+     * This method is only useful to {@link SSLSocket}s or {@link SSLEngine}s
+     * operating in client mode.
+     * <P>
+     * Note that the {@code serverNames} list is cloned
+     * to protect against subsequent modification.
+     *
+     * @param  serverNames
+     *         the list of desired {@link SNIServerName}s (or null)
+     *
+     * @throws NullPointerException if the {@code serverNames}
+     *         contains {@code null} element
+     * @throws IllegalArgumentException if the {@code serverNames}
+     *         contains more than one name of the same name type
+     *
+     * @see SNIServerName
+     * @see #getServerNames()
+     *
+     * @since 1.8
+     */
+    public final void setServerNames(List<SNIServerName> serverNames) {
+        if (serverNames != null) {
+            if (!serverNames.isEmpty()) {
+                sniNames = new LinkedHashMap<>(serverNames.size());
+                for (SNIServerName serverName : serverNames) {
+                    if (sniNames.put(serverName.getType(),
+                                                serverName) != null) {
+                        throw new IllegalArgumentException(
+                                    "Duplicated server name of type " +
+                                    serverName.getType());
+                    }
+                }
+            } else {
+                sniNames = Collections.<Integer, SNIServerName>emptyMap();
+            }
+        } else {
+            sniNames = null;
+        }
+    }
+
+    /**
+     * Returns a {@link List} containing all {@link SNIServerName}s of the
+     * Server Name Indication (SNI) parameter, or null if none has been set.
+     * <P>
+     * This method is only useful to {@link SSLSocket}s or {@link SSLEngine}s
+     * operating in client mode.
+     * <P>
+     * For SSL/TLS connections, the underlying SSL/TLS provider
+     * may specify a default value for a certain server name type.  In
+     * client mode, it is recommended that, by default, providers should
+     * include the server name indication whenever the server can be located
+     * by a supported server name type.
+     * <P>
+     * It is recommended that providers initialize default Server Name
+     * Indications when creating {@code SSLSocket}/{@code SSLEngine}s.
+     * In the following examples, the server name could be represented by an
+     * instance of {@link SNIHostName} which has been initialized with the
+     * hostname "www.example.com" and type
+     * {@link StandardConstants#SNI_HOST_NAME}.
+     *
+     * <pre>
+     *     Socket socket =
+     *         sslSocketFactory.createSocket("www.example.com", 443);
+     * </pre>
+     * or
+     * <pre>
+     *     SSLEngine engine =
+     *         sslContext.createSSLEngine("www.example.com", 443);
+     * </pre>
+     * <P>
+     *
+     * @return null or an immutable list of non-null {@link SNIServerName}s
+     *
+     * @see List
+     * @see #setServerNames(List)
+     *
+     * @since 1.8
+     */
+    public final List<SNIServerName> getServerNames() {
+        if (sniNames != null) {
+            if (!sniNames.isEmpty()) {
+                return Collections.<SNIServerName>unmodifiableList(
+                                        new ArrayList<>(sniNames.values()));
+            } else {
+                return Collections.<SNIServerName>emptyList();
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Sets the {@link SNIMatcher}s of the Server Name Indication (SNI)
+     * parameter.
+     * <P>
+     * This method is only useful to {@link SSLSocket}s or {@link SSLEngine}s
+     * operating in server mode.
+     * <P>
+     * Note that the {@code matchers} collection is cloned to protect
+     * against subsequent modification.
+     *
+     * @param  matchers
+     *         the collection of {@link SNIMatcher}s (or null)
+     *
+     * @throws NullPointerException if the {@code matchers}
+     *         contains {@code null} element
+     * @throws IllegalArgumentException if the {@code matchers}
+     *         contains more than one name of the same name type
+     *
+     * @see Collection
+     * @see SNIMatcher
+     * @see #getSNIMatchers()
+     *
+     * @since 1.8
+     */
+    public final void setSNIMatchers(Collection<SNIMatcher> matchers) {
+        if (matchers != null) {
+            if (!matchers.isEmpty()) {
+                sniMatchers = new HashMap<>(matchers.size());
+                for (SNIMatcher matcher : matchers) {
+                    if (sniMatchers.put(matcher.getType(),
+                                                matcher) != null) {
+                        throw new IllegalArgumentException(
+                                    "Duplicated server name of type " +
+                                    matcher.getType());
+                    }
+                }
+            } else {
+                sniMatchers = Collections.<Integer, SNIMatcher>emptyMap();
+            }
+        } else {
+            sniMatchers = null;
+        }
+    }
+
+    /**
+     * Returns a {@link Collection} containing all {@link SNIMatcher}s of the
+     * Server Name Indication (SNI) parameter, or null if none has been set.
+     * <P>
+     * This method is only useful to {@link SSLSocket}s or {@link SSLEngine}s
+     * operating in server mode.
+     * <P>
+     * For better interoperability, providers generally will not define
+     * default matchers so that by default servers will ignore the SNI
+     * extension and continue the handshake.
+     *
+     * @return null or an immutable collection of non-null {@link SNIMatcher}s
+     *
+     * @see SNIMatcher
+     * @see #setSNIMatchers(Collection)
+     *
+     * @since 1.8
+     */
+    public final Collection<SNIMatcher> getSNIMatchers() {
+        if (sniMatchers != null) {
+            if (!sniMatchers.isEmpty()) {
+                return Collections.<SNIMatcher>unmodifiableList(
+                                        new ArrayList<>(sniMatchers.values()));
+            } else {
+                return Collections.<SNIMatcher>emptyList();
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Sets whether the local cipher suites preference should be honored.
+     *
+     * @param honorOrder whether local cipher suites order in
+     *        {@code #getCipherSuites} should be honored during
+     *        SSL/TLS handshaking.
+     *
+     * @see #getUseCipherSuitesOrder()
+     *
+     * @since 1.8
+     */
+    public final void setUseCipherSuitesOrder(boolean honorOrder) {
+        this.preferLocalCipherSuites = honorOrder;
+    }
+
+    /**
+     * Returns whether the local cipher suites preference should be honored.
+     *
+     * @return whether local cipher suites order in {@code #getCipherSuites}
+     *         should be honored during SSL/TLS handshaking.
+     *
+     * @see #setUseCipherSuitesOrder(boolean)
+     *
+     * @since 1.8
+     */
+    public final boolean getUseCipherSuitesOrder() {
+        return preferLocalCipherSuites;
+    }
+
+    // BEGIN Android-added: Integrate ALPN-related methods from OpenJDK 9+181
+    // Also removed references to DTLS in documentation; Android doesn't support DTLS.
+    /**
+     * Returns a prioritized array of application-layer protocol names that
+     * can be negotiated over the SSL/TLS protocols.
+     * <p>
+     * The array could be empty (zero-length), in which case protocol
+     * indications will not be used.
+     * <p>
+     * This method will return a new array each time it is invoked.
+     *
+     * @return a non-null, possibly zero-length array of application protocol
+     *         {@code String}s.  The array is ordered based on protocol
+     *         preference, with {@code protocols[0]} being the most preferred.
+     * @see #setApplicationProtocols
+     * @since 9
+     */
+    public String[] getApplicationProtocols() {
+        return applicationProtocols.clone();
+    }
+
+    /**
+     * Sets the prioritized array of application-layer protocol names that
+     * can be negotiated over the SSL/TLS protocols.
+     * <p>
+     * If application-layer protocols are supported by the underlying
+     * SSL/TLS implementation, this method configures which values can
+     * be negotiated by protocols such as <a
+     * href="http://www.ietf.org/rfc/rfc7301.txt"> RFC 7301 </a>, the
+     * Application Layer Protocol Negotiation (ALPN).
+     * <p>
+     * If this end of the connection is expected to offer application protocol
+     * values, all protocols configured by this method will be sent to the
+     * peer.
+     * <p>
+     * If this end of the connection is expected to select the application
+     * protocol value, the {@code protocols} configured by this method are
+     * compared with those sent by the peer.  The first matched value becomes
+     * the negotiated value.  If none of the {@code protocols} were actually
+     * requested by the peer, the underlying protocol will determine what
+     * action to take.  (For example, ALPN will send a
+     * {@code "no_application_protocol"} alert and terminate the connection.)
+     * <p>
+     * @implSpec
+     * This method will make a copy of the {@code protocols} array.
+     *
+     * @param protocols   an ordered array of application protocols,
+     *                    with {@code protocols[0]} being the most preferred.
+     *                    If the array is empty (zero-length), protocol
+     *                    indications will not be used.
+     * @throws IllegalArgumentException if protocols is null, or if
+     *                    any element in a non-empty array is null or an
+     *                    empty (zero-length) string
+     * @see #getApplicationProtocols
+     * @since 9
+     */
+    public void setApplicationProtocols(String[] protocols) {
+        if (protocols == null) {
+            throw new IllegalArgumentException("protocols was null");
+        }
+
+        String[] tempProtocols = protocols.clone();
+
+        for (String p : tempProtocols) {
+            if (p == null || p.equals("")) {
+                throw new IllegalArgumentException(
+                    "An element of protocols was null/empty");
+            }
+        }
+        applicationProtocols = tempProtocols;
+    }
+    // END Android-added: Integrate ALPN-related methods from OpenJDK 9+181
+}
diff --git a/javax/net/ssl/SSLPeerUnverifiedException.java b/javax/net/ssl/SSLPeerUnverifiedException.java
new file mode 100644
index 0000000..e613e0f
--- /dev/null
+++ b/javax/net/ssl/SSLPeerUnverifiedException.java
@@ -0,0 +1,57 @@
+/*
+ * 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 javax.net.ssl;
+
+
+/**
+ * Indicates that the peer's identity has not been verified.
+ * <P>
+ * When the peer was not able to
+ * identify itself (for example; no certificate, the particular
+ * cipher suite being used does not support authentication, or no
+ * peer authentication was established during SSL handshaking) this
+ * exception is thrown.
+ *
+ * @since 1.4
+ * @author David Brownell
+ */
+public
+class SSLPeerUnverifiedException extends SSLException
+{
+    private static final long serialVersionUID = -8919512675000600547L;
+
+    /**
+     * Constructs an exception reporting that the SSL peer's
+     * identity has not been verified.
+     *
+     * @param reason describes the problem.
+     */
+    public SSLPeerUnverifiedException(String reason)
+    {
+        super(reason);
+    }
+}
diff --git a/javax/net/ssl/SSLPermission.java b/javax/net/ssl/SSLPermission.java
new file mode 100644
index 0000000..a23e1ce
--- /dev/null
+++ b/javax/net/ssl/SSLPermission.java
@@ -0,0 +1,47 @@
+/*
+ * 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 javax.net.ssl;
+
+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 SSLPermission extends BasicPermission {
+
+    public SSLPermission(String name)
+    {
+        super("");
+    }
+
+    public SSLPermission(String name, String actions)
+    {
+        super("", "");
+    }
+}
diff --git a/javax/net/ssl/SSLProtocolException.java b/javax/net/ssl/SSLProtocolException.java
new file mode 100644
index 0000000..2924c2a
--- /dev/null
+++ b/javax/net/ssl/SSLProtocolException.java
@@ -0,0 +1,51 @@
+/*
+ * 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 javax.net.ssl;
+
+/**
+ * Reports an error in the operation of the SSL protocol.  Normally
+ * this indicates a flaw in one of the protocol implementations.
+ *
+ * @since 1.4
+ * @author David Brownell
+ */
+public
+class SSLProtocolException extends SSLException
+{
+    private static final long serialVersionUID = 5445067063799134928L;
+
+    /**
+     * Constructs an exception reporting an SSL protocol error
+     * detected by an SSL subsystem.
+     *
+     * @param reason describes the problem.
+     */
+    public SSLProtocolException(String reason)
+    {
+        super(reason);
+    }
+}
diff --git a/javax/net/ssl/SSLServerSocket.java b/javax/net/ssl/SSLServerSocket.java
new file mode 100644
index 0000000..35c14ea
--- /dev/null
+++ b/javax/net/ssl/SSLServerSocket.java
@@ -0,0 +1,553 @@
+/*
+ * 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 javax.net.ssl;
+
+import java.io.*;
+import java.net.*;
+
+
+/**
+ * This class extends <code>ServerSocket</code>s and
+ * provides secure server sockets using protocols such as the Secure
+ * Sockets Layer (SSL) or Transport Layer Security (TLS) protocols.
+ * <P>
+ * Instances of this class are generally created using a
+ * <code>SSLServerSocketFactory</code>.  The primary function
+ * of <code>SSLServerSocket</code>s
+ * is to create <code>SSLSocket</code>s by <code>accept</code>ing
+ * connections.
+ * <P>
+ * <code>SSLServerSocket</code>s contain several pieces of state data
+ * which are inherited by the <code>SSLSocket</code> at
+ * socket creation.  These include the enabled cipher
+ * suites and protocols, whether client
+ * authentication is necessary, and whether created sockets should
+ * begin handshaking in client or server mode.  The state
+ * inherited by the created <code>SSLSocket</code> can be
+ * overriden by calling the appropriate methods.
+ *
+ * @see java.net.ServerSocket
+ * @see SSLSocket
+ *
+ * @since 1.4
+ * @author David Brownell
+ */
+public abstract class SSLServerSocket extends ServerSocket {
+
+    /**
+     * Used only by subclasses.
+     * <P>
+     * Create an unbound TCP server socket using the default authentication
+     * context.
+     *
+     * @throws IOException if an I/O error occurs when creating the socket
+     */
+    protected SSLServerSocket()
+    throws IOException
+        { super(); }
+
+
+    /**
+     * Used only by subclasses.
+     * <P>
+     * Create a TCP server socket on a port, using the default
+     * authentication context.  The connection backlog defaults to
+     * fifty connections queued up before the system starts to
+     * reject new connection requests.
+     * <P>
+     * A port number of <code>0</code> creates a socket on any free port.
+     * <P>
+     * If there is a security manager, its <code>checkListen</code>
+     * method is called with the <code>port</code> argument as its
+     * argument to ensure the operation is allowed. This could result
+     * in a SecurityException.
+     *
+     * @param port the port on which to listen
+     * @throws IOException if an I/O error occurs when creating the socket
+     * @throws SecurityException if a security manager exists and its
+     *         <code>checkListen</code> method doesn't allow the operation.
+     * @throws IllegalArgumentException if the port parameter is outside the
+     *         specified range of valid port values, which is between 0 and
+     *         65535, inclusive.
+     * @see    SecurityManager#checkListen
+     */
+    protected SSLServerSocket(int port)
+    throws IOException
+        { super(port); }
+
+
+    /**
+     * Used only by subclasses.
+     * <P>
+     * Create a TCP server socket on a port, using the default
+     * authentication context and a specified backlog of connections.
+     * <P>
+     * A port number of <code>0</code> creates a socket on any free port.
+     * <P>
+     * The <code>backlog</code> 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</code>. If it is less than or equal to
+     * <code>0</code>, then an implementation specific default will be used.
+     * <P>
+     * If there is a security manager, its <code>checkListen</code>
+     * method is called with the <code>port</code> argument as its
+     * argument to ensure the operation is allowed. This could result
+     * in a SecurityException.
+     *
+     * @param port the port on which to listen
+     * @param backlog  requested maximum length of the queue of incoming
+     *                  connections.
+     * @throws IOException if an I/O error occurs when creating the socket
+     * @throws SecurityException if a security manager exists and its
+     *         <code>checkListen</code> method doesn't allow the operation.
+     * @throws IllegalArgumentException if the port parameter is outside the
+     *         specified range of valid port values, which is between 0 and
+     *         65535, inclusive.
+     * @see    SecurityManager#checkListen
+     */
+    protected SSLServerSocket(int port, int backlog)
+    throws IOException
+        { super(port, backlog); }
+
+
+    /**
+     * Used only by subclasses.
+     * <P>
+     * Create a TCP server socket on a port, using the default
+     * authentication context and a specified backlog of connections
+     * as well as a particular specified network interface.  This
+     * constructor is used on multihomed hosts, such as those used
+     * for firewalls or as routers, to control through which interface
+     * a network service is provided.
+     * <P>
+     * If there is a security manager, its <code>checkListen</code>
+     * method is called with the <code>port</code> argument as its
+     * argument to ensure the operation is allowed. This could result
+     * in a SecurityException.
+     * <P>
+     * A port number of <code>0</code> creates a socket on any free port.
+     * <P>
+     * The <code>backlog</code> 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</code>. If it is less than or equal to
+     * <code>0</code>, then an implementation specific default will be used.
+     * <P>
+     * If <i>address</i> is null, it will default accepting connections
+     * on any/all local addresses.
+     *
+     * @param port the port on which to listen
+     * @param backlog  requested maximum length of the queue of incoming
+     *                  connections.
+     * @param address the address of the network interface through
+     *          which connections will be accepted
+     * @throws IOException if an I/O error occurs when creating the socket
+     * @throws SecurityException if a security manager exists and its
+     *         <code>checkListen</code> method doesn't allow the operation.
+     * @throws IllegalArgumentException if the port parameter is outside the
+     *         specified range of valid port values, which is between 0 and
+     *         65535, inclusive.
+     * @see    SecurityManager#checkListen
+     */
+    protected SSLServerSocket(int port, int backlog, InetAddress address)
+    throws IOException
+        { super(port, backlog, address); }
+
+
+
+    /**
+     * Returns the list of cipher suites which are currently enabled
+     * for use by newly accepted connections.
+     * <P>
+     * If this list has not been explicitly modified, a system-provided
+     * default guarantees a minimum quality of service in all enabled
+     * cipher suites.
+     * <P>
+     * There are several reasons why an enabled cipher suite might
+     * not actually be used.  For example:  the server socket might
+     * not have appropriate private keys available to it or the cipher
+     * suite might be anonymous, precluding the use of client authentication,
+     * while the server socket has been told to require that sort of
+     * authentication.
+     *
+     * @return an array of cipher suites enabled
+     * @see #getSupportedCipherSuites()
+     * @see #setEnabledCipherSuites(String [])
+     */
+    public abstract String [] getEnabledCipherSuites();
+
+
+    /**
+     * Sets the cipher suites enabled for use by accepted connections.
+     * <P>
+     * The cipher suites must have been listed by getSupportedCipherSuites()
+     * as being supported.  Following a successful call to this method,
+     * only suites listed in the <code>suites</code> parameter are enabled
+     * for use.
+     * <P>
+     * Suites that require authentication information which is not available
+     * in this ServerSocket's authentication context will not be used
+     * in any case, even if they are enabled.
+     * <P>
+     * <code>SSLSocket</code>s returned from <code>accept()</code>
+     * inherit this setting.
+     *
+     * @param suites Names of all the cipher suites to enable
+     * @exception IllegalArgumentException when one or more of ciphers
+     *          named by the parameter is not supported, or when
+     *          the parameter is null.
+     * @see #getSupportedCipherSuites()
+     * @see #getEnabledCipherSuites()
+     */
+    public abstract void setEnabledCipherSuites(String suites []);
+
+
+    // Android-changed: Added warnings about misuse
+    /**
+     * Returns the names of the cipher suites which could be enabled for use
+     * on an SSL connection.
+     * <P>
+     * Normally, only a subset of these will actually
+     * be enabled by default, since this list may include cipher suites which
+     * do not meet quality of service requirements for those defaults.  Such
+     * cipher suites are useful in specialized applications.
+     *
+     * <p class="caution">Applications should not blindly enable all supported
+     * cipher suites.  The supported cipher suites can include signaling cipher suite
+     * values that can cause connection problems if enabled inappropriately.
+     *
+     * <p>The proper way to use this method is to either check if a specific cipher
+     * suite is supported via {@code Arrays.asList(getSupportedCipherSuites()).contains(...)}
+     * or to filter a desired list of cipher suites to only the supported ones via
+     * {@code desiredSuiteSet.retainAll(Arrays.asList(getSupportedCipherSuites()))}.
+     *
+     * @return an array of cipher suite names
+     * @see #getEnabledCipherSuites()
+     * @see #setEnabledCipherSuites(String [])
+     */
+    public abstract String [] getSupportedCipherSuites();
+
+
+    /**
+     * Returns the names of the protocols which could be enabled for use.
+     *
+     * @return an array of protocol names supported
+     * @see #getEnabledProtocols()
+     * @see #setEnabledProtocols(String [])
+     */
+    public abstract String [] getSupportedProtocols();
+
+
+    /**
+     * Returns the names of the protocols which are currently
+     * enabled for use by the newly accepted connections.
+     *
+     * @return an array of protocol names
+     * @see #getSupportedProtocols()
+     * @see #setEnabledProtocols(String [])
+     */
+    public abstract String [] getEnabledProtocols();
+
+
+    // Android-added: Added paragraph about contiguous protocols.
+    /**
+     * Controls which particular protocols are enabled for use by
+     * accepted connections.
+     * <P>
+     * The protocols must have been listed by
+     * getSupportedProtocols() as being supported.
+     * Following a successful call to this method, only protocols listed
+     * in the <code>protocols</code> parameter are enabled for use.
+     * <p>
+     * Because of the way the protocol version is negotiated, connections
+     * will only be able to use a member of the lowest set of contiguous
+     * enabled protocol versions.  For example, enabling TLSv1.2 and TLSv1
+     * will result in connections only being able to use TLSv1.
+     * <P>
+     * <code>SSLSocket</code>s returned from <code>accept()</code>
+     * inherit this setting.
+     *
+     * @param protocols Names of all the protocols to enable.
+     * @exception IllegalArgumentException when one or more of
+     *            the protocols named by the parameter is not supported or
+     *            when the protocols parameter is null.
+     * @see #getEnabledProtocols()
+     * @see #getSupportedProtocols()
+     */
+    public abstract void setEnabledProtocols(String protocols[]);
+
+
+    /**
+     * Controls whether <code>accept</code>ed server-mode
+     * <code>SSLSockets</code> will be initially configured to
+     * <i>require</i> client authentication.
+     * <P>
+     * A socket's client authentication setting is one of the following:
+     * <ul>
+     * <li> client authentication required
+     * <li> client authentication requested
+     * <li> no client authentication desired
+     * </ul>
+     * <P>
+     * Unlike {@link #setWantClientAuth(boolean)}, if the accepted
+     * socket's option is set and the client chooses not to provide
+     * authentication information about itself, <i>the negotiations
+     * will stop and the connection will be dropped</i>.
+     * <P>
+     * Calling this method overrides any previous setting made by
+     * this method or {@link #setWantClientAuth(boolean)}.
+     * <P>
+     * The initial inherited setting may be overridden by calling
+     * {@link SSLSocket#setNeedClientAuth(boolean)} or
+     * {@link SSLSocket#setWantClientAuth(boolean)}.
+     *
+     * @param   need set to true if client authentication is required,
+     *          or false if no client authentication is desired.
+     * @see #getNeedClientAuth()
+     * @see #setWantClientAuth(boolean)
+     * @see #getWantClientAuth()
+     * @see #setUseClientMode(boolean)
+     */
+    public abstract void setNeedClientAuth(boolean need);
+
+
+    /**
+     * Returns true if client authentication will be <i>required</i> on
+     * newly <code>accept</code>ed server-mode <code>SSLSocket</code>s.
+     * <P>
+     * The initial inherited setting may be overridden by calling
+     * {@link SSLSocket#setNeedClientAuth(boolean)} or
+     * {@link SSLSocket#setWantClientAuth(boolean)}.
+     *
+     * @return  true if client authentication is required,
+     *          or false if no client authentication is desired.
+     * @see #setNeedClientAuth(boolean)
+     * @see #setWantClientAuth(boolean)
+     * @see #getWantClientAuth()
+     * @see #setUseClientMode(boolean)
+     */
+    public abstract boolean getNeedClientAuth();
+
+
+    /**
+     * Controls whether <code>accept</code>ed server-mode
+     * <code>SSLSockets</code> will be initially configured to
+     * <i>request</i> client authentication.
+     * <P>
+     * A socket's client authentication setting is one of the following:
+     * <ul>
+     * <li> client authentication required
+     * <li> client authentication requested
+     * <li> no client authentication desired
+     * </ul>
+     * <P>
+     * Unlike {@link #setNeedClientAuth(boolean)}, if the accepted
+     * socket's option is set and the client chooses not to provide
+     * authentication information about itself, <i>the negotiations
+     * will continue</i>.
+     * <P>
+     * Calling this method overrides any previous setting made by
+     * this method or {@link #setNeedClientAuth(boolean)}.
+     * <P>
+     * The initial inherited setting may be overridden by calling
+     * {@link SSLSocket#setNeedClientAuth(boolean)} or
+     * {@link SSLSocket#setWantClientAuth(boolean)}.
+     *
+     * @param   want set to true if client authentication is requested,
+     *          or false if no client authentication is desired.
+     * @see #getWantClientAuth()
+     * @see #setNeedClientAuth(boolean)
+     * @see #getNeedClientAuth()
+     * @see #setUseClientMode(boolean)
+     */
+    public abstract void setWantClientAuth(boolean want);
+
+
+    /**
+     * Returns true if client authentication will be <i>requested</i> on
+     * newly accepted server-mode connections.
+     * <P>
+     * The initial inherited setting may be overridden by calling
+     * {@link SSLSocket#setNeedClientAuth(boolean)} or
+     * {@link SSLSocket#setWantClientAuth(boolean)}.
+     *
+     * @return  true if client authentication is requested,
+     *          or false if no client authentication is desired.
+     * @see #setWantClientAuth(boolean)
+     * @see #setNeedClientAuth(boolean)
+     * @see #getNeedClientAuth()
+     * @see #setUseClientMode(boolean)
+     */
+    public abstract boolean getWantClientAuth();
+
+
+    /**
+     * Controls whether accepted connections are in the (default) SSL
+     * server mode, or the SSL client mode.
+     * <P>
+     * Servers normally authenticate themselves, and clients are not
+     * required to do so.
+     * <P>
+     * In rare cases, TCP servers
+     * need to act in the SSL client mode on newly accepted
+     * connections. For example, FTP clients acquire server sockets
+     * and listen there for reverse connections from the server. An
+     * FTP client would use an SSLServerSocket in "client" mode to
+     * accept the reverse connection while the FTP server uses an
+     * SSLSocket with "client" mode disabled to initiate the
+     * connection. During the resulting handshake, existing SSL
+     * sessions may be reused.
+     * <P>
+     * <code>SSLSocket</code>s returned from <code>accept()</code>
+     * inherit this setting.
+     *
+     * @param mode true if newly accepted connections should use SSL
+     *          client mode.
+     * @see #getUseClientMode()
+     */
+    public abstract void setUseClientMode(boolean mode);
+
+
+    /**
+     * Returns true if accepted connections will be in SSL client mode.
+     *
+     * @see #setUseClientMode(boolean)
+     * @return true if the connection should use SSL client mode.
+     */
+    public abstract boolean getUseClientMode();
+
+
+    /**
+     * Controls whether new SSL sessions may be established by the
+     * sockets which are created from this server socket.
+     * <P>
+     * <code>SSLSocket</code>s returned from <code>accept()</code>
+     * inherit this setting.
+     *
+     * @param flag true indicates that sessions may be created; this
+     *          is the default. false indicates that an existing session
+     *          must be resumed.
+     * @see #getEnableSessionCreation()
+     */
+    public abstract void setEnableSessionCreation(boolean flag);
+
+
+    /**
+     * Returns true if new SSL sessions may be established by the
+     * sockets which are created from this server socket.
+     *
+     * @return true indicates that sessions may be created; this
+     *          is the default.  false indicates that an existing
+     *          session must be resumed
+     * @see #setEnableSessionCreation(boolean)
+     */
+    public abstract boolean getEnableSessionCreation();
+
+    /**
+     * Returns the SSLParameters in effect for newly accepted connections.
+     * The ciphersuites and protocols of the returned SSLParameters
+     * are always non-null.
+     *
+     * @return the SSLParameters in effect for newly accepted connections
+     *
+     * @see #setSSLParameters(SSLParameters)
+     *
+     * @since 1.7
+     */
+    public SSLParameters getSSLParameters() {
+        SSLParameters parameters = new SSLParameters();
+
+        parameters.setCipherSuites(getEnabledCipherSuites());
+        parameters.setProtocols(getEnabledProtocols());
+        if (getNeedClientAuth()) {
+            parameters.setNeedClientAuth(true);
+        } else if (getWantClientAuth()) {
+            parameters.setWantClientAuth(true);
+        }
+
+        return parameters;
+    }
+
+    /**
+     * Applies SSLParameters to newly accepted connections.
+     *
+     * <p>This means:
+     * <ul>
+     * <li>If {@code params.getCipherSuites()} is non-null,
+     *   {@code setEnabledCipherSuites()} is called with that value.</li>
+     * <li>If {@code params.getProtocols()} is non-null,
+     *   {@code setEnabledProtocols()} is called with that value.</li>
+     * <li>If {@code params.getNeedClientAuth()} or
+     *   {@code params.getWantClientAuth()} return {@code true},
+     *   {@code setNeedClientAuth(true)} and
+     *   {@code setWantClientAuth(true)} are called, respectively;
+     *   otherwise {@code setWantClientAuth(false)} is called.</li>
+     * <li>If {@code params.getServerNames()} is non-null, the socket will
+     *   configure its server names with that value.</li>
+     * <li>If {@code params.getSNIMatchers()} is non-null, the socket will
+     *   configure its SNI matchers with that value.</li>
+     * </ul>
+     *
+     * @param params the parameters
+     * @throws IllegalArgumentException if the setEnabledCipherSuites() or
+     *    the setEnabledProtocols() call fails
+     *
+     * @see #getSSLParameters()
+     *
+     * @since 1.7
+     */
+    public void setSSLParameters(SSLParameters params) {
+        String[] s;
+        s = params.getCipherSuites();
+        if (s != null) {
+            setEnabledCipherSuites(s);
+        }
+
+        s = params.getProtocols();
+        if (s != null) {
+            setEnabledProtocols(s);
+        }
+
+        if (params.getNeedClientAuth()) {
+            setNeedClientAuth(true);
+        } else if (params.getWantClientAuth()) {
+            setWantClientAuth(true);
+        } else {
+            setWantClientAuth(false);
+        }
+    }
+
+    // Android-added: Make toString explicit that this is an SSLServerSocket (http://b/6602228)
+    @Override
+    public String toString() {
+        return "SSL" + super.toString();
+    }
+
+}
diff --git a/javax/net/ssl/SSLServerSocketFactory.java b/javax/net/ssl/SSLServerSocketFactory.java
new file mode 100644
index 0000000..5067f8f
--- /dev/null
+++ b/javax/net/ssl/SSLServerSocketFactory.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * 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 javax.net.ssl;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.SocketException;
+import javax.net.ServerSocketFactory;
+import java.security.*;
+
+/**
+ * <code>SSLServerSocketFactory</code>s create
+ * <code>SSLServerSocket</code>s.
+ *
+ * @since 1.4
+ * @see SSLSocket
+ * @see SSLServerSocket
+ * @author David Brownell
+ */
+public abstract class SSLServerSocketFactory extends ServerSocketFactory
+{
+    // Android-changed: Renamed field.
+    // Some apps rely on changing this field via reflection, so we can't change the name
+    // without introducing app compatibility problems.  See http://b/62248930.
+    private static SSLServerSocketFactory defaultServerSocketFactory;
+
+    // Android-changed: Check Security.getVersion() on each update.
+    // If the set of providers or other such things changes, it may change the default
+    // factory, so we track the version returned from Security.getVersion() instead of
+    // only having a flag that says if we've ever initialized the default.
+    // private static boolean propertyChecked;
+    private static int lastVersion = -1;
+
+    private static void log(String msg) {
+        if (SSLSocketFactory.DEBUG) {
+            System.out.println(msg);
+        }
+    }
+
+    /**
+     * Constructor is used only by subclasses.
+     */
+    protected SSLServerSocketFactory() { /* NOTHING */ }
+
+    /**
+     * Returns the default SSL server socket factory.
+     *
+     * <p>The first time this method is called, the security property
+     * "ssl.ServerSocketFactory.provider" is examined. If it is non-null, a
+     * class by that name is loaded and instantiated. If that is successful and
+     * the object is an instance of SSLServerSocketFactory, it is made the
+     * default SSL server socket factory.
+     *
+     * <p>Otherwise, this method returns
+     * <code>SSLContext.getDefault().getServerSocketFactory()</code>. If that
+     * call fails, an inoperative factory is returned.
+     *
+     * @return the default <code>ServerSocketFactory</code>
+     * @see SSLContext#getDefault
+     */
+    public static synchronized ServerSocketFactory getDefault() {
+        // Android-changed: Check Security.getVersion() on each update.
+        if (defaultServerSocketFactory != null && lastVersion == Security.getVersion()) {
+            return defaultServerSocketFactory;
+        }
+
+        lastVersion = Security.getVersion();
+        SSLServerSocketFactory previousDefaultServerSocketFactory = defaultServerSocketFactory;
+        defaultServerSocketFactory = null;
+
+        String clsName = SSLSocketFactory.getSecurityProperty
+                                    ("ssl.ServerSocketFactory.provider");
+        if (clsName != null) {
+            // Android-changed: Check if we already have an instance of the default factory class.
+            // The instance for the default socket factory is checked for updates quite
+            // often (for instance, every time a security provider is added). Which leads
+            // to unnecessary overload and excessive error messages in case of class-loading
+            // errors. Avoid creating a new object if the class name is the same as before.
+            if (previousDefaultServerSocketFactory != null
+                    && clsName.equals(previousDefaultServerSocketFactory.getClass().getName())) {
+                defaultServerSocketFactory = previousDefaultServerSocketFactory;
+                return defaultServerSocketFactory;
+            }
+            log("setting up default SSLServerSocketFactory");
+            try {
+                Class<?> cls = null;
+                try {
+                    cls = Class.forName(clsName);
+                } catch (ClassNotFoundException e) {
+                    // Android-changed; Try the contextClassLoader first.
+                    ClassLoader cl = Thread.currentThread().getContextClassLoader();
+                    if (cl == null) {
+                        cl = ClassLoader.getSystemClassLoader();
+                    }
+
+                    if (cl != null) {
+                        // Android-changed: Use Class.forName() so the class gets initialized.
+                        cls = Class.forName(clsName, true, cl);
+                    }
+                }
+                log("class " + clsName + " is loaded");
+                SSLServerSocketFactory fac = (SSLServerSocketFactory)cls.newInstance();
+                log("instantiated an instance of class " + clsName);
+                defaultServerSocketFactory = fac;
+                return fac;
+            } catch (Exception e) {
+                log("SSLServerSocketFactory instantiation failed: " + e);
+                // Android-changed: Fallback to the default SSLContext on exception.
+            }
+        }
+
+        try {
+            // Android-changed: Allow for {@code null} SSLContext.getDefault.
+            SSLContext context = SSLContext.getDefault();
+            if (context != null) {
+                defaultServerSocketFactory = context.getServerSocketFactory();
+            } else {
+                defaultServerSocketFactory = new DefaultSSLServerSocketFactory(new IllegalStateException("No factory found."));
+            }
+            return defaultServerSocketFactory;
+        } catch (NoSuchAlgorithmException e) {
+            return new DefaultSSLServerSocketFactory(e);
+        }
+    }
+
+    /**
+     * Returns the list of cipher suites which are enabled by default.
+     * Unless a different list is enabled, handshaking on an SSL connection
+     * will use one of these cipher suites.  The minimum quality of service
+     * for these defaults requires confidentiality protection and server
+     * authentication (that is, no anonymous cipher suites).
+     *
+     * @see #getSupportedCipherSuites()
+     * @return array of the cipher suites enabled by default
+     */
+    public abstract String [] getDefaultCipherSuites();
+
+
+    // Android-changed: Added warnings about misuse
+    /**
+     * Returns the names of the cipher suites which could be enabled for use
+     * on an SSL connection created by this factory.
+     * Normally, only a subset of these will actually
+     * be enabled by default, since this list may include cipher suites which
+     * do not meet quality of service requirements for those defaults.  Such
+     * cipher suites are useful in specialized applications.
+     *
+     * <p class="caution">Applications should not blindly enable all supported
+     * cipher suites.  The supported cipher suites can include signaling cipher suite
+     * values that can cause connection problems if enabled inappropriately.
+     *
+     * <p>The proper way to use this method is to either check if a specific cipher
+     * suite is supported via {@code Arrays.asList(getSupportedCipherSuites()).contains(...)}
+     * or to filter a desired list of cipher suites to only the supported ones via
+     * {@code desiredSuiteSet.retainAll(Arrays.asList(getSupportedCipherSuites()))}.
+     *
+     * @return an array of cipher suite names
+     * @see #getDefaultCipherSuites()
+     */
+    public abstract String [] getSupportedCipherSuites();
+}
+
+
+//
+// The default factory does NOTHING.
+//
+class DefaultSSLServerSocketFactory extends SSLServerSocketFactory {
+
+    private final Exception reason;
+
+    DefaultSSLServerSocketFactory(Exception reason) {
+        this.reason = reason;
+    }
+
+    private ServerSocket throwException() throws SocketException {
+        throw (SocketException)
+            new SocketException(reason.toString()).initCause(reason);
+    }
+
+    @Override
+    public ServerSocket createServerSocket() throws IOException {
+        return throwException();
+    }
+
+
+    @Override
+    public ServerSocket createServerSocket(int port)
+    throws IOException
+    {
+        return throwException();
+    }
+
+    @Override
+    public ServerSocket createServerSocket(int port, int backlog)
+    throws IOException
+    {
+        return throwException();
+    }
+
+    @Override
+    public ServerSocket
+    createServerSocket(int port, int backlog, InetAddress ifAddress)
+    throws IOException
+    {
+        return throwException();
+    }
+
+    @Override
+    public String [] getDefaultCipherSuites() {
+        return new String[0];
+    }
+
+    @Override
+    public String [] getSupportedCipherSuites() {
+        return new String[0];
+    }
+}
diff --git a/javax/net/ssl/SSLSession.java b/javax/net/ssl/SSLSession.java
new file mode 100644
index 0000000..d98edf0
--- /dev/null
+++ b/javax/net/ssl/SSLSession.java
@@ -0,0 +1,410 @@
+/*
+ * 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 javax.net.ssl;
+
+import java.security.Principal;
+
+/**
+ * In SSL, sessions are used to describe an ongoing relationship between
+ * two entities.  Each SSL connection involves one session at a time, but
+ * that session may be used on many connections between those entities,
+ * simultaneously or sequentially.  The session used on a connection may
+ * also be replaced by a different session.  Sessions are created, or
+ * rejoined, as part of the SSL handshaking protocol. Sessions may be
+ * invalidated due to policies affecting security or resource usage,
+ * or by an application explicitly calling <code>invalidate</code>.
+ * Session management policies are typically used to tune performance.
+ *
+ * <P> In addition to the standard session attributes, SSL sessions expose
+ * these read-only attributes:  <UL>
+ *
+ *      <LI> <em>Peer Identity.</em>  Sessions are between a particular
+ *      client and a particular server.  The identity of the peer may
+ *      have been established as part of session setup.  Peers are
+ *      generally identified by X.509 certificate chains.
+ *
+ *      <LI> <em>Cipher Suite Name.</em>  Cipher suites describe the
+ *      kind of cryptographic protection that's used by connections
+ *      in a particular session.
+ *
+ *      <LI> <em>Peer Host.</em>  All connections in a session are
+ *      between the same two hosts.  The address of the host on the other
+ *      side of the connection is available.
+ *
+ *      </UL>
+ *
+ * <P> Sessions may be explicitly invalidated.  Invalidation may also
+ * be done implicitly, when faced with certain kinds of errors.
+ *
+ * @since 1.4
+ * @author David Brownell
+ */
+public interface SSLSession {
+
+    /**
+     * Returns the identifier assigned to this Session.
+     *
+     * @return the Session identifier
+     */
+    public byte[] getId();
+
+
+    /**
+     * Returns the context in which this session is bound.
+     * <P>
+     * This context may be unavailable in some environments,
+     * in which case this method returns null.
+     * <P>
+     * If the context is available and there is a
+     * security manager installed, the caller may require
+     * permission to access it or a security exception may be thrown.
+     * In a Java environment, the security manager's
+     * <code>checkPermission</code> method is called with a
+     * <code>SSLPermission("getSSLSessionContext")</code> permission.
+     *
+     * @throws SecurityException if the calling thread does not have
+     *         permission to get SSL session context.
+     * @return the session context used for this session, or null
+     * if the context is unavailable.
+     */
+    public SSLSessionContext getSessionContext();
+
+
+    /**
+     * Returns the time at which this Session representation was created,
+     * in milliseconds since midnight, January 1, 1970 UTC.
+     *
+     * @return the time this Session was created
+     */
+    public long getCreationTime();
+
+
+    /**
+     * Returns the last time this Session representation was accessed by the
+     * session level infrastructure, in milliseconds since
+     * midnight, January 1, 1970 UTC.
+     * <P>
+     * Access indicates a new connection being established using session data.
+     * Application level operations, such as getting or setting a value
+     * associated with the session, are not reflected in this access time.
+     *
+     * <P> This information is particularly useful in session management
+     * policies.  For example, a session manager thread could leave all
+     * sessions in a given context which haven't been used in a long time;
+     * or, the sessions might be sorted according to age to optimize some task.
+     *
+     * @return the last time this Session was accessed
+     */
+    public long getLastAccessedTime();
+
+
+    /**
+     * Invalidates the session.
+     * <P>
+     * Future connections will not be able to
+     * resume or join this session.  However, any existing connection
+     * using this session can continue to use the session until the
+     * connection is closed.
+     *
+     * @see #isValid()
+     */
+    public void invalidate();
+
+
+    /**
+     * Returns whether this session is valid and available for resuming or
+     * joining.
+     *
+     * @return true if this session may be rejoined.
+     * @see #invalidate()
+     *
+     * @since 1.5
+     */
+    public boolean isValid();
+
+
+    /**
+     *
+     * Binds the specified <code>value</code> object into the
+     * session's application layer data
+     * with the given <code>name</code>.
+     * <P>
+     * Any existing binding using the same <code>name</code> is
+     * replaced.  If the new (or existing) <code>value</code> implements the
+     * <code>SSLSessionBindingListener</code> interface, the object
+     * represented by <code>value</code> is notified appropriately.
+     * <p>
+     * For security reasons, the same named values may not be
+     * visible across different access control contexts.
+     *
+     * @param name the name to which the data object will be bound.
+     *          This may not be null.
+     * @param value the data object to be bound. This may not be null.
+     * @throws IllegalArgumentException if either argument is null.
+     */
+    public void putValue(String name, Object value);
+
+
+    /**
+     * Returns the object bound to the given name in the session's
+     * application layer data.  Returns null if there is no such binding.
+     * <p>
+     * For security reasons, the same named values may not be
+     * visible across different access control contexts.
+     *
+     * @param name the name of the binding to find.
+     * @return the value bound to that name, or null if the binding does
+     *          not exist.
+     * @throws IllegalArgumentException if the argument is null.
+     */
+    public Object getValue(String name);
+
+
+    /**
+     * Removes the object bound to the given name in the session's
+     * application layer data.  Does nothing if there is no object
+     * bound to the given name.  If the bound existing object
+     * implements the <code>SessionBindingListener</code> interface,
+     * it is notified appropriately.
+     * <p>
+     * For security reasons, the same named values may not be
+     * visible across different access control contexts.
+     *
+     * @param name the name of the object to remove visible
+     *          across different access control contexts
+     * @throws IllegalArgumentException if the argument is null.
+     */
+    public void removeValue(String name);
+
+
+    /**
+     * Returns an array of the names of all the application layer
+     * data objects bound into the Session.
+     * <p>
+     * For security reasons, the same named values may not be
+     * visible across different access control contexts.
+     *
+     * @return a non-null (possibly empty) array of names of the objects
+     *  bound to this Session.
+     */
+    public String [] getValueNames();
+
+    /**
+     * Returns the identity of the peer which was established as part
+     * of defining the session.
+     * <P>
+     * 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 ordered array of peer certificates,
+     *          with the peer's own certificate first followed by any
+     *          certificate authorities.
+     * @exception SSLPeerUnverifiedException if the peer's identity has not
+     *          been verified
+     * @see #getPeerPrincipal()
+     */
+    public java.security.cert.Certificate [] getPeerCertificates()
+            throws SSLPeerUnverifiedException;
+
+    /**
+     * Returns the certificate(s) that were sent to the peer during
+     * handshaking.
+     * <P>
+     * Note: This method is useful only when using certificate-based
+     * cipher suites.
+     * <P>
+     * When multiple certificates are available for use in a
+     * handshake, the implementation chooses what it considers the
+     * "best" certificate chain available, and transmits that to
+     * the other side.  This method allows the caller to know
+     * which certificate chain was actually used.
+     *
+     * @return an ordered array of certificates,
+     * with the local certificate first followed by any
+     * certificate authorities.  If no certificates were sent,
+     * then null is returned.
+     *
+     * @see #getLocalPrincipal()
+     */
+    public java.security.cert.Certificate [] getLocalCertificates();
+
+    /**
+     * Returns the identity of the peer which was identified as part
+     * of defining the session.
+     * <P>
+     * 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.
+     *
+     * <p><em>Note: this method exists for compatibility with previous
+     * releases. New applications should use
+     * {@link #getPeerCertificates} instead.</em></p>
+     *
+     * @return an ordered array of peer X.509 certificates,
+     *          with the peer's own certificate first followed by any
+     *          certificate authorities.  (The certificates are in
+     *          the original JSSE certificate
+     *          {@link javax.security.cert.X509Certificate} format.)
+     * @exception SSLPeerUnverifiedException if the peer's identity
+     *          has not been verified
+     * @see #getPeerPrincipal()
+     */
+    public javax.security.cert.X509Certificate [] getPeerCertificateChain()
+            throws SSLPeerUnverifiedException;
+
+    /**
+     * Returns the identity of the peer which was established as part of
+     * defining the session.
+     *
+     * @return the peer'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's identity has not
+     *          been verified
+     *
+     * @see #getPeerCertificates()
+     * @see #getLocalPrincipal()
+     *
+     * @since 1.5
+     */
+    public Principal getPeerPrincipal()
+            throws SSLPeerUnverifiedException;
+
+    /**
+     * Returns the principal that was sent to the peer during handshaking.
+     *
+     * @return the principal sent to the peer. 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 #getLocalCertificates()
+     * @see #getPeerPrincipal()
+     *
+     * @since 1.5
+     */
+    public Principal getLocalPrincipal();
+
+    /**
+     * Returns the name of the SSL cipher suite which is used for all
+     * connections in the session.
+     *
+     * <P> This defines the level of protection
+     * provided to the data sent on the connection, including the kind
+     * of encryption used and most aspects of how authentication is done.
+     *
+     * @return the name of the session's cipher suite
+     */
+    public String getCipherSuite();
+
+    /**
+     * Returns the standard name of the protocol used for all
+     * connections in the session.
+     *
+     * <P> This defines the protocol used in the connection.
+     *
+     * @return the standard name of the protocol used for all
+     * connections in the session.
+     */
+    public String getProtocol();
+
+    /**
+     * Returns the host name of the peer in this session.
+     * <P>
+     * For the server, this is the client's host;  and for
+     * the client, it is the server's host. The name may not be
+     * a fully qualified host name or even a host name at all as
+     * it may represent a string encoding of the peer's network address.
+     * If such a name is desired, it might
+     * be resolved through a name service based on the value returned
+     * by this method.
+     * <P>
+     * This value is not authenticated and should not be relied upon.
+     * It is mainly used as a hint for <code>SSLSession</code> caching
+     * strategies.
+     *
+     * @return  the host name of the peer host, or null if no information
+     *          is available.
+     */
+    public String getPeerHost();
+
+    /**
+     * Returns the port number of the peer in this session.
+     * <P>
+     * For the server, this is the client's port number;  and for
+     * the client, it is the server's port number.
+     * <P>
+     * This value is not authenticated and should not be relied upon.
+     * It is mainly used as a hint for <code>SSLSession</code> caching
+     * strategies.
+     *
+     * @return  the port number of the peer host, or -1 if no information
+     *          is available.
+     *
+     * @since 1.5
+     */
+    public int getPeerPort();
+
+    /**
+     * Gets the current size of the largest SSL/TLS packet that is expected
+     * when using this session.
+     * <P>
+     * A <code>SSLEngine</code> using this session may generate SSL/TLS
+     * packets of any size up to and including the value returned by this
+     * method. All <code>SSLEngine</code> network buffers should be sized
+     * at least this large to avoid insufficient space problems when
+     * performing <code>wrap</code> and <code>unwrap</code> calls.
+     *
+     * @return  the current maximum expected network packet size
+     *
+     * @see SSLEngine#wrap(ByteBuffer, ByteBuffer)
+     * @see SSLEngine#unwrap(ByteBuffer, ByteBuffer)
+     *
+     * @since 1.5
+     */
+    public int getPacketBufferSize();
+
+
+    /**
+     * Gets the current size of the largest application data that is
+     * expected when using this session.
+     * <P>
+     * <code>SSLEngine</code> application data buffers must be large
+     * enough to hold the application data from any inbound network
+     * application data packet received.  Typically, outbound
+     * application data buffers can be of any size.
+     *
+     * @return  the current maximum expected application packet size
+     *
+     * @see SSLEngine#wrap(ByteBuffer, ByteBuffer)
+     * @see SSLEngine#unwrap(ByteBuffer, ByteBuffer)
+     *
+     * @since 1.5
+     */
+    public int getApplicationBufferSize();
+}
diff --git a/javax/net/ssl/SSLSessionBindingEvent.java b/javax/net/ssl/SSLSessionBindingEvent.java
new file mode 100644
index 0000000..c5cafba
--- /dev/null
+++ b/javax/net/ssl/SSLSessionBindingEvent.java
@@ -0,0 +1,93 @@
+/*
+ * 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 javax.net.ssl;
+
+import java.util.EventObject;
+
+
+/**
+ * This event is propagated to a SSLSessionBindingListener.
+ * When a listener object is bound or unbound to an SSLSession by
+ * {@link SSLSession#putValue(String, Object)}
+ * or {@link SSLSession#removeValue(String)}, objects which
+ * implement the SSLSessionBindingListener will be receive an
+ * event of this type.  The event's <code>name</code> field is the
+ * key in which the listener is being bound or unbound.
+ *
+ * @see SSLSession
+ * @see SSLSessionBindingListener
+ *
+ * @since 1.4
+ * @author Nathan Abramson
+ * @author David Brownell
+ */
+public
+class SSLSessionBindingEvent
+extends EventObject
+{
+    private static final long serialVersionUID = 3989172637106345L;
+
+    /**
+     * @serial The name to which the object is being bound or unbound
+     */
+    private String name;
+
+    /**
+     * Constructs a new SSLSessionBindingEvent.
+     *
+     * @param session the SSLSession acting as the source of the event
+     * @param name the name to which the object is being bound or unbound
+     * @exception  IllegalArgumentException  if <code>session</code> is null.
+     */
+    public SSLSessionBindingEvent(SSLSession session, String name)
+    {
+        super(session);
+        this.name = name;
+    }
+
+    /**
+     * Returns the name to which the object is being bound, or the name
+     * from which the object is being unbound.
+     *
+     * @return the name to which the object is being bound or unbound
+     */
+    public String getName()
+    {
+        return name;
+    }
+
+    /**
+     * Returns the SSLSession into which the listener is being bound or
+     * from which the listener is being unbound.
+     *
+     * @return the <code>SSLSession</code>
+     */
+    public SSLSession getSession()
+    {
+        return (SSLSession) getSource();
+    }
+}
diff --git a/javax/net/ssl/SSLSessionBindingListener.java b/javax/net/ssl/SSLSessionBindingListener.java
new file mode 100644
index 0000000..72a149f
--- /dev/null
+++ b/javax/net/ssl/SSLSessionBindingListener.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 1997, 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 javax.net.ssl;
+
+import java.util.EventListener;
+
+/**
+ * This interface is implemented by objects which want to know when
+ * they are being bound or unbound from a SSLSession.  When either event
+ * occurs via {@link SSLSession#putValue(String, Object)}
+ * or {@link SSLSession#removeValue(String)}, the event is communicated
+ * through a SSLSessionBindingEvent identifying the session.
+ *
+ * @see SSLSession
+ * @see SSLSessionBindingEvent
+ *
+ * @since 1.4
+ * @author Nathan Abramson
+ * @author David Brownell
+ */
+public
+interface SSLSessionBindingListener
+extends EventListener
+{
+    /**
+     * This is called to notify the listener that it is being bound into
+     * an SSLSession.
+     *
+     * @param event the event identifying the SSLSession into
+     *          which the listener is being bound.
+     */
+    public void valueBound(SSLSessionBindingEvent event);
+
+    /**
+     * This is called to notify the listener that it is being unbound
+     * from a SSLSession.
+     *
+     * @param event the event identifying the SSLSession from
+     *          which the listener is being unbound.
+     */
+    public void valueUnbound(SSLSessionBindingEvent event);
+}
diff --git a/javax/net/ssl/SSLSessionContext.java b/javax/net/ssl/SSLSessionContext.java
new file mode 100644
index 0000000..b6f6fb6
--- /dev/null
+++ b/javax/net/ssl/SSLSessionContext.java
@@ -0,0 +1,141 @@
+/*
+ * 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 javax.net.ssl;
+
+import java.util.Enumeration;
+
+
+/**
+ * A <code>SSLSessionContext</code> represents a set of
+ * <code>SSLSession</code>s associated with a single entity. For example,
+ * it could be associated with a server or client who participates in many
+ * sessions concurrently.
+ * <p>
+ * Not all environments will contain session contexts.
+ * <p>
+ * There are <code>SSLSessionContext</code> parameters that affect how
+ * sessions are stored:
+ * <UL>
+ *      <LI>Sessions can be set to expire after a specified
+ *      time limit.
+ *      <LI>The number of sessions that can be stored in context
+ *      can be limited.
+ * </UL>
+ * A session can be retrieved based on its session id, and all session id's
+ * in a <code>SSLSessionContext</code> can be listed.
+ *
+ * @see SSLSession
+ *
+ * @since 1.4
+ * @author Nathan Abramson
+ * @author David Brownell
+ */
+public interface SSLSessionContext {
+
+    /**
+     * Returns the <code>SSLSession</code> bound to the specified session id.
+     *
+     * @param sessionId the Session identifier
+     * @return the <code>SSLSession</code> or null if
+     * the specified session id does not refer to a valid SSLSession.
+     *
+     * @throws NullPointerException if <code>sessionId</code> is null.
+     */
+    public SSLSession getSession(byte[] sessionId);
+
+    /**
+     * Returns an Enumeration of all session id's grouped under this
+     * <code>SSLSessionContext</code>.
+     *
+     * @return an enumeration of all the Session id's
+     */
+    public Enumeration<byte[]> getIds();
+
+    /**
+     * Sets the timeout limit for <code>SSLSession</code> objects grouped
+     * under this <code>SSLSessionContext</code>.
+     * <p>
+     * If the timeout limit is set to 't' seconds, a session exceeds the
+     * timeout limit 't' seconds after its creation time.
+     * When the timeout limit is exceeded for a session, the
+     * <code>SSLSession</code> object is invalidated and future connections
+     * cannot resume or rejoin the session.
+     * A check for sessions exceeding the timeout is made immediately whenever
+     * the timeout limit is changed for this <code>SSLSessionContext</code>.
+     *
+     * @param seconds the new session timeout limit in seconds; zero means
+     *          there is no limit.
+     *
+     * @exception IllegalArgumentException if the timeout specified is {@code < 0}.
+     * @see #getSessionTimeout
+     */
+    public void setSessionTimeout(int seconds)
+                 throws IllegalArgumentException;
+
+    /**
+     * Returns the timeout limit of <code>SSLSession</code> objects grouped
+     * under this <code>SSLSessionContext</code>.
+     * <p>
+     * If the timeout limit is set to 't' seconds, a session exceeds the
+     * timeout limit 't' seconds after its creation time.
+     * When the timeout limit is exceeded for a session, the
+     * <code>SSLSession</code> object is invalidated and future connections
+     * cannot resume or rejoin the session.
+     * A check for sessions exceeding the timeout limit is made immediately
+     * whenever the timeout limit is changed for this
+     * <code>SSLSessionContext</code>.
+     *
+     * @return the session timeout limit in seconds; zero means there is no
+     * limit.
+     * @see #setSessionTimeout
+     */
+    public int getSessionTimeout();
+
+    /**
+     * Sets the size of the cache used for storing
+     * <code>SSLSession</code> objects grouped under this
+     * <code>SSLSessionContext</code>.
+     *
+     * @param size the new session cache size limit; zero means there is no
+     * limit.
+     * @exception IllegalArgumentException if the specified size is {@code < 0}.
+     * @see #getSessionCacheSize
+     */
+    public void setSessionCacheSize(int size)
+                 throws IllegalArgumentException;
+
+    /**
+     * Returns the size of the cache used for storing
+     * <code>SSLSession</code> objects grouped under this
+     * <code>SSLSessionContext</code>.
+     *
+     * @return size of the session cache; zero means there is no size limit.
+     * @see #setSessionCacheSize
+     */
+    public int getSessionCacheSize();
+
+}
diff --git a/javax/net/ssl/SSLSocket.java b/javax/net/ssl/SSLSocket.java
new file mode 100644
index 0000000..a2ba960
--- /dev/null
+++ b/javax/net/ssl/SSLSocket.java
@@ -0,0 +1,1588 @@
+/*
+ * 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 javax.net.ssl;
+
+import java.io.IOException;
+import java.net.*;
+import java.util.List;
+import java.util.function.BiFunction;
+
+
+/**
+ * This class extends <code>Socket</code>s and provides secure
+ * socket using protocols such as the "Secure
+ * Sockets Layer" (SSL) or IETF "Transport Layer Security" (TLS) protocols.
+ * <P>
+ * Such sockets are normal stream sockets, but they
+ * add a layer of security protections over the underlying network transport
+ * protocol, such as TCP.  Those protections include: <UL>
+ *
+ *      <LI> <em>Integrity Protection</em>.  SSL protects against
+ *      modification of messages by an active wiretapper.
+ *
+ *      <LI> <em>Authentication</em>.  In most modes, SSL provides
+ *      peer authentication.  Servers are usually authenticated,
+ *      and clients may be authenticated as requested by servers.
+ *
+ *      <LI> <em>Confidentiality (Privacy Protection)</em>.  In most
+ *      modes, SSL encrypts data being sent between client and server.
+ *      This protects the confidentiality of data, so that passive
+ *      wiretappers won't see sensitive data such as financial
+ *      information or personal information of many kinds.
+ *
+ *      </UL>
+ *
+ * <P>These kinds of protection are specified by a "cipher suite", which
+ * is a combination of cryptographic algorithms used by a given SSL connection.
+ * During the negotiation process, the two endpoints must agree on
+ * a ciphersuite that is available in both environments.
+ * If there is no such suite in common, no SSL connection can
+ * be established, and no data can be exchanged.
+ *
+ * <P> The cipher suite used is established by a negotiation process
+ * called "handshaking".  The goal of this
+ * process is to create or rejoin a "session", which may protect many
+ * connections over time.  After handshaking has completed, you can access
+ * session attributes by using the <em>getSession</em> method.
+ * The initial handshake on this connection can be initiated in
+ * one of three ways: <UL>
+ *
+ *      <LI> calling <code>startHandshake</code> which explicitly
+ *              begins handshakes, or
+ *      <LI> any attempt to read or write application data on
+ *              this socket causes an implicit handshake, or
+ *      <LI> a call to <code>getSession</code> tries to set up a session
+ *              if there is no currently valid session, and
+ *              an implicit handshake is done.
+ * </UL>
+ *
+ * <P>If handshaking fails for any reason, the <code>SSLSocket</code>
+ * is closed, and no further communications can be done.
+ *
+ * <P>There are two groups of cipher suites which you will need to know
+ * about when managing cipher suites: <UL>
+ *
+ *      <LI> <em>Supported</em> cipher suites:  all the suites which are
+ *      supported by the SSL implementation.  This list is reported
+ *      using <em>getSupportedCipherSuites</em>.
+ *
+ *      <LI> <em>Enabled</em> cipher suites, which may be fewer
+ *      than the full set of supported suites.  This group is
+ *      set using the <em>setEnabledCipherSuites</em> method, and
+ *      queried using the <em>getEnabledCipherSuites</em> method.
+ *      Initially, a default set of cipher suites will be enabled on
+ *      a new socket that represents the minimum suggested configuration.
+ *
+ *      </UL>
+ *
+ * <P> Implementation defaults require that only cipher
+ * suites which authenticate servers and provide confidentiality
+ * be enabled by default.
+ * Only if both sides explicitly agree to unauthenticated and/or
+ * non-private (unencrypted) communications will such a ciphersuite be
+ * selected.
+ *
+ * <P>When <code>SSLSocket</code>s are first created, no handshaking
+ * is done so that applications may first set their communication
+ * preferences:  what cipher suites to use, whether the socket should be
+ * in client or server mode, etc.
+ * However, security is always provided by the time that application data
+ * is sent over the connection.
+ *
+ * <P> You may register to receive event notification of handshake
+ * completion.  This involves
+ * the use of two additional classes.  <em>HandshakeCompletedEvent</em>
+ * objects are passed to <em>HandshakeCompletedListener</em> instances,
+ * which are registered by users of this API.
+ *
+ * <code>SSLSocket</code>s are created by <code>SSLSocketFactory</code>s,
+ * or by <code>accept</code>ing a connection from a
+ * <code>SSLServerSocket</code>.
+ *
+ * <P>A SSL socket must choose to operate in the client or server mode.
+ * This will determine who begins the handshaking process, as well
+ * as which messages should be sent by each party.  Each
+ * connection must have one client and one server, or handshaking
+ * will not progress properly.  Once the initial handshaking has started, a
+ * socket can not switch between client and server modes, even when
+ * performing renegotiations.
+ *
+ * <h3>Default configuration for different Android versions</h3>
+ * <p>{@code SSLSocket} instances obtained from default {@link SSLSocketFactory},
+ * {@link SSLServerSocketFactory}, and {@link SSLContext} are configured as follows:
+ *
+ * <style type="text/css">
+ *   tr.deprecated {
+ *     background-color: #ccc;
+ *     color: #999;
+ *     font-style: italic;
+ *   }
+ * </style>
+ *
+ * <h4>Protocols</h4>
+ *
+ * <p>Client socket:
+ * <table>
+ *     <thead>
+ *         <tr>
+ *             <th>Protocol</th>
+ *             <th>Supported (API Levels)</th>
+ *             <th>Enabled by default (API Levels)</th>
+ *         </tr>
+ *     </thead>
+ *     <tbody>
+ *         <tr class="deprecated">
+ *             <td>SSLv3</td>
+ *             <td>1&ndash;25</td>
+ *             <td>1&ndash;22</td>
+ *         </tr>
+ *         <tr>
+ *             <td>TLSv1</td>
+ *             <td>1+</td>
+ *             <td>1+</td>
+ *         </tr>
+ *         <tr>
+ *             <td>TLSv1.1</td>
+ *             <td>16+</td>
+ *             <td>20+</td>
+ *         </tr>
+ *         <tr>
+ *             <td>TLSv1.2</td>
+ *             <td>16+</td>
+ *             <td>20+</td>
+ *         </tr>
+ *         <tr>
+ *             <td>TLSv1.3</td>
+ *             <td>29+</td>
+ *             <td>29+</td>
+ *         </tr>
+ *     </tbody>
+ * </table>
+ *
+ * <p>Server socket:
+ * <table>
+ *     <thead>
+ *         <tr>
+ *             <th>Protocol</th>
+ *             <th>Supported (API Levels)</th>
+ *             <th>Enabled by default (API Levels)</th>
+ *         </tr>
+ *     </thead>
+ *     <tbody>
+ *         <tr class="deprecated">
+ *             <td>SSLv3</td>
+ *             <td>1&ndash;25</td>
+ *             <td>1&ndash;22</td>
+ *         </tr>
+ *         <tr>
+ *             <td>TLSv1</td>
+ *             <td>1+</td>
+ *             <td>1+</td>
+ *         </tr>
+ *         <tr>
+ *             <td>TLSv1.1</td>
+ *             <td>16+</td>
+ *             <td>16+</td>
+ *         </tr>
+ *         <tr>
+ *             <td>TLSv1.2</td>
+ *             <td>16+</td>
+ *             <td>16+</td>
+ *         </tr>
+ *         <tr>
+ *             <td>TLSv1.3</td>
+ *             <td>29+</td>
+ *             <td>29+</td>
+ *         </tr>
+ *     </tbody>
+ * </table>
+ *
+ * <h4>Cipher suites</h4>
+ *
+ * <p>Methods that operate with cipher suite names (for example,
+ * {@link #getSupportedCipherSuites() getSupportedCipherSuites},
+ * {@link #setEnabledCipherSuites(String[]) setEnabledCipherSuites}) have used
+ * standard names for cipher suites since API Level 9, as listed in the table
+ * below. Prior to API Level 9, non-standard (OpenSSL) names had been used (see
+ * the table following this table).
+ * <table>
+ *   <thead>
+ *     <tr>
+ *       <th>Cipher suite</th>
+ *       <th>Supported (API Levels)</th>
+ *       <th>Enabled by default (API Levels)</th>
+ *     </tr>
+ *   </thead>
+ *   <tbody>
+ *     <tr class="deprecated">
+ *       <td>SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA</td>
+ *       <td>9-22</td>
+ *       <td>9-19</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA</td>
+ *       <td>9-22</td>
+ *       <td>9-19</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>SSL_DHE_DSS_WITH_DES_CBC_SHA</td>
+ *       <td>9-22</td>
+ *       <td>9-19</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA</td>
+ *       <td>9-22</td>
+ *       <td>9-19</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA</td>
+ *       <td>9-22</td>
+ *       <td>9-19</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>SSL_DHE_RSA_WITH_DES_CBC_SHA</td>
+ *       <td>9-22</td>
+ *       <td>9-19</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA</td>
+ *       <td>9-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>SSL_DH_anon_EXPORT_WITH_RC4_40_MD5</td>
+ *       <td>9-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>SSL_DH_anon_WITH_3DES_EDE_CBC_SHA</td>
+ *       <td>9-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>SSL_DH_anon_WITH_DES_CBC_SHA</td>
+ *       <td>9-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>SSL_DH_anon_WITH_RC4_128_MD5</td>
+ *       <td>9-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>SSL_RSA_EXPORT_WITH_DES40_CBC_SHA</td>
+ *       <td>9-22</td>
+ *       <td>9-19</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>SSL_RSA_EXPORT_WITH_RC4_40_MD5</td>
+ *       <td>9-22</td>
+ *       <td>9-19</td>
+ *     </tr>
+ *     <tr>
+ *       <td>SSL_RSA_WITH_3DES_EDE_CBC_SHA</td>
+ *       <td>9+</td>
+ *       <td>9-19</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>SSL_RSA_WITH_DES_CBC_SHA</td>
+ *       <td>9-22</td>
+ *       <td>9-19</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>SSL_RSA_WITH_NULL_MD5</td>
+ *       <td>9-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>SSL_RSA_WITH_NULL_SHA</td>
+ *       <td>9-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>SSL_RSA_WITH_RC4_128_MD5</td>
+ *       <td>9-25</td>
+ *       <td>9-19</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>SSL_RSA_WITH_RC4_128_SHA</td>
+ *       <td>9-25</td>
+ *       <td>9-23</td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_AES_128_GCM_SHA256</td>
+ *       <td>29+</td>
+ *       <td>29+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_AES_256_GCM_SHA384</td>
+ *       <td>29+</td>
+ *       <td>29+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_CHACHA20_POLY1305_SHA256</td>
+ *       <td>29+</td>
+ *       <td>29+</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DHE_DSS_WITH_AES_128_CBC_SHA</td>
+ *       <td>9-22</td>
+ *       <td>9-22</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DHE_DSS_WITH_AES_128_CBC_SHA256</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DHE_DSS_WITH_AES_128_GCM_SHA256</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DHE_DSS_WITH_AES_256_CBC_SHA</td>
+ *       <td>9-22</td>
+ *       <td>11-22</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DHE_DSS_WITH_AES_256_CBC_SHA256</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DHE_DSS_WITH_AES_256_GCM_SHA384</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DHE_RSA_WITH_AES_128_CBC_SHA</td>
+ *       <td>9-25</td>
+ *       <td>9-25</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DHE_RSA_WITH_AES_128_CBC_SHA256</td>
+ *       <td>20-25</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DHE_RSA_WITH_AES_128_GCM_SHA256</td>
+ *       <td>20-25</td>
+ *       <td>20-25</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DHE_RSA_WITH_AES_256_CBC_SHA</td>
+ *       <td>9-25</td>
+ *       <td>11-25</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DHE_RSA_WITH_AES_256_CBC_SHA256</td>
+ *       <td>20-25</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DHE_RSA_WITH_AES_256_GCM_SHA384</td>
+ *       <td>20-25</td>
+ *       <td>20-25</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DH_anon_WITH_AES_128_CBC_SHA</td>
+ *       <td>9-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DH_anon_WITH_AES_128_CBC_SHA256</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DH_anon_WITH_AES_128_GCM_SHA256</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DH_anon_WITH_AES_256_CBC_SHA</td>
+ *       <td>9-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DH_anon_WITH_AES_256_CBC_SHA256</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_DH_anon_WITH_AES_256_GCM_SHA384</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA</td>
+ *       <td>11-22</td>
+ *       <td>11-19</td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA</td>
+ *       <td>11+</td>
+ *       <td>11+</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256</td>
+ *       <td>20-28</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256</td>
+ *       <td>20+</td>
+ *       <td>20+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA</td>
+ *       <td>11+</td>
+ *       <td>11+</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384</td>
+ *       <td>20-28</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384</td>
+ *       <td>20+</td>
+ *       <td>20+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256</td>
+ *       <td>24+</td>
+ *       <td>24+</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDHE_ECDSA_WITH_NULL_SHA</td>
+ *       <td>11-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDHE_ECDSA_WITH_RC4_128_SHA</td>
+ *       <td>11-25</td>
+ *       <td>11-23</td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA</td>
+ *       <td>21+</td>
+ *       <td>21+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA</td>
+ *       <td>21+</td>
+ *       <td>21+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256</td>
+ *       <td>24+</td>
+ *       <td>24+</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA</td>
+ *       <td>11-22</td>
+ *       <td>11-19</td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA</td>
+ *       <td>11+</td>
+ *       <td>11+</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256</td>
+ *       <td>20-28</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256</td>
+ *       <td>20+</td>
+ *       <td>20+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA</td>
+ *       <td>11+</td>
+ *       <td>11+</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384</td>
+ *       <td>20-28</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384</td>
+ *       <td>20+</td>
+ *       <td>20+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256</td>
+ *       <td>24+</td>
+ *       <td>24+</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDHE_RSA_WITH_NULL_SHA</td>
+ *       <td>11-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDHE_RSA_WITH_RC4_128_SHA</td>
+ *       <td>11-25</td>
+ *       <td>11-23</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA</td>
+ *       <td>11-22</td>
+ *       <td>11-19</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA</td>
+ *       <td>11-22</td>
+ *       <td>11-19</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA</td>
+ *       <td>11-22</td>
+ *       <td>11-19</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_ECDSA_WITH_NULL_SHA</td>
+ *       <td>11-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_ECDSA_WITH_RC4_128_SHA</td>
+ *       <td>11-22</td>
+ *       <td>11-19</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA</td>
+ *       <td>11-22</td>
+ *       <td>11-19</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_RSA_WITH_AES_128_CBC_SHA</td>
+ *       <td>11-22</td>
+ *       <td>11-19</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_RSA_WITH_AES_256_CBC_SHA</td>
+ *       <td>11-22</td>
+ *       <td>11-19</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_RSA_WITH_NULL_SHA</td>
+ *       <td>11-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_RSA_WITH_RC4_128_SHA</td>
+ *       <td>11-22</td>
+ *       <td>11-19</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA</td>
+ *       <td>11-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_anon_WITH_AES_128_CBC_SHA</td>
+ *       <td>11-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_anon_WITH_AES_256_CBC_SHA</td>
+ *       <td>11-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_anon_WITH_NULL_SHA</td>
+ *       <td>11-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_ECDH_anon_WITH_RC4_128_SHA</td>
+ *       <td>11-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_EMPTY_RENEGOTIATION_INFO_SCSV</td>
+ *       <td>11+</td>
+ *       <td>11+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_FALLBACK_SCSV</td>
+ *       <td>21+</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_PSK_WITH_3DES_EDE_CBC_SHA</td>
+ *       <td>21-22</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_PSK_WITH_AES_128_CBC_SHA</td>
+ *       <td>21+</td>
+ *       <td>21+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_PSK_WITH_AES_256_CBC_SHA</td>
+ *       <td>21+</td>
+ *       <td>21+</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_PSK_WITH_RC4_128_SHA</td>
+ *       <td>21-25</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_RSA_WITH_AES_128_CBC_SHA</td>
+ *       <td>9+</td>
+ *       <td>9+</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_RSA_WITH_AES_128_CBC_SHA256</td>
+ *       <td>20-28</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_RSA_WITH_AES_128_GCM_SHA256</td>
+ *       <td>20+</td>
+ *       <td>20+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_RSA_WITH_AES_256_CBC_SHA</td>
+ *       <td>9+</td>
+ *       <td>11+</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_RSA_WITH_AES_256_CBC_SHA256</td>
+ *       <td>20-28</td>
+ *       <td></td>
+ *     </tr>
+ *     <tr>
+ *       <td>TLS_RSA_WITH_AES_256_GCM_SHA384</td>
+ *       <td>20+</td>
+ *       <td>20+</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>TLS_RSA_WITH_NULL_SHA256</td>
+ *       <td>20-22</td>
+ *       <td></td>
+ *     </tr>
+ *   </tbody>
+ * </table>
+ *
+ * <p><em>NOTE</em>: PSK cipher suites are enabled by default only if the {@code SSLContext} through
+ * which the socket was created has been initialized with a {@code PSKKeyManager}.
+ *
+ * <p>API Levels 1 to 8 use OpenSSL names for cipher suites. The table below
+ * lists these OpenSSL names and their corresponding standard names used in API
+ * Levels 9 and newer.
+ * <table>
+ *     <thead>
+ *         <tr>
+ *             <th>OpenSSL cipher suite</th>
+ *             <th>Standard cipher suite</th>
+ *             <th>Supported (API Levels)</th>
+ *             <th>Enabled by default (API Levels)</th>
+ *         </tr>
+ *     </thead>
+ *
+ *     <tbody>
+ *         <tr>
+ *             <td>AES128-SHA</td>
+ *             <td>TLS_RSA_WITH_AES_128_CBC_SHA</td>
+ *             <td>1+</td>
+ *             <td>1+</td>
+ *         </tr>
+ *         <tr>
+ *             <td>AES256-SHA</td>
+ *             <td>TLS_RSA_WITH_AES_256_CBC_SHA</td>
+ *             <td>1+</td>
+ *             <td>1&ndash;8, 11+</td>
+ *         </tr>
+ *         <tr>
+ *             <td>DES-CBC-MD5</td>
+ *             <td>SSL_CK_DES_64_CBC_WITH_MD5</td>
+ *             <td>1&ndash;8</td>
+ *             <td>1&ndash;8</td>
+ *         </tr>
+ *         <tr class="deprecated">
+ *             <td>DES-CBC-SHA</td>
+ *             <td>SSL_RSA_WITH_DES_CBC_SHA</td>
+ *             <td>1&ndash;22</td>
+ *             <td>1&ndash;19</td>
+ *         </tr>
+ *         <tr>
+ *             <td>DES-CBC3-MD5</td>
+ *             <td>SSL_CK_DES_192_EDE3_CBC_WITH_MD5</td>
+ *             <td>1&ndash;8</td>
+ *             <td>1&ndash;8</td>
+ *         </tr>
+ *         <tr>
+ *             <td>DES-CBC3-SHA</td>
+ *             <td>SSL_RSA_WITH_3DES_EDE_CBC_SHA</td>
+ *             <td>1+</td>
+ *             <td>1&ndash;19</td>
+ *         </tr>
+ *         <tr class="deprecated">
+ *             <td>DHE-DSS-AES128-SHA</td>
+ *             <td>TLS_DHE_DSS_WITH_AES_128_CBC_SHA</td>
+ *             <td>1&ndash;22</td>
+ *             <td>1&ndash;22</td>
+ *         </tr>
+ *         <tr class="deprecated">
+ *             <td>DHE-DSS-AES256-SHA</td>
+ *             <td>TLS_DHE_DSS_WITH_AES_256_CBC_SHA</td>
+ *             <td>1&ndash;22</td>
+ *             <td>1&ndash;8, 11&ndash;22</td>
+ *         </tr>
+ *         <tr>
+ *             <td>DHE-RSA-AES128-SHA</td>
+ *             <td>TLS_DHE_RSA_WITH_AES_128_CBC_SHA</td>
+ *             <td>1+</td>
+ *             <td>1+</td>
+ *         </tr>
+ *         <tr>
+ *             <td>DHE-RSA-AES256-SHA</td>
+ *             <td>TLS_DHE_RSA_WITH_AES_256_CBC_SHA</td>
+ *             <td>1+</td>
+ *             <td>1&ndash;8, 11+</td>
+ *         </tr>
+ *         <tr class="deprecated">
+ *             <td>EDH-DSS-DES-CBC-SHA</td>
+ *             <td>SSL_DHE_DSS_WITH_DES_CBC_SHA</td>
+ *             <td>1&ndash;22</td>
+ *             <td>1&ndash;19</td>
+ *         </tr>
+ *         <tr class="deprecated">
+ *             <td>EDH-DSS-DES-CBC3-SHA</td>
+ *             <td>SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA</td>
+ *             <td>1&ndash;22</td>
+ *             <td>1&ndash;19</td>
+ *         </tr>
+ *         <tr class="deprecated">
+ *             <td>EDH-RSA-DES-CBC-SHA</td>
+ *             <td>SSL_DHE_RSA_WITH_DES_CBC_SHA</td>
+ *             <td>1&ndash;22</td>
+ *             <td>1&ndash;19</td>
+ *         </tr>
+ *         <tr class="deprecated">
+ *             <td>EDH-RSA-DES-CBC3-SHA</td>
+ *             <td>SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA</td>
+ *             <td>1&ndash;22</td>
+ *             <td>1&ndash;19</td>
+ *         </tr>
+ *         <tr class="deprecated">
+ *             <td>EXP-DES-CBC-SHA</td>
+ *             <td>SSL_RSA_EXPORT_WITH_DES40_CBC_SHA</td>
+ *             <td>1&ndash;22</td>
+ *             <td>1&ndash;19</td>
+ *         </tr>
+ *         <tr class="deprecated">
+ *             <td>EXP-EDH-DSS-DES-CBC-SHA</td>
+ *             <td>SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA</td>
+ *             <td>1&ndash;22</td>
+ *             <td>1&ndash;19</td>
+ *         </tr>
+ *         <tr class="deprecated">
+ *             <td>EXP-EDH-RSA-DES-CBC-SHA</td>
+ *             <td>SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA</td>
+ *             <td>1&ndash;22</td>
+ *             <td>1&ndash;19</td>
+ *         </tr>
+ *         <tr>
+ *             <td>EXP-RC2-CBC-MD5</td>
+ *             <td>SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5</td>
+ *             <td>1&ndash;8</td>
+ *             <td>1&ndash;8</td>
+ *         </tr>
+ *         <tr class="deprecated">
+ *             <td>EXP-RC4-MD5</td>
+ *             <td>SSL_RSA_EXPORT_WITH_RC4_40_MD5</td>
+ *             <td>1&ndash;22</td>
+ *             <td>1&ndash;19</td>
+ *         </tr>
+ *         <tr>
+ *             <td>RC2-CBC-MD5</td>
+ *             <td>SSL_CK_RC2_128_CBC_WITH_MD5</td>
+ *             <td>1&ndash;8</td>
+ *             <td>1&ndash;8</td>
+ *         </tr>
+ *         <tr class="deprecated">
+ *             <td>RC4-MD5</td>
+ *             <td>SSL_RSA_WITH_RC4_128_MD5</td>
+ *             <td>1&ndash;25</td>
+ *             <td>1&ndash;19</td>
+ *         </tr>
+ *         <tr class="deprecated">
+ *             <td>RC4-SHA</td>
+ *             <td>SSL_RSA_WITH_RC4_128_SHA</td>
+ *             <td>1&ndash;25</td>
+ *             <td>1&ndash;23</td>
+ *         </tr>
+ *     </tbody>
+ * </table>
+ *
+ * @see java.net.Socket
+ * @see SSLServerSocket
+ * @see SSLSocketFactory
+ *
+ * @since 1.4
+ * @author David Brownell
+ */
+public abstract class SSLSocket extends Socket
+{
+    /**
+     * Used only by subclasses.
+     * Constructs an uninitialized, unconnected TCP socket.
+     */
+    protected SSLSocket()
+        { super(); }
+
+
+    /**
+     * Used only by subclasses.
+     * Constructs a TCP connection to a named host at a specified port.
+     * This acts as the SSL client.
+     * <p>
+     * If there is a security manager, its <code>checkConnect</code>
+     * method is called with the host address and <code>port</code>
+     * as its arguments. This could result in a SecurityException.
+     *
+     * @param host name of the host with which to connect, or
+     *        <code>null</code> for the loopback address.
+     * @param port number of the server's port
+     * @throws IOException if an I/O error occurs when creating the socket
+     * @throws SecurityException if a security manager exists and its
+     *         <code>checkConnect</code> method doesn't allow the operation.
+     * @throws UnknownHostException if the host is not known
+     * @throws IllegalArgumentException if the port parameter is outside the
+     *         specified range of valid port values, which is between 0 and
+     *         65535, inclusive.
+     * @see SecurityManager#checkConnect
+     */
+    protected SSLSocket(String host, int port)
+    throws IOException, UnknownHostException
+        { super(host, port); }
+
+
+    /**
+     * Used only by subclasses.
+     * Constructs a TCP connection to a server at a specified address
+     * and port.  This acts as the SSL client.
+     * <p>
+     * If there is a security manager, its <code>checkConnect</code>
+     * method is called with the host address and <code>port</code>
+     * as its arguments. This could result in a SecurityException.
+     *
+     * @param address the server's host
+     * @param port its port
+     * @throws IOException if an I/O error occurs when creating the socket
+     * @throws SecurityException if a security manager exists and its
+     *         <code>checkConnect</code> method doesn't allow the operation.
+     * @throws IllegalArgumentException if the port parameter is outside the
+     *         specified range of valid port values, which is between 0 and
+     *         65535, inclusive.
+     * @throws NullPointerException if <code>address</code> is null.
+     * @see SecurityManager#checkConnect
+     */
+    protected SSLSocket(InetAddress address, int port)
+    throws IOException
+        { super(address, port); }
+
+
+    /**
+     * Used only by subclasses.
+     * Constructs an SSL connection to a named host at a specified port,
+     * binding the client side of the connection a given address and port.
+     * This acts as the SSL client.
+     * <p>
+     * If there is a security manager, its <code>checkConnect</code>
+     * method is called with the host address and <code>port</code>
+     * as its arguments. This could result in a SecurityException.
+     *
+     * @param host name of the host with which to connect, or
+     *        <code>null</code> for the loopback address.
+     * @param port number of the server's port
+     * @param clientAddress the client's address the socket is bound to, or
+     *        <code>null</code> for the <code>anyLocal</code> address.
+     * @param clientPort the client's port the socket is bound to, or
+     *        <code>zero</code> for a system selected free port.
+     * @throws IOException if an I/O error occurs when creating the socket
+     * @throws SecurityException if a security manager exists and its
+     *         <code>checkConnect</code> method doesn't allow the operation.
+     * @throws UnknownHostException if the host is not known
+     * @throws IllegalArgumentException if the port parameter or clientPort
+     *         parameter is outside the specified range of valid port values,
+     *         which is between 0 and 65535, inclusive.
+     * @see SecurityManager#checkConnect
+     */
+    protected SSLSocket(String host, int port,
+        InetAddress clientAddress, int clientPort)
+    throws IOException, UnknownHostException
+        { super(host, port, clientAddress, clientPort); }
+
+
+    /**
+     * Used only by subclasses.
+     * Constructs an SSL connection to a server at a specified address
+     * and TCP port, binding the client side of the connection a given
+     * address and port.  This acts as the SSL client.
+     * <p>
+     * If there is a security manager, its <code>checkConnect</code>
+     * method is called with the host address and <code>port</code>
+     * as its arguments. This could result in a SecurityException.
+     *
+     * @param address the server's host
+     * @param port its port
+     * @param clientAddress the client's address the socket is bound to, or
+     *        <code>null</code> for the <code>anyLocal</code> address.
+     * @param clientPort the client's port the socket is bound to, or
+     *        <code>zero</code> for a system selected free port.
+     * @throws IOException if an I/O error occurs when creating the socket
+     * @throws SecurityException if a security manager exists and its
+     *         <code>checkConnect</code> method doesn't allow the operation.
+     * @throws IllegalArgumentException if the port parameter or clientPort
+     *         parameter is outside the specified range of valid port values,
+     *         which is between 0 and 65535, inclusive.
+     * @throws NullPointerException if <code>address</code> is null.
+     * @see SecurityManager#checkConnect
+     */
+    protected SSLSocket(InetAddress address, int port,
+        InetAddress clientAddress, int clientPort)
+    throws IOException
+        { super(address, port, clientAddress, clientPort); }
+
+
+    // Android-changed: Added warnings about misuse
+    /**
+     * Returns the names of the cipher suites which could be enabled for use
+     * on this connection.  Normally, only a subset of these will actually
+     * be enabled by default, since this list may include cipher suites which
+     * do not meet quality of service requirements for those defaults.  Such
+     * cipher suites might be useful in specialized applications.
+     *
+     * <p class="caution">Applications should not blindly enable all supported
+     * cipher suites.  The supported cipher suites can include signaling cipher suite
+     * values that can cause connection problems if enabled inappropriately.
+     *
+     * <p>The proper way to use this method is to either check if a specific cipher
+     * suite is supported via {@code Arrays.asList(getSupportedCipherSuites()).contains(...)}
+     * or to filter a desired list of cipher suites to only the supported ones via
+     * {@code desiredSuiteSet.retainAll(Arrays.asList(getSupportedCipherSuites()))}.
+     *
+     * @return an array of cipher suite names
+     * @see #getEnabledCipherSuites()
+     * @see #setEnabledCipherSuites(String [])
+     */
+    public abstract String [] getSupportedCipherSuites();
+
+
+    /**
+     * Returns the names of the SSL cipher suites which are currently
+     * enabled for use on this connection.  When an SSLSocket is first
+     * created, all enabled cipher suites support a minimum quality of
+     * service.  Thus, in some environments this value might be empty.
+     * <P>
+     * Even if a suite has been enabled, it might never be used.  (For
+     * example, the peer does not support it, the requisite certificates
+     * (and private keys) for the suite are not available, or an
+     * anonymous suite is enabled but authentication is required.
+     *
+     * @return an array of cipher suite names
+     * @see #getSupportedCipherSuites()
+     * @see #setEnabledCipherSuites(String [])
+     */
+    public abstract String [] getEnabledCipherSuites();
+
+
+    /**
+     * Sets the cipher suites enabled for use on this connection.
+     * <P>
+     * Each cipher suite in the <code>suites</code> parameter must have
+     * been listed by getSupportedCipherSuites(), or the method will
+     * fail.  Following a successful call to this method, only suites
+     * listed in the <code>suites</code> parameter are enabled for use.
+     * <P>
+     * See {@link #getEnabledCipherSuites()} for more information
+     * on why a specific ciphersuite may never be used on a connection.
+     *
+     * @param suites Names of all the cipher suites to enable
+     * @throws IllegalArgumentException when one or more of the ciphers
+     *          named by the parameter is not supported, or when the
+     *          parameter is null.
+     * @see #getSupportedCipherSuites()
+     * @see #getEnabledCipherSuites()
+     */
+    public abstract void setEnabledCipherSuites(String suites []);
+
+
+    /**
+     * Returns the names of the protocols which could be enabled for use
+     * on an SSL connection.
+     *
+     * @return an array of protocols supported
+     */
+    public abstract String [] getSupportedProtocols();
+
+
+    /**
+     * Returns the names of the protocol versions which are currently
+     * enabled for use on this connection.
+     * @see #setEnabledProtocols(String [])
+     * @return an array of protocols
+     */
+    public abstract String [] getEnabledProtocols();
+
+
+    // Android-added: Added paragraph about contiguous protocols.
+    /**
+     * Sets the protocol versions enabled for use on this connection.
+     * <P>
+     * The protocols must have been listed by
+     * <code>getSupportedProtocols()</code> as being supported.
+     * Following a successful call to this method, only protocols listed
+     * in the <code>protocols</code> parameter are enabled for use.
+     * <p>
+     * Because of the way the protocol version is negotiated, connections
+     * will only be able to use a member of the lowest set of contiguous
+     * enabled protocol versions.  For example, enabling TLSv1.2 and TLSv1
+     * will result in connections only being able to use TLSv1.
+     *
+     * @param protocols Names of all the protocols to enable.
+     * @throws IllegalArgumentException when one or more of
+     *            the protocols named by the parameter is not supported or
+     *            when the protocols parameter is null.
+     * @see #getEnabledProtocols()
+     */
+    public abstract void setEnabledProtocols(String protocols[]);
+
+
+    /**
+     * Returns the SSL Session in use by this connection.  These can
+     * be long lived, and frequently correspond to an entire login session
+     * for some user.  The session specifies a particular cipher suite
+     * which is being actively used by all connections in that session,
+     * as well as the identities of the session's client and server.
+     * <P>
+     * This method will initiate the initial handshake if
+     * necessary and then block until the handshake has been
+     * established.
+     * <P>
+     * If an error occurs during the initial handshake, this method
+     * returns an invalid session object which reports an invalid
+     * cipher suite of "SSL_NULL_WITH_NULL_NULL".
+     *
+     * @return the <code>SSLSession</code>
+     */
+    public abstract SSLSession getSession();
+
+
+    /**
+     * Returns the {@code SSLSession} being constructed during a SSL/TLS
+     * handshake.
+     * <p>
+     * TLS protocols may negotiate parameters that are needed when using
+     * an instance of this class, but before the {@code SSLSession} has
+     * been completely initialized and made available via {@code getSession}.
+     * For example, the list of valid signature algorithms may restrict
+     * the type of certificates that can used during TrustManager
+     * decisions, or the maximum TLS fragment packet sizes can be
+     * resized to better support the network environment.
+     * <p>
+     * This method provides early access to the {@code SSLSession} being
+     * constructed.  Depending on how far the handshake has progressed,
+     * some data may not yet be available for use.  For example, if a
+     * remote server will be sending a Certificate chain, but that chain
+     * has yet not been processed, the {@code getPeerCertificates}
+     * method of {@code SSLSession} will throw a
+     * SSLPeerUnverifiedException.  Once that chain has been processed,
+     * {@code getPeerCertificates} will return the proper value.
+     * <p>
+     * Unlike {@link #getSession()}, this method does not initiate the
+     * initial handshake and does not block until handshaking is
+     * complete.
+     *
+     * @see SSLEngine
+     * @see SSLSession
+     * @see ExtendedSSLSession
+     * @see X509ExtendedKeyManager
+     * @see X509ExtendedTrustManager
+     *
+     * @return null if this instance is not currently handshaking, or
+     *         if the current handshake has not progressed far enough to
+     *         create a basic SSLSession.  Otherwise, this method returns the
+     *         {@code SSLSession} currently being negotiated.
+     * @throws UnsupportedOperationException if the underlying provider
+     *         does not implement the operation.
+     *
+     * @since 1.7
+     */
+    public SSLSession getHandshakeSession() {
+        throw new UnsupportedOperationException();
+    }
+
+
+    /**
+     * Registers an event listener to receive notifications that an
+     * SSL handshake has completed on this connection.
+     *
+     * @param listener the HandShake Completed event listener
+     * @see #startHandshake()
+     * @see #removeHandshakeCompletedListener(HandshakeCompletedListener)
+     * @throws IllegalArgumentException if the argument is null.
+     */
+    public abstract void addHandshakeCompletedListener(
+        HandshakeCompletedListener listener);
+
+
+    /**
+     * Removes a previously registered handshake completion listener.
+     *
+     * @param listener the HandShake Completed event listener
+     * @throws IllegalArgumentException if the listener is not registered,
+     * or the argument is null.
+     * @see #addHandshakeCompletedListener(HandshakeCompletedListener)
+     */
+    public abstract void removeHandshakeCompletedListener(
+        HandshakeCompletedListener listener);
+
+
+    /**
+     * Starts an SSL handshake on this connection.  Common reasons include
+     * a need to use new encryption keys, to change cipher suites, or to
+     * initiate a new session.  To force complete reauthentication, the
+     * current session could be invalidated before starting this handshake.
+     *
+     * <P> If data has already been sent on the connection, it continues
+     * to flow during this handshake.  When the handshake completes, this
+     * will be signaled with an event.
+     *
+     * This method is synchronous for the initial handshake on a connection
+     * and returns when the negotiated handshake is complete. Some
+     * protocols may not support multiple handshakes on an existing socket
+     * and may throw an IOException.
+     *
+     * @throws IOException on a network level error
+     * @see #addHandshakeCompletedListener(HandshakeCompletedListener)
+     */
+    public abstract void startHandshake() throws IOException;
+
+
+    /**
+     * Configures the socket to use client (or server) mode when
+     * handshaking.
+     * <P>
+     * This method must be called before any handshaking occurs.
+     * Once handshaking has begun, the mode can not be reset for the
+     * life of this socket.
+     * <P>
+     * Servers normally authenticate themselves, and clients
+     * are not required to do so.
+     *
+     * @param mode true if the socket should start its handshaking
+     *          in "client" mode
+     * @throws IllegalArgumentException if a mode change is attempted
+     *          after the initial handshake has begun.
+     * @see #getUseClientMode()
+     */
+    public abstract void setUseClientMode(boolean mode);
+
+
+    /**
+     * Returns true if the socket is set to use client mode when
+     * handshaking.
+     *
+     * @return true if the socket should do handshaking
+     *          in "client" mode
+     * @see #setUseClientMode(boolean)
+     */
+    public abstract boolean getUseClientMode();
+
+
+    /**
+     * Configures the socket to <i>require</i> client authentication.  This
+     * option is only useful for sockets in the server mode.
+     * <P>
+     * A socket's client authentication setting is one of the following:
+     * <ul>
+     * <li> client authentication required
+     * <li> client authentication requested
+     * <li> no client authentication desired
+     * </ul>
+     * <P>
+     * Unlike {@link #setWantClientAuth(boolean)}, if this option is set and
+     * the client chooses not to provide authentication information
+     * about itself, <i>the negotiations will stop and the connection
+     * will be dropped</i>.
+     * <P>
+     * Calling this method overrides any previous setting made by
+     * this method or {@link #setWantClientAuth(boolean)}.
+     *
+     * @param   need set to true if client authentication is required,
+     *          or false if no client authentication is desired.
+     * @see #getNeedClientAuth()
+     * @see #setWantClientAuth(boolean)
+     * @see #getWantClientAuth()
+     * @see #setUseClientMode(boolean)
+     */
+    public abstract void setNeedClientAuth(boolean need);
+
+
+    /**
+     * Returns true if the socket will <i>require</i> client authentication.
+     * This option is only useful to sockets in the server mode.
+     *
+     * @return  true if client authentication is required,
+     *          or false if no client authentication is desired.
+     * @see #setNeedClientAuth(boolean)
+     * @see #setWantClientAuth(boolean)
+     * @see #getWantClientAuth()
+     * @see #setUseClientMode(boolean)
+     */
+    public abstract boolean getNeedClientAuth();
+
+
+    /**
+     * Configures the socket to <i>request</i> client authentication.
+     * This option is only useful for sockets in the server mode.
+     * <P>
+     * A socket's client authentication setting is one of the following:
+     * <ul>
+     * <li> client authentication required
+     * <li> client authentication requested
+     * <li> no client authentication desired
+     * </ul>
+     * <P>
+     * Unlike {@link #setNeedClientAuth(boolean)}, if this option is set and
+     * the client chooses not to provide authentication information
+     * about itself, <i>the negotiations will continue</i>.
+     * <P>
+     * Calling this method overrides any previous setting made by
+     * this method or {@link #setNeedClientAuth(boolean)}.
+     *
+     * @param   want set to true if client authentication is requested,
+     *          or false if no client authentication is desired.
+     * @see #getWantClientAuth()
+     * @see #setNeedClientAuth(boolean)
+     * @see #getNeedClientAuth()
+     * @see #setUseClientMode(boolean)
+     */
+    public abstract void setWantClientAuth(boolean want);
+
+
+    /**
+     * Returns true if the socket will <i>request</i> client authentication.
+     * This option is only useful for sockets in the server mode.
+     *
+     * @return  true if client authentication is requested,
+     *          or false if no client authentication is desired.
+     * @see #setNeedClientAuth(boolean)
+     * @see #getNeedClientAuth()
+     * @see #setWantClientAuth(boolean)
+     * @see #setUseClientMode(boolean)
+     */
+    public abstract boolean getWantClientAuth();
+
+
+    /**
+     * Controls whether new SSL sessions may be established by this socket.
+     * If session creations are not allowed, and there are no
+     * existing sessions to resume, there will be no successful
+     * handshaking.
+     *
+     * @param flag true indicates that sessions may be created; this
+     *          is the default.  false indicates that an existing session
+     *          must be resumed
+     * @see #getEnableSessionCreation()
+     */
+    public abstract void setEnableSessionCreation(boolean flag);
+
+
+    /**
+     * Returns true if new SSL sessions may be established by this socket.
+     *
+     * @return true indicates that sessions may be created; this
+     *          is the default.  false indicates that an existing session
+     *          must be resumed
+     * @see #setEnableSessionCreation(boolean)
+     */
+    public abstract boolean getEnableSessionCreation();
+
+    /**
+     * Returns the SSLParameters in effect for this SSLSocket.
+     * The ciphersuites and protocols of the returned SSLParameters
+     * are always non-null.
+     *
+     * @return the SSLParameters in effect for this SSLSocket.
+     * @since 1.6
+     */
+    public SSLParameters getSSLParameters() {
+        SSLParameters params = new SSLParameters();
+        params.setCipherSuites(getEnabledCipherSuites());
+        params.setProtocols(getEnabledProtocols());
+        if (getNeedClientAuth()) {
+            params.setNeedClientAuth(true);
+        } else if (getWantClientAuth()) {
+            params.setWantClientAuth(true);
+        }
+        return params;
+    }
+
+    /**
+     * Applies SSLParameters to this socket.
+     *
+     * <p>This means:
+     * <ul>
+     * <li>If {@code params.getCipherSuites()} is non-null,
+     *   {@code setEnabledCipherSuites()} is called with that value.</li>
+     * <li>If {@code params.getProtocols()} is non-null,
+     *   {@code setEnabledProtocols()} is called with that value.</li>
+     * <li>If {@code params.getNeedClientAuth()} or
+     *   {@code params.getWantClientAuth()} return {@code true},
+     *   {@code setNeedClientAuth(true)} and
+     *   {@code setWantClientAuth(true)} are called, respectively;
+     *   otherwise {@code setWantClientAuth(false)} is called.</li>
+     * <li>If {@code params.getServerNames()} is non-null, the socket will
+     *   configure its server names with that value.</li>
+     * <li>If {@code params.getSNIMatchers()} is non-null, the socket will
+     *   configure its SNI matchers with that value.</li>
+     * </ul>
+     *
+     * @param params the parameters
+     * @throws IllegalArgumentException if the setEnabledCipherSuites() or
+     *    the setEnabledProtocols() call fails
+     * @since 1.6
+     */
+    public void setSSLParameters(SSLParameters params) {
+        String[] s;
+        s = params.getCipherSuites();
+        if (s != null) {
+            setEnabledCipherSuites(s);
+        }
+        s = params.getProtocols();
+        if (s != null) {
+            setEnabledProtocols(s);
+        }
+        if (params.getNeedClientAuth()) {
+            setNeedClientAuth(true);
+        } else if (params.getWantClientAuth()) {
+            setWantClientAuth(true);
+        } else {
+            setWantClientAuth(false);
+        }
+    }
+
+    // BEGIN Android-added: Add ALPN-related methods from OpenJDK 9.
+    // Also removed references to DTLS in documentation; Android doesn't support DTLS.
+    /**
+     * Returns the most recent application protocol value negotiated for this
+     * connection.
+     * <p>
+     * If supported by the underlying SSL/TLS implementation,
+     * application name negotiation mechanisms such as <a
+     * href="http://www.ietf.org/rfc/rfc7301.txt"> RFC 7301 </a>, the
+     * Application-Layer Protocol Negotiation (ALPN), can negotiate
+     * application-level values between peers.
+     * <p>
+     * @implSpec
+     * The implementation in this class throws
+     * {@code UnsupportedOperationException} and performs no other action.
+     *
+     * @return null if it has not yet been determined if application
+     *         protocols might be used for this connection, an empty
+     *         {@code String} if application protocols values will not
+     *         be used, or a non-empty application protocol {@code String}
+     *         if a value was successfully negotiated.
+     * @throws UnsupportedOperationException if the underlying provider
+     *         does not implement the operation.
+     * @since 9
+     */
+    public String getApplicationProtocol() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Returns the application protocol value negotiated on a SSL/TLS
+     * handshake currently in progress.
+     * <p>
+     * Like {@link #getHandshakeSession()},
+     * a connection may be in the middle of a handshake. The
+     * application protocol may or may not yet be available.
+     * <p>
+     * @implSpec
+     * The implementation in this class throws
+     * {@code UnsupportedOperationException} and performs no other action.
+     *
+     * @return null if it has not yet been determined if application
+     *         protocols might be used for this handshake, an empty
+     *         {@code String} if application protocols values will not
+     *         be used, or a non-empty application protocol {@code String}
+     *         if a value was successfully negotiated.
+     * @throws UnsupportedOperationException if the underlying provider
+     *         does not implement the operation.
+     * @since 9
+     */
+    public String getHandshakeApplicationProtocol() {
+        throw new UnsupportedOperationException();
+    }
+
+
+    /**
+     * Registers a callback function that selects an application protocol
+     * value for a SSL/TLS handshake.
+     * The function overrides any values supplied using
+     * {@link SSLParameters#setApplicationProtocols
+     * SSLParameters.setApplicationProtocols} and it supports the following
+     * type parameters:
+     * <blockquote>
+     * <dl>
+     * <dt> {@code SSLSocket}
+     * <dd> The function's first argument allows the current {@code SSLSocket}
+     *      to be inspected, including the handshake session and configuration
+     *      settings.
+     * <dt> {@code List<String>}
+     * <dd> The function's second argument lists the application protocol names
+     *      advertised by the TLS peer.
+     * <dt> {@code String}
+     * <dd> The function's result is an application protocol name, or null to
+     *      indicate that none of the advertised names are acceptable.
+     *      If the return value is an empty {@code String} then application
+     *      protocol indications will not be used.
+     *      If the return value is null (no value chosen) or is a value that
+     *      was not advertised by the peer, the underlying protocol will
+     *      determine what action to take. (For example, ALPN will send a
+     *      "no_application_protocol" alert and terminate the connection.)
+     * </dl>
+     * </blockquote>
+     *
+     * For example, the following call registers a callback function that
+     * examines the TLS handshake parameters and selects an application protocol
+     * name:
+     * <pre>{@code
+     *     serverSocket.setHandshakeApplicationProtocolSelector(
+     *         (serverSocket, clientProtocols) -> {
+     *             SSLSession session = serverSocket.getHandshakeSession();
+     *             return chooseApplicationProtocol(
+     *                 serverSocket,
+     *                 clientProtocols,
+     *                 session.getProtocol(),
+     *                 session.getCipherSuite());
+     *         });
+     * }</pre>
+     *
+     * @apiNote
+     * This method should be called by TLS server applications before the TLS
+     * handshake begins. Also, this {@code SSLSocket} should be configured with
+     * parameters that are compatible with the application protocol selected by
+     * the callback function. For example, enabling a poor choice of cipher
+     * suites could result in no suitable application protocol.
+     * See {@link SSLParameters}.
+     *
+     * @implSpec
+     * The implementation in this class throws
+     * {@code UnsupportedOperationException} and performs no other action.
+     *
+     * @param selector the callback function, or null to de-register.
+     * @throws UnsupportedOperationException if the underlying provider
+     *         does not implement the operation.
+     * @since 9
+     */
+    public void setHandshakeApplicationProtocolSelector(
+            BiFunction<SSLSocket, List<String>, String> selector) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Retrieves the callback function that selects an application protocol
+     * value during a SSL/TLS handshake.
+     * See {@link #setHandshakeApplicationProtocolSelector
+     * setHandshakeApplicationProtocolSelector}
+     * for the function's type parameters.
+     *
+     * @implSpec
+     * The implementation in this class throws
+     * {@code UnsupportedOperationException} and performs no other action.
+     *
+     * @return the callback function, or null if none has been set.
+     * @throws UnsupportedOperationException if the underlying provider
+     *         does not implement the operation.
+     * @since 9
+     */
+    public BiFunction<SSLSocket, List<String>, String>
+            getHandshakeApplicationProtocolSelector() {
+        throw new UnsupportedOperationException();
+    }
+    // END Android-added: Add ALPN-related methods from OpenJDK 9.
+
+    // Android-added: Make toString explicit that this is an SSLSocket (http://b/6602228)
+    @Override
+    public String toString() {
+        return "SSL" + super.toString();
+    }
+}
diff --git a/javax/net/ssl/SSLSocketFactory.java b/javax/net/ssl/SSLSocketFactory.java
new file mode 100644
index 0000000..8b0966b
--- /dev/null
+++ b/javax/net/ssl/SSLSocketFactory.java
@@ -0,0 +1,351 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * 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 javax.net.ssl;
+
+import java.net.*;
+import javax.net.SocketFactory;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.*;
+import java.util.Locale;
+
+import sun.security.action.GetPropertyAction;
+
+/**
+ * <code>SSLSocketFactory</code>s create <code>SSLSocket</code>s.
+ *
+ * @since 1.4
+ * @see SSLSocket
+ * @author David Brownell
+ */
+public abstract class SSLSocketFactory extends SocketFactory
+{
+    // Android-changed: Renamed field.
+    // Some apps rely on changing this field via reflection, so we can't change the name
+    // without introducing app compatibility problems.  See http://b/62248930.
+    private static SSLSocketFactory defaultSocketFactory;
+
+    // Android-changed: Check Security.getVersion() on each update.
+    // If the set of providers or other such things changes, it may change the default
+    // factory, so we track the version returned from Security.getVersion() instead of
+    // only having a flag that says if we've ever initialized the default.
+    // private static boolean propertyChecked;
+    private static int lastVersion = -1;
+
+    static final boolean DEBUG;
+
+    static {
+        String s = java.security.AccessController.doPrivileged(
+            new GetPropertyAction("javax.net.debug", "")).toLowerCase(
+                                                            Locale.ENGLISH);
+        DEBUG = s.contains("all") || s.contains("ssl");
+    }
+
+    private static void log(String msg) {
+        if (DEBUG) {
+            System.out.println(msg);
+        }
+    }
+
+    /**
+     * Constructor is used only by subclasses.
+     */
+    public SSLSocketFactory() {
+    }
+
+    /**
+     * Returns the default SSL socket factory.
+     *
+     * <p>The first time this method is called, the security property
+     * "ssl.SocketFactory.provider" is examined. If it is non-null, a class by
+     * that name is loaded and instantiated. If that is successful and the
+     * object is an instance of SSLSocketFactory, it is made the default SSL
+     * socket factory.
+     *
+     * <p>Otherwise, this method returns
+     * <code>SSLContext.getDefault().getSocketFactory()</code>. If that
+     * call fails, an inoperative factory is returned.
+     *
+     * @return the default <code>SocketFactory</code>
+     * @see SSLContext#getDefault
+     */
+    public static synchronized SocketFactory getDefault() {
+        // Android-changed: Check Security.getVersion() on each update.
+        if (defaultSocketFactory != null && lastVersion == Security.getVersion()) {
+            return defaultSocketFactory;
+        }
+
+        lastVersion = Security.getVersion();
+        SSLSocketFactory previousDefaultSocketFactory = defaultSocketFactory;
+        defaultSocketFactory = null;
+
+        String clsName = getSecurityProperty("ssl.SocketFactory.provider");
+
+        if (clsName != null) {
+            // Android-changed: Check if we already have an instance of the default factory class.
+            // The instance for the default socket factory is checked for updates quite
+            // often (for instance, every time a security provider is added). Which leads
+            // to unnecessary overload and excessive error messages in case of class-loading
+            // errors. Avoid creating a new object if the class name is the same as before.
+            if (previousDefaultSocketFactory != null
+                    && clsName.equals(previousDefaultSocketFactory.getClass().getName())) {
+                defaultSocketFactory = previousDefaultSocketFactory;
+                return defaultSocketFactory;
+            }
+            log("setting up default SSLSocketFactory");
+            try {
+                Class<?> cls = null;
+                try {
+                    cls = Class.forName(clsName);
+                } catch (ClassNotFoundException e) {
+                    // Android-changed: Try the contextClassLoader first.
+                    ClassLoader cl = Thread.currentThread().getContextClassLoader();
+                    if (cl == null) {
+                        cl = ClassLoader.getSystemClassLoader();
+                    }
+
+                    if (cl != null) {
+                        // Android-changed: Use Class.forName() so the class gets initialized.
+                        cls = Class.forName(clsName, true, cl);
+                    }
+                }
+                log("class " + clsName + " is loaded");
+                SSLSocketFactory fac = (SSLSocketFactory)cls.newInstance();
+                log("instantiated an instance of class " + clsName);
+                defaultSocketFactory = fac;
+                return fac;
+            } catch (Exception e) {
+                log("SSLSocketFactory instantiation failed: " + e.toString());
+                // Android-changed: Fallback to the default SSLContext on exception.
+            }
+        }
+
+        try {
+            // Android-changed: Allow for {@code null} SSLContext.getDefault.
+            SSLContext context = SSLContext.getDefault();
+            if (context != null) {
+                defaultSocketFactory = context.getSocketFactory();
+            } else {
+                defaultSocketFactory = new DefaultSSLSocketFactory(new IllegalStateException("No factory found."));
+            }
+            return defaultSocketFactory;
+        } catch (NoSuchAlgorithmException e) {
+            return new DefaultSSLSocketFactory(e);
+        }
+    }
+
+    static String getSecurityProperty(final String name) {
+        return AccessController.doPrivileged(new PrivilegedAction<String>() {
+            @Override
+            public String run() {
+                String s = java.security.Security.getProperty(name);
+                if (s != null) {
+                    s = s.trim();
+                    if (s.length() == 0) {
+                        s = null;
+                    }
+                }
+                return s;
+            }
+        });
+    }
+
+    /**
+     * Returns the list of cipher suites which are enabled by default.
+     * Unless a different list is enabled, handshaking on an SSL connection
+     * will use one of these cipher suites.  The minimum quality of service
+     * for these defaults requires confidentiality protection and server
+     * authentication (that is, no anonymous cipher suites).
+     *
+     * @see #getSupportedCipherSuites()
+     * @return array of the cipher suites enabled by default
+     */
+    public abstract String [] getDefaultCipherSuites();
+
+    // Android-changed: Added warnings about misuse
+    /**
+     * Returns the names of the cipher suites which could be enabled for use
+     * on an SSL connection.  Normally, only a subset of these will actually
+     * be enabled by default, since this list may include cipher suites which
+     * do not meet quality of service requirements for those defaults.  Such
+     * cipher suites are useful in specialized applications.
+     *
+     * <p class="caution">Applications should not blindly enable all supported
+     * cipher suites.  The supported cipher suites can include signaling cipher suite
+     * values that can cause connection problems if enabled inappropriately.
+     *
+     * <p>The proper way to use this method is to either check if a specific cipher
+     * suite is supported via {@code Arrays.asList(getSupportedCipherSuites()).contains(...)}
+     * or to filter a desired list of cipher suites to only the supported ones via
+     * {@code desiredSuiteSet.retainAll(Arrays.asList(getSupportedCipherSuites()))}.
+     *
+     * @see #getDefaultCipherSuites()
+     * @return an array of cipher suite names
+     */
+    public abstract String [] getSupportedCipherSuites();
+
+    /**
+     * Returns a socket layered over an existing socket connected to the named
+     * host, at the given port.  This constructor can be used when tunneling SSL
+     * through a proxy or when negotiating the use of SSL over an existing
+     * socket. The host and port refer to the logical peer destination.
+     * This socket is configured using the socket options established for
+     * this factory.
+     *
+     * @param s the existing socket
+     * @param host the server host
+     * @param port the server port
+     * @param autoClose close the underlying socket when this socket is closed
+     * @return a socket connected to the specified host and port
+     * @throws IOException if an I/O error occurs when creating the socket
+     * @throws NullPointerException if the parameter s is null
+     */
+    public abstract Socket createSocket(Socket s, String host,
+            int port, boolean autoClose) throws IOException;
+
+    /**
+     * Creates a server mode {@link Socket} layered over an
+     * existing connected socket, and is able to read data which has
+     * already been consumed/removed from the {@link Socket}'s
+     * underlying {@link InputStream}.
+     * <p>
+     * This method can be used by a server application that needs to
+     * observe the inbound data but still create valid SSL/TLS
+     * connections: for example, inspection of Server Name Indication
+     * (SNI) extensions (See section 3 of <A
+     * HREF="http://www.ietf.org/rfc/rfc6066.txt">TLS Extensions
+     * (RFC6066)</A>).  Data that has been already removed from the
+     * underlying {@link InputStream} should be loaded into the
+     * {@code consumed} stream before this method is called, perhaps
+     * using a {@link java.io.ByteArrayInputStream}.  When this
+     * {@link Socket} begins handshaking, it will read all of the data in
+     * {@code consumed} until it reaches {@code EOF}, then all further
+     * data is read from the underlying {@link InputStream} as
+     * usual.
+     * <p>
+     * The returned socket is configured using the socket options
+     * established for this factory, and is set to use server mode when
+     * handshaking (see {@link SSLSocket#setUseClientMode(boolean)}).
+     *
+     * @param  s
+     *         the existing socket
+     * @param  consumed
+     *         the consumed inbound network data that has already been
+     *         removed from the existing {@link Socket}
+     *         {@link InputStream}.  This parameter may be
+     *         {@code null} if no data has been removed.
+     * @param  autoClose close the underlying socket when this socket is closed.
+     *
+     * @return the {@link Socket} compliant with the socket options
+     *         established for this factory
+     *
+     * @throws IOException if an I/O error occurs when creating the socket
+     * @throws UnsupportedOperationException if the underlying provider
+     *         does not implement the operation
+     * @throws NullPointerException if {@code s} is {@code null}
+     *
+     * @since 1.8
+     *
+     * @hide
+     */
+    public Socket createSocket(Socket s, InputStream consumed,
+            boolean autoClose) throws IOException {
+        throw new UnsupportedOperationException();
+    }
+}
+
+
+// file private
+class DefaultSSLSocketFactory extends SSLSocketFactory
+{
+    private Exception reason;
+
+    DefaultSSLSocketFactory(Exception reason) {
+        this.reason = reason;
+    }
+
+    private Socket throwException() throws SocketException {
+        throw (SocketException)
+            new SocketException(reason.toString()).initCause(reason);
+    }
+
+    @Override
+    public Socket createSocket()
+    throws IOException
+    {
+        return throwException();
+    }
+
+    @Override
+    public Socket createSocket(String host, int port)
+    throws IOException
+    {
+        return throwException();
+    }
+
+    @Override
+    public Socket createSocket(Socket s, String host,
+                                int port, boolean autoClose)
+    throws IOException
+    {
+        return throwException();
+    }
+
+    @Override
+    public Socket createSocket(InetAddress address, int port)
+    throws IOException
+    {
+        return throwException();
+    }
+
+    @Override
+    public Socket createSocket(String host, int port,
+        InetAddress clientAddress, int clientPort)
+    throws IOException
+    {
+        return throwException();
+    }
+
+    @Override
+    public Socket createSocket(InetAddress address, int port,
+        InetAddress clientAddress, int clientPort)
+    throws IOException
+    {
+        return throwException();
+    }
+
+    @Override
+    public String [] getDefaultCipherSuites() {
+        return new String[0];
+    }
+
+    @Override
+    public String [] getSupportedCipherSuites() {
+        return new String[0];
+    }
+}
diff --git a/javax/net/ssl/StandardConstants.java b/javax/net/ssl/StandardConstants.java
new file mode 100644
index 0000000..405417c
--- /dev/null
+++ b/javax/net/ssl/StandardConstants.java
@@ -0,0 +1,56 @@
+/*
+ * 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 javax.net.ssl;
+
+/**
+ * Standard constants definitions
+ *
+ * @since 1.8
+ */
+public final class StandardConstants {
+
+    // Suppress default constructor for noninstantiability
+    private StandardConstants() {
+        throw new AssertionError(
+            "No javax.net.ssl.StandardConstants instances for you!");
+    }
+
+    /**
+     * The "host_name" type representing of a DNS hostname
+     * (see {@link SNIHostName}) in a Server Name Indication (SNI) extension.
+     * <P>
+     * The SNI extension is a feature that extends the SSL/TLS protocols to
+     * indicate what server name the client is attempting to connect to during
+     * handshaking.  See section 3, "Server Name Indication", of <A
+     * HREF="http://www.ietf.org/rfc/rfc6066.txt">TLS Extensions (RFC 6066)</A>.
+     * <P>
+     * The value of this constant is {@code 0x00}.
+     *
+     * @see SNIServerName
+     * @see SNIHostName
+     */
+    public static final int SNI_HOST_NAME = 0x00;
+}
diff --git a/javax/net/ssl/TrustManager.java b/javax/net/ssl/TrustManager.java
new file mode 100644
index 0000000..e4d032d
--- /dev/null
+++ b/javax/net/ssl/TrustManager.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 1999, 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 javax.net.ssl;
+
+/**
+ * This is the base interface for JSSE trust managers.
+ * <P>
+ * <code>TrustManager</code>s are responsible for managing the trust material
+ * that is used when making trust decisions, and for deciding whether
+ * credentials presented by a peer should be accepted.
+ * <P>
+ * <code>TrustManager</code>s are created by either
+ * using a <code>TrustManagerFactory</code>,
+ * or by implementing one of the <code>TrustManager</code> subclasses.
+ *
+ * @see TrustManagerFactory
+ * @since 1.4
+ */
+public interface TrustManager {
+}
diff --git a/javax/net/ssl/TrustManagerFactory.java b/javax/net/ssl/TrustManagerFactory.java
new file mode 100644
index 0000000..d76f5fb
--- /dev/null
+++ b/javax/net/ssl/TrustManagerFactory.java
@@ -0,0 +1,303 @@
+/*
+ * Copyright (c) 1999, 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 javax.net.ssl;
+
+import java.security.Security;
+import java.security.*;
+
+import sun.security.jca.GetInstance;
+
+/**
+ * This class acts as a factory for trust managers based on a
+ * source of trust material. Each trust manager manages a specific
+ * type of trust material for use by secure sockets. The trust
+ * material is based on a KeyStore and/or provider specific sources.
+ *
+ * <p> Android provides the following <code>TrustManagerFactory</code> 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>
+ *
+ * @since 1.4
+ * @see TrustManager
+ */
+public class TrustManagerFactory {
+    // The provider
+    private Provider provider;
+
+    // The provider implementation (delegate)
+    private TrustManagerFactorySpi factorySpi;
+
+    // The name of the trust management algorithm.
+    private String algorithm;
+
+    /**
+     * Obtains the default TrustManagerFactory algorithm name.
+     *
+     * <p>The default TrustManager can be changed at runtime by setting
+     * the value of the {@code ssl.TrustManagerFactory.algorithm}
+     * security property to the desired algorithm name.
+     *
+     * @see java.security.Security security properties
+     * @return the default algorithm name as specified by the
+     * {@code ssl.TrustManagerFactory.algorithm} security property, or an
+     * implementation-specific default if no such property exists.
+     */
+    public final static String getDefaultAlgorithm() {
+        String type;
+        type = AccessController.doPrivileged(new PrivilegedAction<String>() {
+            @Override
+            public String run() {
+                return Security.getProperty(
+                    "ssl.TrustManagerFactory.algorithm");
+            }
+        });
+        if (type == null) {
+            type = "SunX509";
+        }
+        return type;
+    }
+
+    /**
+     * Creates a TrustManagerFactory object.
+     *
+     * @param factorySpi the delegate
+     * @param provider the provider
+     * @param algorithm the algorithm
+     */
+    protected TrustManagerFactory(TrustManagerFactorySpi factorySpi,
+            Provider provider, String algorithm) {
+        this.factorySpi = factorySpi;
+        this.provider = provider;
+        this.algorithm = algorithm;
+    }
+
+    /**
+     * Returns the algorithm name of this <code>TrustManagerFactory</code>
+     * object.
+     *
+     * <p>This is the same name that was specified in one of the
+     * <code>getInstance</code> calls that created this
+     * <code>TrustManagerFactory</code> object.
+     *
+     * @return the algorithm name of this <code>TrustManagerFactory</code>
+     *          object
+     */
+    public final String getAlgorithm() {
+        return this.algorithm;
+    }
+
+    /**
+     * Returns a <code>TrustManagerFactory</code> object that acts as a
+     * factory for trust managers.
+     *
+     * <p> This method traverses the list of registered security Providers,
+     * starting with the most preferred Provider.
+     * A new TrustManagerFactory object encapsulating the
+     * TrustManagerFactorySpi 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 requested trust management
+     *          algorithm.  See the <a href=
+     *  "{@docRoot}/../technotes/guides/security/jsse/JSSERefGuide.html">
+     *          Java Secure Socket Extension Reference Guide </a>
+     *          for information about standard algorithm names.
+     *
+     * @return the new <code>TrustManagerFactory</code> object.
+     *
+     * @exception NoSuchAlgorithmException if no Provider supports a
+     *          TrustManagerFactorySpi implementation for the
+     *          specified algorithm.
+     * @exception NullPointerException if algorithm is null.
+     *
+     * @see java.security.Provider
+     */
+    public static final TrustManagerFactory getInstance(String algorithm)
+            throws NoSuchAlgorithmException {
+        GetInstance.Instance instance = GetInstance.getInstance
+                ("TrustManagerFactory", TrustManagerFactorySpi.class,
+                algorithm);
+        return new TrustManagerFactory((TrustManagerFactorySpi)instance.impl,
+                instance.provider, algorithm);
+    }
+
+    /**
+     * Returns a <code>TrustManagerFactory</code> object that acts as a
+     * factory for trust managers.
+     *
+     * <p> A new KeyManagerFactory object encapsulating the
+     * KeyManagerFactorySpi 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 name of the requested trust management
+     *          algorithm.  See the <a href=
+     *  "{@docRoot}/../technotes/guides/security/jsse/JSSERefGuide.html">
+     *          Java Secure Socket Extension Reference Guide </a>
+     *          for information about standard algorithm names.
+     *
+     * @param provider the name of the provider.
+     *
+     * @return the new <code>TrustManagerFactory</code> object
+     *
+     * @throws NoSuchAlgorithmException if a TrustManagerFactorySpi
+     *          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.
+     *
+     * @throws IllegalArgumentException if the provider name is null or empty.
+     * @throws NullPointerException if algorithm is null.
+     *
+     * @see java.security.Provider
+     */
+    public static final TrustManagerFactory getInstance(String algorithm,
+            String provider) throws NoSuchAlgorithmException,
+            NoSuchProviderException {
+        GetInstance.Instance instance = GetInstance.getInstance
+                ("TrustManagerFactory", TrustManagerFactorySpi.class,
+                algorithm, provider);
+        return new TrustManagerFactory((TrustManagerFactorySpi)instance.impl,
+                instance.provider, algorithm);
+    }
+
+    /**
+     * Returns a <code>TrustManagerFactory</code> object that acts as a
+     * factory for trust managers.
+     *
+     * <p> A new TrustManagerFactory object encapsulating the
+     * TrustManagerFactorySpi 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 name of the requested trust management
+     *          algorithm.  See the <a href=
+     *  "{@docRoot}/../technotes/guides/security/jsse/JSSERefGuide.html">
+     *          Java Secure Socket Extension Reference Guide </a>
+     *          for information about standard algorithm names.
+     *
+     * @param provider an instance of the provider.
+     *
+     * @return the new <code>TrustManagerFactory</code> object.
+     *
+     * @throws NoSuchAlgorithmException if a TrustManagerFactorySpi
+     *          implementation for the specified algorithm is not available
+     *          from the specified Provider object.
+     *
+     * @throws IllegalArgumentException if the provider is null.
+     * @throws NullPointerException if algorithm is null.
+     *
+     * @see java.security.Provider
+     */
+    public static final TrustManagerFactory getInstance(String algorithm,
+            Provider provider) throws NoSuchAlgorithmException {
+        GetInstance.Instance instance = GetInstance.getInstance
+                ("TrustManagerFactory", TrustManagerFactorySpi.class,
+                algorithm, provider);
+        return new TrustManagerFactory((TrustManagerFactorySpi)instance.impl,
+                instance.provider, algorithm);
+    }
+
+    /**
+     * Returns the provider of this <code>TrustManagerFactory</code> object.
+     *
+     * @return the provider of this <code>TrustManagerFactory</code> object
+     */
+    public final Provider getProvider() {
+        return this.provider;
+    }
+
+
+    /**
+     * Initializes this factory with a source of certificate
+     * authorities and related trust material.
+     * <P>
+     * The provider typically uses a KeyStore as a basis for making
+     * trust decisions.
+     * <P>
+     * For more flexible initialization, please see
+     * {@link #init(ManagerFactoryParameters)}.
+     *
+     * @param ks the key store, or null
+     * @throws KeyStoreException if this operation fails
+     */
+    public final void init(KeyStore ks) throws KeyStoreException {
+        factorySpi.engineInit(ks);
+    }
+
+
+    /**
+     * Initializes this factory with a source of provider-specific
+     * trust material.
+     * <P>
+     * In some cases, initialization parameters other than a keystore
+     * may be needed by a provider.  Users of that particular provider
+     * are expected to pass an implementation of the appropriate
+     * <CODE>ManagerFactoryParameters</CODE> as defined by the
+     * provider.  The provider can then call the specified methods in
+     * the <CODE>ManagerFactoryParameters</CODE> implementation to obtain the
+     * needed information.
+     *
+     * @param spec an implementation of a provider-specific parameter
+     *          specification
+     * @throws InvalidAlgorithmParameterException if an error is
+     *          encountered
+     */
+    public final void init(ManagerFactoryParameters spec) throws
+            InvalidAlgorithmParameterException {
+        factorySpi.engineInit(spec);
+    }
+
+
+    /**
+     * Returns one trust manager for each type of trust material.
+     *
+     * @throws IllegalStateException if the factory is not initialized.
+     *
+     * @return the trust managers
+     */
+    public final TrustManager[] getTrustManagers() {
+        return factorySpi.engineGetTrustManagers();
+    }
+}
diff --git a/javax/net/ssl/TrustManagerFactorySpi.java b/javax/net/ssl/TrustManagerFactorySpi.java
new file mode 100644
index 0000000..5d6ac7c
--- /dev/null
+++ b/javax/net/ssl/TrustManagerFactorySpi.java
@@ -0,0 +1,82 @@
+/*
+ * 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 javax.net.ssl;
+
+import java.security.*;
+
+/**
+ * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>)
+ * for the <code>TrustManagerFactory</code> class.
+ *
+ * <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 trust manager factory.
+ *
+ * @since 1.4
+ * @see TrustManagerFactory
+ * @see TrustManager
+ */
+public abstract class TrustManagerFactorySpi {
+    /**
+     * Initializes this factory with a source of certificate
+     * authorities and related trust material.
+     *
+     * @param ks the key store or null
+     * @throws KeyStoreException if this operation fails
+     * @see TrustManagerFactory#init(KeyStore)
+     */
+    protected abstract void engineInit(KeyStore ks) throws KeyStoreException;
+
+    /**
+     * Initializes this factory with a source of provider-specific
+     * key material.
+     * <P>
+     * In some cases, initialization parameters other than a keystore
+     * may be needed by a provider.  Users of that
+     * particular provider are expected to pass an implementation of
+     * the appropriate <CODE>ManagerFactoryParameters</CODE> as
+     * defined by the provider.  The provider can then call the
+     * specified methods in the <CODE>ManagerFactoryParameters</CODE>
+     * implementation to obtain the needed information.
+     *
+     * @param spec an implementation of a provider-specific parameter
+     *          specification
+     * @throws InvalidAlgorithmParameterException if there is problem
+     *          with the parameters
+     * @see TrustManagerFactory#init(ManagerFactoryParameters spec)
+     */
+    protected abstract void engineInit(ManagerFactoryParameters spec)
+        throws InvalidAlgorithmParameterException;
+
+    /**
+     * Returns one trust manager for each type of trust material.
+     *
+     * @throws IllegalStateException if the factory is not initialized.
+     *
+     * @return the trust managers
+     */
+    protected abstract TrustManager[] engineGetTrustManagers();
+}
diff --git a/javax/net/ssl/X509ExtendedKeyManager.java b/javax/net/ssl/X509ExtendedKeyManager.java
new file mode 100644
index 0000000..a28cc6f
--- /dev/null
+++ b/javax/net/ssl/X509ExtendedKeyManager.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 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 javax.net.ssl;
+
+import java.security.Principal;
+
+/**
+ * Abstract class that provides for extension of the X509KeyManager
+ * interface.
+ * <P>
+ * Methods in this class should be overriden to provide actual
+ * implementations.
+ *
+ * @since 1.5
+ * @author Brad R. Wetmore
+ */
+public abstract class X509ExtendedKeyManager implements X509KeyManager {
+
+    /**
+     * Constructor used by subclasses only.
+     */
+    protected X509ExtendedKeyManager() {
+    }
+
+    /**
+     * Choose an alias to authenticate the client side of an
+     * <code>SSLEngine</code> connection given the public key type
+     * and the list of certificate issuer authorities recognized by
+     * the peer (if any).
+     * <P>
+     * The default implementation returns null.
+     *
+     * @param keyType the key algorithm type name(s), ordered
+     *          with the most-preferred key type first.
+     * @param issuers the list of acceptable CA issuer subject names
+     *          or null if it does not matter which issuers are used.
+     * @param engine the <code>SSLEngine</code> to be used for this
+     *          connection.  This parameter can be null, which indicates
+     *          that implementations of this interface are free to
+     *          select an alias applicable to any engine.
+     * @return the alias name for the desired key, or null if there
+     *          are no matches.
+     */
+    public String chooseEngineClientAlias(String[] keyType,
+            Principal[] issuers, SSLEngine engine) {
+        return null;
+    }
+
+    /**
+     * Choose an alias to authenticate the server side of an
+     * <code>SSLEngine</code> connection given the public key type
+     * and the list of certificate issuer authorities recognized by
+     * the peer (if any).
+     * <P>
+     * The default implementation returns null.
+     *
+     * @param keyType the key algorithm type name.
+     * @param issuers the list of acceptable CA issuer subject names
+     *          or null if it does not matter which issuers are used.
+     * @param engine the <code>SSLEngine</code> to be used for this
+     *          connection.  This parameter can be null, which indicates
+     *          that implementations of this interface are free to
+     *          select an alias applicable to any engine.
+     * @return the alias name for the desired key, or null if there
+     *          are no matches.
+     */
+    public String chooseEngineServerAlias(String keyType,
+            Principal[] issuers, SSLEngine engine) {
+        return null;
+    }
+
+}
diff --git a/javax/net/ssl/X509ExtendedTrustManager.java b/javax/net/ssl/X509ExtendedTrustManager.java
new file mode 100644
index 0000000..f14489f
--- /dev/null
+++ b/javax/net/ssl/X509ExtendedTrustManager.java
@@ -0,0 +1,234 @@
+/*
+ * 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 javax.net.ssl;
+
+import java.net.Socket;
+import javax.net.ssl.X509TrustManager;
+
+import java.security.cert.X509Certificate;
+import java.security.cert.CertificateException;
+
+/**
+ * Extensions to the <code>X509TrustManager</code> interface to support
+ * SSL/TLS connection sensitive trust management.
+ * <p>
+ * To prevent man-in-the-middle attacks, hostname checks can be done
+ * to verify that the hostname in an end-entity certificate matches the
+ * targeted hostname.  TLS does not require such checks, but some protocols
+ * over TLS (such as HTTPS) do.  In earlier versions of the JDK, the
+ * certificate chain checks were done at the SSL/TLS layer, and the hostname
+ * verification checks were done at the layer over TLS.  This class allows
+ * for the checking to be done during a single call to this class.
+ * <p>
+ * RFC 2830 defines the server identification specification for the "LDAPS"
+ * algorithm. RFC 2818 defines both the server identification and the
+ * client identification specification for the "HTTPS" algorithm.
+ *
+ * @see X509TrustManager
+ * @see HostnameVerifier
+ *
+ * @since 1.7
+ */
+public abstract class X509ExtendedTrustManager implements X509TrustManager {
+    /**
+     * Given the partial or complete certificate chain provided by the
+     * peer, build and validate the certificate path based on the
+     * authentication type and ssl parameters.
+     * <p>
+     * The authentication type is determined by the actual certificate
+     * used. For instance, if RSAPublicKey is used, the authType
+     * should be "RSA". Checking is case-sensitive.
+     * <p>
+     * If the <code>socket</code> parameter is an instance of
+     * {@link javax.net.ssl.SSLSocket}, and the endpoint identification
+     * algorithm of the <code>SSLParameters</code> is non-empty, to prevent
+     * man-in-the-middle attacks, the address that the <code>socket</code>
+     * connected to should be checked against the peer's identity presented
+     * in the end-entity X509 certificate, as specified in the endpoint
+     * identification algorithm.
+     * <p>
+     * If the <code>socket</code> parameter is an instance of
+     * {@link javax.net.ssl.SSLSocket}, and the algorithm constraints of the
+     * <code>SSLParameters</code> is non-null, for every certificate in the
+     * certification path, fields such as subject public key, the signature
+     * algorithm, key usage, extended key usage, etc. need to conform to the
+     * algorithm constraints in place on this socket.
+     *
+     * @param chain the peer certificate chain
+     * @param authType the key exchange algorithm used
+     * @param socket the socket used for this connection. This parameter
+     *        can be null, which indicates that implementations need not check
+     *        the ssl parameters
+     * @throws IllegalArgumentException if null or zero-length array is passed
+     *        in for the <code>chain</code> parameter or if null or zero-length
+     *        string is passed in for the <code>authType</code> parameter
+     * @throws CertificateException if the certificate chain is not trusted
+     *        by this TrustManager
+     *
+     * @see SSLParameters#getEndpointIdentificationAlgorithm
+     * @see SSLParameters#setEndpointIdentificationAlgorithm(String)
+     * @see SSLParameters#getAlgorithmConstraints
+     * @see SSLParameters#setAlgorithmConstraints(AlgorithmConstraints)
+     */
+    public abstract void checkClientTrusted(X509Certificate[] chain,
+            String authType, Socket socket) throws CertificateException;
+
+    /**
+     * Given the partial or complete certificate chain provided by the
+     * peer, build and validate the certificate path based on the
+     * authentication type and ssl parameters.
+     * <p>
+     * The authentication type is the key exchange algorithm portion
+     * of the cipher suites represented as a String, such as "RSA",
+     * "DHE_DSS". Note: for some exportable cipher suites, the key
+     * exchange algorithm is determined at run time during the
+     * handshake. For instance, for TLS_RSA_EXPORT_WITH_RC4_40_MD5,
+     * the authType should be RSA_EXPORT when an ephemeral RSA key is
+     * used for the key exchange, and RSA when the key from the server
+     * certificate is used. Checking is case-sensitive.
+     * <p>
+     * If the <code>socket</code> parameter is an instance of
+     * {@link javax.net.ssl.SSLSocket}, and the endpoint identification
+     * algorithm of the <code>SSLParameters</code> is non-empty, to prevent
+     * man-in-the-middle attacks, the address that the <code>socket</code>
+     * connected to should be checked against the peer's identity presented
+     * in the end-entity X509 certificate, as specified in the endpoint
+     * identification algorithm.
+     * <p>
+     * If the <code>socket</code> parameter is an instance of
+     * {@link javax.net.ssl.SSLSocket}, and the algorithm constraints of the
+     *  <code>SSLParameters</code> is non-null, for every certificate in the
+     * certification path, fields such as subject public key, the signature
+     * algorithm, key usage, extended key usage, etc. need to conform to the
+     * algorithm constraints in place on this socket.
+     *
+     * @param chain the peer certificate chain
+     * @param authType the key exchange algorithm used
+     * @param socket the socket used for this connection. This parameter
+     *        can be null, which indicates that implementations need not check
+     *        the ssl parameters
+     * @throws IllegalArgumentException if null or zero-length array is passed
+     *        in for the <code>chain</code> parameter or if null or zero-length
+     *        string is passed in for the <code>authType</code> parameter
+     * @throws CertificateException if the certificate chain is not trusted
+     *        by this TrustManager
+     *
+     * @see SSLParameters#getEndpointIdentificationAlgorithm
+     * @see SSLParameters#setEndpointIdentificationAlgorithm(String)
+     * @see SSLParameters#getAlgorithmConstraints
+     * @see SSLParameters#setAlgorithmConstraints(AlgorithmConstraints)
+     */
+    public abstract void checkServerTrusted(X509Certificate[] chain,
+        String authType, Socket socket) throws CertificateException;
+
+    /**
+     * Given the partial or complete certificate chain provided by the
+     * peer, build and validate the certificate path based on the
+     * authentication type and ssl parameters.
+     * <p>
+     * The authentication type is determined by the actual certificate
+     * used. For instance, if RSAPublicKey is used, the authType
+     * should be "RSA". Checking is case-sensitive.
+     * <p>
+     * If the <code>engine</code> parameter is available, and the endpoint
+     * identification algorithm of the <code>SSLParameters</code> is
+     * non-empty, to prevent man-in-the-middle attacks, the address that
+     * the <code>engine</code> connected to should be checked against
+     * the peer's identity presented in the end-entity X509 certificate,
+     * as specified in the endpoint identification algorithm.
+     * <p>
+     * If the <code>engine</code> parameter is available, and the algorithm
+     * constraints of the <code>SSLParameters</code> is non-null, for every
+     * certificate in the certification path, fields such as subject public
+     * key, the signature algorithm, key usage, extended key usage, etc.
+     * need to conform to the algorithm constraints in place on this engine.
+     *
+     * @param chain the peer certificate chain
+     * @param authType the key exchange algorithm used
+     * @param engine the engine used for this connection. This parameter
+     *        can be null, which indicates that implementations need not check
+     *        the ssl parameters
+     * @throws IllegalArgumentException if null or zero-length array is passed
+     *        in for the <code>chain</code> parameter or if null or zero-length
+     *        string is passed in for the <code>authType</code> parameter
+     * @throws CertificateException if the certificate chain is not trusted
+     *        by this TrustManager
+     *
+     * @see SSLParameters#getEndpointIdentificationAlgorithm
+     * @see SSLParameters#setEndpointIdentificationAlgorithm(String)
+     * @see SSLParameters#getAlgorithmConstraints
+     * @see SSLParameters#setAlgorithmConstraints(AlgorithmConstraints)
+     */
+    public abstract void checkClientTrusted(X509Certificate[] chain,
+        String authType, SSLEngine engine) throws CertificateException;
+
+    /**
+     * Given the partial or complete certificate chain provided by the
+     * peer, build and validate the certificate path based on the
+     * authentication type and ssl parameters.
+     * <p>
+     * The authentication type is the key exchange algorithm portion
+     * of the cipher suites represented as a String, such as "RSA",
+     * "DHE_DSS". Note: for some exportable cipher suites, the key
+     * exchange algorithm is determined at run time during the
+     * handshake. For instance, for TLS_RSA_EXPORT_WITH_RC4_40_MD5,
+     * the authType should be RSA_EXPORT when an ephemeral RSA key is
+     * used for the key exchange, and RSA when the key from the server
+     * certificate is used. Checking is case-sensitive.
+     * <p>
+     * If the <code>engine</code> parameter is available, and the endpoint
+     * identification algorithm of the <code>SSLParameters</code> is
+     * non-empty, to prevent man-in-the-middle attacks, the address that
+     * the <code>engine</code> connected to should be checked against
+     * the peer's identity presented in the end-entity X509 certificate,
+     * as specified in the endpoint identification algorithm.
+     * <p>
+     * If the <code>engine</code> parameter is available, and the algorithm
+     * constraints of the <code>SSLParameters</code> is non-null, for every
+     * certificate in the certification path, fields such as subject public
+     * key, the signature algorithm, key usage, extended key usage, etc.
+     * need to conform to the algorithm constraints in place on this engine.
+     *
+     * @param chain the peer certificate chain
+     * @param authType the key exchange algorithm used
+     * @param engine the engine used for this connection. This parameter
+     *        can be null, which indicates that implementations need not check
+     *        the ssl parameters
+     * @throws IllegalArgumentException if null or zero-length array is passed
+     *        in for the <code>chain</code> parameter or if null or zero-length
+     *        string is passed in for the <code>authType</code> parameter
+     * @throws CertificateException if the certificate chain is not trusted
+     *        by this TrustManager
+     *
+     * @see SSLParameters#getEndpointIdentificationAlgorithm
+     * @see SSLParameters#setEndpointIdentificationAlgorithm(String)
+     * @see SSLParameters#getAlgorithmConstraints
+     * @see SSLParameters#setAlgorithmConstraints(AlgorithmConstraints)
+     */
+    public abstract void checkServerTrusted(X509Certificate[] chain,
+        String authType, SSLEngine engine) throws CertificateException;
+
+}
diff --git a/javax/net/ssl/X509KeyManager.java b/javax/net/ssl/X509KeyManager.java
new file mode 100644
index 0000000..69ab91a
--- /dev/null
+++ b/javax/net/ssl/X509KeyManager.java
@@ -0,0 +1,134 @@
+/*
+ * 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 javax.net.ssl;
+
+import java.security.PrivateKey;
+import java.security.Principal;
+import java.security.cert.X509Certificate;
+import java.net.Socket;
+
+/**
+ * Instances of this interface manage which X509 certificate-based
+ * key pairs are used to authenticate the local side of a secure
+ * socket.
+ * <P>
+ * During secure socket negotiations, implentations
+ * call methods in this interface to:
+ * <UL>
+ * <LI> determine the set of aliases that are available for negotiations
+ *      based on the criteria presented,
+ * <LI> select the <i> best alias</i> based on
+ *      the criteria presented, and
+ * <LI> obtain the corresponding key material for given aliases.
+ * </UL>
+ * <P>
+ * Note: the X509ExtendedKeyManager should be used in favor of this
+ * class.
+ *
+ * @since 1.4
+ */
+public interface X509KeyManager extends KeyManager {
+    /**
+     * Get the matching aliases for authenticating the client side of a secure
+     * socket given the public key type and the list of
+     * certificate issuer authorities recognized by the peer (if any).
+     *
+     * @param keyType the key algorithm type name
+     * @param issuers the list of acceptable CA issuer subject names,
+     *          or null if it does not matter which issuers are used.
+     * @return an array of the matching alias names, or null if there
+     *          were no matches.
+     */
+    public String[] getClientAliases(String keyType, Principal[] issuers);
+
+    /**
+     * Choose an alias to authenticate the client side of a secure
+     * socket given the public key type and the list of
+     * certificate issuer authorities recognized by the peer (if any).
+     *
+     * @param keyType the key algorithm type name(s), ordered
+     *          with the most-preferred key type first.
+     * @param issuers the list of acceptable CA issuer subject names
+     *           or null if it does not matter which issuers are used.
+     * @param socket the socket to be used for this connection.  This
+     *          parameter can be null, which indicates that
+     *          implementations are free to select an alias applicable
+     *          to any socket.
+     * @return the alias name for the desired key, or null if there
+     *          are no matches.
+     */
+    public String chooseClientAlias(String[] keyType, Principal[] issuers,
+        Socket socket);
+
+    /**
+     * Get the matching aliases for authenticating the server side of a secure
+     * socket given the public key type and the list of
+     * certificate issuer authorities recognized by the peer (if any).
+     *
+     * @param keyType the key algorithm type name
+     * @param issuers the list of acceptable CA issuer subject names
+     *          or null if it does not matter which issuers are used.
+     * @return an array of the matching alias names, or null
+     *          if there were no matches.
+     */
+    public String[] getServerAliases(String keyType, Principal[] issuers);
+
+    /**
+     * Choose an alias to authenticate the server side of a secure
+     * socket given the public key type and the list of
+     * certificate issuer authorities recognized by the peer (if any).
+     *
+     * @param keyType the key algorithm type name.
+     * @param issuers the list of acceptable CA issuer subject names
+     *          or null if it does not matter which issuers are used.
+     * @param socket the socket to be used for this connection.  This
+     *          parameter can be null, which indicates that
+     *          implementations are free to select an alias applicable
+     *          to any socket.
+     * @return the alias name for the desired key, or null if there
+     *          are no matches.
+     */
+    public String chooseServerAlias(String keyType, Principal[] issuers,
+        Socket socket);
+
+    /**
+     * Returns the certificate chain associated with the given alias.
+     *
+     * @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 alias can't be found.
+     */
+    public X509Certificate[] getCertificateChain(String alias);
+
+    /**
+     * Returns the key associated with the given alias.
+     *
+     * @param alias the alias name
+     * @return the requested key, or null if the alias can't be found.
+     */
+    public PrivateKey getPrivateKey(String alias);
+}
diff --git a/javax/net/ssl/X509TrustManager.java b/javax/net/ssl/X509TrustManager.java
new file mode 100644
index 0000000..9622c70
--- /dev/null
+++ b/javax/net/ssl/X509TrustManager.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 1999, 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 javax.net.ssl;
+
+import java.security.cert.*;
+
+/**
+ * Instance of this interface manage which X509 certificates
+ * may be used to authenticate the remote side of a secure
+ * socket. Decisions may be based on trusted certificate
+ * authorities, certificate revocation lists, online
+ * status checking or other means.
+ *
+ * @since 1.4
+ */
+public interface X509TrustManager extends TrustManager {
+    /**
+     * Given the partial or complete certificate chain provided by the
+     * peer, build a certificate path to a trusted root and return if
+     * it can be validated and is trusted for client SSL
+     * authentication based on the authentication type.
+     * <p>
+     * The authentication type is determined by the actual certificate
+     * used. For instance, if RSAPublicKey is used, the authType
+     * should be "RSA". Checking is case-sensitive.
+     *
+     * @param chain the peer certificate chain
+     * @param authType the authentication type based on the client certificate
+     * @throws IllegalArgumentException if null or zero-length chain
+     *         is passed in for the chain parameter or if null or zero-length
+     *         string is passed in for the  authType parameter
+     * @throws CertificateException if the certificate chain is not trusted
+     *         by this TrustManager.
+     */
+    public void checkClientTrusted(X509Certificate[] chain, String authType)
+        throws CertificateException;
+
+    /**
+     * Given the partial or complete certificate chain provided by the
+     * peer, build a certificate path to a trusted root and return if
+     * it can be validated and is trusted for server SSL
+     * authentication based on the authentication type.
+     * <p>
+     * The authentication type is the key exchange algorithm portion
+     * of the cipher suites represented as a String, such as "RSA",
+     * "DHE_DSS". Note: for some exportable cipher suites, the key
+     * exchange algorithm is determined at run time during the
+     * handshake. For instance, for TLS_RSA_EXPORT_WITH_RC4_40_MD5,
+     * the authType should be RSA_EXPORT when an ephemeral RSA key is
+     * used for the key exchange, and RSA when the key from the server
+     * certificate is used. Checking is case-sensitive.
+     *
+     * @param chain the peer certificate chain
+     * @param authType the key exchange algorithm used
+     * @throws IllegalArgumentException if null or zero-length chain
+     *         is passed in for the chain parameter or if null or zero-length
+     *         string is passed in for the  authType parameter
+     * @throws CertificateException if the certificate chain is not trusted
+     *         by this TrustManager.
+     */
+    public void checkServerTrusted(X509Certificate[] chain, String authType)
+        throws CertificateException;
+
+    /**
+     * Return an array of certificate authority certificates
+     * which are trusted for authenticating peers.
+     *
+     * @return a non-null (possibly empty) array of acceptable
+     *          CA issuer certificates.
+     */
+    public X509Certificate[] getAcceptedIssuers();
+}
diff --git a/javax/obex/ApplicationParameter.java b/javax/obex/ApplicationParameter.java
new file mode 100644
index 0000000..16770a1
--- /dev/null
+++ b/javax/obex/ApplicationParameter.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * 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 the Motorola, Inc. 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 HOLDER 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 javax.obex;
+
+/**
+ * @hide
+ */
+public final class ApplicationParameter {
+
+    private byte[] mArray;
+
+    private int mLength;
+
+    private int mMaxLength = 1000;
+
+    public static class TRIPLET_TAGID {
+        public static final byte ORDER_TAGID = 0x01;
+
+        public static final byte SEARCH_VALUE_TAGID = 0x02;
+
+        public static final byte SEARCH_ATTRIBUTE_TAGID = 0x03;
+
+        // if equals to "0", PSE only reply number of contacts
+        public static final byte MAXLISTCOUNT_TAGID = 0x04;
+
+        public static final byte LISTSTARTOFFSET_TAGID = 0x05;
+
+        public static final byte PROPERTY_SELECTOR_TAGID = 0x06;
+
+        public static final byte FORMAT_TAGID = 0x07;
+
+        // only used if max list count = 0
+        public static final byte PHONEBOOKSIZE_TAGID = 0x08;
+
+        // only used in "mch" in response
+        public static final byte NEWMISSEDCALLS_TAGID = 0x09;
+
+        public static final byte SUPPORTEDFEATURE_TAGID = 0x10;
+
+        public static final byte PRIMARYVERSIONCOUNTER_TAGID = 0x0A;
+
+        public static final byte SECONDARYVERSIONCOUNTER_TAGID = 0x0B;
+
+        public static final byte VCARDSELECTOR_TAGID = 0x0C;
+
+        public static final byte DATABASEIDENTIFIER_TAGID = 0x0D;
+
+        public static final byte VCARDSELECTOROPERATOR_TAGID = 0x0E;
+
+        public static final byte RESET_NEW_MISSED_CALLS_TAGID = 0x0F;
+    }
+
+    public static class TRIPLET_VALUE {
+        public static class ORDER {
+            public static final byte ORDER_BY_INDEX = 0x00;
+
+            public static final byte ORDER_BY_ALPHANUMERIC = 0x01;
+
+            public static final byte ORDER_BY_PHONETIC = 0x02;
+        }
+
+        public static class SEARCHATTRIBUTE {
+            public static final byte SEARCH_BY_NAME = 0x00;
+
+            public static final byte SEARCH_BY_NUMBER = 0x01;
+
+            public static final byte SEARCH_BY_SOUND = 0x02;
+        }
+
+        public static class FORMAT {
+            public static final byte VCARD_VERSION_21 = 0x00;
+
+            public static final byte VCARD_VERSION_30 = 0x01;
+        }
+    }
+
+    public static class TRIPLET_LENGTH {
+        public static final byte ORDER_LENGTH = 1;
+
+        public static final byte SEARCH_ATTRIBUTE_LENGTH = 1;
+
+        public static final byte MAXLISTCOUNT_LENGTH = 2;
+
+        public static final byte LISTSTARTOFFSET_LENGTH = 2;
+
+        public static final byte PROPERTY_SELECTOR_LENGTH = 8;
+
+        public static final byte FORMAT_LENGTH = 1;
+
+        public static final byte PHONEBOOKSIZE_LENGTH = 2;
+
+        public static final byte NEWMISSEDCALLS_LENGTH = 1;
+
+        public static final byte SUPPORTEDFEATURE_LENGTH = 4;
+
+        public static final byte PRIMARYVERSIONCOUNTER_LENGTH = 16;
+
+        public static final byte SECONDARYVERSIONCOUNTER_LENGTH = 16;
+
+        public static final byte VCARDSELECTOR_LENGTH = 8;
+
+        public static final byte DATABASEIDENTIFIER_LENGTH = 16;
+
+        public static final byte VCARDSELECTOROPERATOR_LENGTH = 1;
+
+        public static final byte RESETNEWMISSEDCALLS_LENGTH = 1;
+    }
+
+    public ApplicationParameter() {
+        mArray = new byte[mMaxLength];
+        mLength = 0;
+    }
+
+    public void addAPPHeader(byte tag, byte len, byte[] value) {
+        if ((mLength + len + 2) > mMaxLength) {
+            byte[] array_tmp = new byte[mLength + 4 * len];
+            System.arraycopy(mArray, 0, array_tmp, 0, mLength);
+            mArray = array_tmp;
+            mMaxLength = mLength + 4 * len;
+        }
+        mArray[mLength++] = tag;
+        mArray[mLength++] = len;
+        System.arraycopy(value, 0, mArray, mLength, len);
+        mLength += len;
+    }
+
+    public byte[] getAPPparam() {
+        byte[] para = new byte[mLength];
+        System.arraycopy(mArray, 0, para, 0, mLength);
+        return para;
+    }
+}
diff --git a/javax/obex/Authenticator.java b/javax/obex/Authenticator.java
new file mode 100644
index 0000000..ec226fb
--- /dev/null
+++ b/javax/obex/Authenticator.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * 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 the Motorola, Inc. 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 HOLDER 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 javax.obex;
+
+/**
+ * This interface provides a way to respond to authentication challenge and
+ * authentication response headers. When a client or server receives an
+ * authentication challenge or authentication response header, the
+ * <code>onAuthenticationChallenge()</code> or
+ * <code>onAuthenticationResponse()</code> will be called, respectively, by the
+ * implementation.
+ * <P>
+ * For more information on how the authentication procedure works in OBEX,
+ * please review the IrOBEX specification at <A
+ * HREF="http://www.irda.org">http://www.irda.org</A>.
+ * <P>
+ * <STRONG>Authentication Challenges</STRONG>
+ * <P>
+ * When a client or server receives an authentication challenge header, the
+ * <code>onAuthenticationChallenge()</code> method will be invoked by the OBEX
+ * API implementation. The application will then return the user name (if
+ * needed) and password via a <code>PasswordAuthentication</code> object. The
+ * password in this object is not sent in the authentication response. Instead,
+ * the 16-byte challenge received in the authentication challenge is combined
+ * with the password returned from the <code>onAuthenticationChallenge()</code>
+ * method and passed through the MD5 hash algorithm. The resulting value is sent
+ * in the authentication response along with the user name if it was provided.
+ * <P>
+ * <STRONG>Authentication Responses</STRONG>
+ * <P>
+ * When a client or server receives an authentication response header, the
+ * <code>onAuthenticationResponse()</code> method is invoked by the API
+ * implementation with the user name received in the authentication response
+ * header. (The user name will be <code>null</code> if no user name was provided
+ * in the authentication response header.) The application must determine the
+ * correct password. This value should be returned from the
+ * <code>onAuthenticationResponse()</code> method. If the authentication request
+ * should fail without the implementation checking the password,
+ * <code>null</code> should be returned by the application. (This is needed for
+ * reasons like not recognizing the user name, etc.) If the returned value is
+ * not <code>null</code>, the OBEX API implementation will combine the password
+ * returned from the <code>onAuthenticationResponse()</code> method and
+ * challenge sent via the authentication challenge, apply the MD5 hash
+ * algorithm, and compare the result to the response hash received in the
+ * authentication response header. If the values are not equal, an
+ * <code>IOException</code> will be thrown if the client requested
+ * authentication. If the server requested authentication, the
+ * <code>onAuthenticationFailure()</code> method will be called on the
+ * <code>ServerRequestHandler</code> that failed authentication. The connection
+ * is <B>not</B> closed if authentication failed.
+ * @hide
+ */
+public interface Authenticator {
+
+    /**
+     * Called when a client or a server receives an authentication challenge
+     * header. It should respond to the challenge with a
+     * <code>PasswordAuthentication</code> that contains the correct user name
+     * and password for the challenge.
+     * @param description the description of which user name and password should
+     *        be used; if no description is provided in the authentication
+     *        challenge or the description is encoded in an encoding scheme that
+     *        is not supported, an empty string will be provided
+     * @param isUserIdRequired <code>true</code> if the user ID is required;
+     *        <code>false</code> if the user ID is not required
+     * @param isFullAccess <code>true</code> if full access to the server will
+     *        be granted; <code>false</code> if read only access will be granted
+     * @return a <code>PasswordAuthentication</code> object containing the user
+     *         name and password used for authentication
+     */
+    PasswordAuthentication onAuthenticationChallenge(String description, boolean isUserIdRequired,
+            boolean isFullAccess);
+
+    /**
+     * Called when a client or server receives an authentication response
+     * header. This method will provide the user name and expect the correct
+     * password to be returned.
+     * @param userName the user name provided in the authentication response; may
+     *        be <code>null</code>
+     * @return the correct password for the user name provided; if
+     *         <code>null</code> is returned then the authentication request
+     *         failed
+     */
+    byte[] onAuthenticationResponse(byte[] userName);
+}
diff --git a/javax/obex/BaseStream.java b/javax/obex/BaseStream.java
new file mode 100644
index 0000000..022ad4f
--- /dev/null
+++ b/javax/obex/BaseStream.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * 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 the Motorola, Inc. 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 HOLDER 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 javax.obex;
+
+import java.io.IOException;
+
+/**
+ * This interface defines the methods needed by a parent that uses the
+ * PrivateInputStream and PrivateOutputStream objects defined in this package.
+ * @hide
+ */
+public interface BaseStream {
+
+    /**
+     * Verifies that this object is still open.
+     * @throws IOException if the object is closed
+     */
+    void ensureOpen() throws IOException;
+
+    /**
+     * Verifies that additional information may be sent. In other words, the
+     * operation is not done.
+     * @throws IOException if the operation is completed
+     */
+    void ensureNotDone() throws IOException;
+
+    /**
+     * Continues the operation since there is no data to read.
+     * @param sendEmpty <code>true</code> if the operation should send an empty
+     *        packet or not send anything if there is no data to send
+     * @param inStream <code>true</code> if the stream is input stream or is
+     *        output stream
+     * @return <code>true</code> if the operation was completed;
+     *         <code>false</code> if no operation took place
+     * @throws IOException if an IO error occurs
+     */
+    boolean continueOperation(boolean sendEmpty, boolean inStream) throws IOException;
+
+    /**
+     * Called when the output or input stream is closed.
+     * @param inStream <code>true</code> if the input stream is closed;
+     *        <code>false</code> if the output stream is closed
+     * @throws IOException if an IO error occurs
+     */
+    void streamClosed(boolean inStream) throws IOException;
+}
diff --git a/javax/obex/ClientOperation.java b/javax/obex/ClientOperation.java
new file mode 100644
index 0000000..c627dfb
--- /dev/null
+++ b/javax/obex/ClientOperation.java
@@ -0,0 +1,851 @@
+/*
+ * Copyright (c) 2015 The Android Open Source Project
+ * Copyright (C) 2015 Samsung LSI
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * 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 the Motorola, Inc. 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 HOLDER 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 javax.obex;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.ByteArrayOutputStream;
+
+import android.util.Log;
+
+/**
+ * This class implements the <code>Operation</code> interface. It will read and
+ * write data via puts and gets.
+ * @hide
+ */
+public final class ClientOperation implements Operation, BaseStream {
+
+    private static final String TAG = "ClientOperation";
+
+    private static final boolean V = ObexHelper.VDBG;
+
+    private ClientSession mParent;
+
+    private boolean mInputOpen;
+
+    private PrivateInputStream mPrivateInput;
+
+    private boolean mPrivateInputOpen;
+
+    private PrivateOutputStream mPrivateOutput;
+
+    private boolean mPrivateOutputOpen;
+
+    private String mExceptionMessage;
+
+    private int mMaxPacketSize;
+
+    private boolean mOperationDone;
+
+    private boolean mGetOperation;
+
+    private boolean mGetFinalFlag;
+
+    private HeaderSet mRequestHeader;
+
+    private HeaderSet mReplyHeader;
+
+    private boolean mEndOfBodySent;
+
+    private boolean mSendBodyHeader = true;
+    // A latch - when triggered, there is not way back ;-)
+    private boolean mSrmActive = false;
+
+    // Assume SRM disabled - until support is confirmed
+    // by the server
+    private boolean mSrmEnabled = false;
+    // keep waiting until final-bit is received in request
+    // to handle the case where the SRM enable header is in
+    // a different OBEX packet than the SRMP header.
+    private boolean mSrmWaitingForRemote = true;
+
+
+    /**
+     * Creates new OperationImpl to read and write data to a server
+     * @param maxSize the maximum packet size
+     * @param p the parent to this object
+     * @param type <code>true</code> if this is a get request;
+     *        <code>false</code. if this is a put request
+     * @param header the header to set in the initial request
+     * @throws IOException if the an IO error occurred
+     */
+    public ClientOperation(int maxSize, ClientSession p, HeaderSet header, boolean type)
+            throws IOException {
+
+        mParent = p;
+        mEndOfBodySent = false;
+        mInputOpen = true;
+        mOperationDone = false;
+        mMaxPacketSize = maxSize;
+        mGetOperation = type;
+        mGetFinalFlag = false;
+
+        mPrivateInputOpen = false;
+        mPrivateOutputOpen = false;
+        mPrivateInput = null;
+        mPrivateOutput = null;
+
+        mReplyHeader = new HeaderSet();
+
+        mRequestHeader = new HeaderSet();
+
+        int[] headerList = header.getHeaderList();
+
+        if (headerList != null) {
+
+            for (int i = 0; i < headerList.length; i++) {
+                mRequestHeader.setHeader(headerList[i], header.getHeader(headerList[i]));
+            }
+        }
+
+        if ((header).mAuthChall != null) {
+            mRequestHeader.mAuthChall = new byte[(header).mAuthChall.length];
+            System.arraycopy((header).mAuthChall, 0, mRequestHeader.mAuthChall, 0,
+                    (header).mAuthChall.length);
+        }
+
+        if ((header).mAuthResp != null) {
+            mRequestHeader.mAuthResp = new byte[(header).mAuthResp.length];
+            System.arraycopy((header).mAuthResp, 0, mRequestHeader.mAuthResp, 0,
+                    (header).mAuthResp.length);
+
+        }
+
+        if ((header).mConnectionID != null) {
+            mRequestHeader.mConnectionID = new byte[4];
+            System.arraycopy((header).mConnectionID, 0, mRequestHeader.mConnectionID, 0,
+                    4);
+
+        }
+    }
+
+    /**
+     * Allows to set flag which will force GET to be always sent as single packet request with
+     * final flag set. This is to improve compatibility with some profiles, i.e. PBAP which
+     * require requests to be sent this way.
+     */
+    public void setGetFinalFlag(boolean flag) {
+        mGetFinalFlag = flag;
+    }
+
+    /**
+     * Sends an ABORT message to the server. By calling this method, the
+     * corresponding input and output streams will be closed along with this
+     * object.
+     * @throws IOException if the transaction has already ended or if an OBEX
+     *         server called this method
+     */
+    public synchronized void abort() throws IOException {
+        ensureOpen();
+        //no compatible with sun-ri
+        if ((mOperationDone) && (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE)) {
+            throw new IOException("Operation has already ended");
+        }
+
+        mExceptionMessage = "Operation aborted";
+        if ((!mOperationDone) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
+            mOperationDone = true;
+            /*
+             * Since we are not sending any headers or returning any headers then
+             * we just need to write and read the same bytes
+             */
+            mParent.sendRequest(ObexHelper.OBEX_OPCODE_ABORT, null, mReplyHeader, null, false);
+
+            if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_OK) {
+                throw new IOException("Invalid response code from server");
+            }
+
+            mExceptionMessage = null;
+        }
+
+        close();
+    }
+
+    /**
+     * Retrieves the response code retrieved from the server. Response codes are
+     * defined in the <code>ResponseCodes</code> interface.
+     * @return the response code retrieved from the server
+     * @throws IOException if an error occurred in the transport layer during
+     *         the transaction; if this method is called on a
+     *         <code>HeaderSet</code> object created by calling
+     *         <code>createHeaderSet</code> in a <code>ClientSession</code>
+     *         object
+     */
+    public synchronized int getResponseCode() throws IOException {
+        if ((mReplyHeader.responseCode == -1)
+                || (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
+            validateConnection();
+        }
+
+        return mReplyHeader.responseCode;
+    }
+
+    /**
+     * This method will always return <code>null</code>
+     * @return <code>null</code>
+     */
+    public String getEncoding() {
+        return null;
+    }
+
+    /**
+     * Returns the type of content that the resource connected to is providing.
+     * E.g. if the connection is via HTTP, then the value of the content-type
+     * header field is returned.
+     * @return the content type of the resource that the URL references, or
+     *         <code>null</code> if not known
+     */
+    public String getType() {
+        try {
+            return (String)mReplyHeader.getHeader(HeaderSet.TYPE);
+        } catch (IOException e) {
+            if(V) Log.d(TAG, "Exception occured - returning null",e);
+            return null;
+        }
+    }
+
+    /**
+     * Returns the length of the content which is being provided. E.g. if the
+     * connection is via HTTP, then the value of the content-length header field
+     * is returned.
+     * @return the content length of the resource that this connection's URL
+     *         references, or -1 if the content length is not known
+     */
+    public long getLength() {
+        try {
+            Long temp = (Long)mReplyHeader.getHeader(HeaderSet.LENGTH);
+
+            if (temp == null) {
+                return -1;
+            } else {
+                return temp.longValue();
+            }
+        } catch (IOException e) {
+            if(V) Log.d(TAG,"Exception occured - returning -1",e);
+            return -1;
+        }
+    }
+
+    /**
+     * Open and return an input stream for a connection.
+     * @return an input stream
+     * @throws IOException if an I/O error occurs
+     */
+    public InputStream openInputStream() throws IOException {
+
+        ensureOpen();
+
+        if (mPrivateInputOpen)
+            throw new IOException("no more input streams available");
+        if (mGetOperation) {
+            // send the GET request here
+            validateConnection();
+        } else {
+            if (mPrivateInput == null) {
+                mPrivateInput = new PrivateInputStream(this);
+            }
+        }
+
+        mPrivateInputOpen = true;
+
+        return mPrivateInput;
+    }
+
+    /**
+     * Open and return a data input stream for a connection.
+     * @return an input stream
+     * @throws IOException if an I/O error occurs
+     */
+    public DataInputStream openDataInputStream() throws IOException {
+        return new DataInputStream(openInputStream());
+    }
+
+    /**
+     * Open and return an output stream for a connection.
+     * @return an output stream
+     * @throws IOException if an I/O error occurs
+     */
+    public OutputStream openOutputStream() throws IOException {
+
+        ensureOpen();
+        ensureNotDone();
+
+        if (mPrivateOutputOpen)
+            throw new IOException("no more output streams available");
+
+        if (mPrivateOutput == null) {
+            // there are 3 bytes operation headers and 3 bytes body headers //
+            mPrivateOutput = new PrivateOutputStream(this, getMaxPacketSize());
+        }
+
+        mPrivateOutputOpen = true;
+
+        return mPrivateOutput;
+    }
+
+    public int getMaxPacketSize() {
+        return mMaxPacketSize - 6 - getHeaderLength();
+    }
+
+    public int getHeaderLength() {
+        // OPP may need it
+        byte[] headerArray = ObexHelper.createHeader(mRequestHeader, false);
+        return headerArray.length;
+    }
+
+    /**
+     * Open and return a data output stream for a connection.
+     * @return an output stream
+     * @throws IOException if an I/O error occurs
+     */
+    public DataOutputStream openDataOutputStream() throws IOException {
+        return new DataOutputStream(openOutputStream());
+    }
+
+    /**
+     * Closes the connection and ends the transaction
+     * @throws IOException if the operation has already ended or is closed
+     */
+    public void close() throws IOException {
+        mInputOpen = false;
+        mPrivateInputOpen = false;
+        mPrivateOutputOpen = false;
+        mParent.setRequestInactive();
+    }
+
+    /**
+     * Returns the headers that have been received during the operation.
+     * Modifying the object returned has no effect on the headers that are sent
+     * or retrieved.
+     * @return the headers received during this <code>Operation</code>
+     * @throws IOException if this <code>Operation</code> has been closed
+     */
+    public HeaderSet getReceivedHeader() throws IOException {
+        ensureOpen();
+
+        return mReplyHeader;
+    }
+
+    /**
+     * Specifies the headers that should be sent in the next OBEX message that
+     * is sent.
+     * @param headers the headers to send in the next message
+     * @throws IOException if this <code>Operation</code> has been closed or the
+     *         transaction has ended and no further messages will be exchanged
+     * @throws IllegalArgumentException if <code>headers</code> was not created
+     *         by a call to <code>ServerRequestHandler.createHeaderSet()</code>
+     * @throws NullPointerException if <code>headers</code> is <code>null</code>
+     */
+    public void sendHeaders(HeaderSet headers) throws IOException {
+        ensureOpen();
+        if (mOperationDone) {
+            throw new IOException("Operation has already exchanged all data");
+        }
+
+        if (headers == null) {
+            throw new IOException("Headers may not be null");
+        }
+
+        int[] headerList = headers.getHeaderList();
+        if (headerList != null) {
+            for (int i = 0; i < headerList.length; i++) {
+                mRequestHeader.setHeader(headerList[i], headers.getHeader(headerList[i]));
+            }
+        }
+    }
+
+    /**
+     * Verifies that additional information may be sent. In other words, the
+     * operation is not done.
+     * @throws IOException if the operation is completed
+     */
+    public void ensureNotDone() throws IOException {
+        if (mOperationDone) {
+            throw new IOException("Operation has completed");
+        }
+    }
+
+    /**
+     * Verifies that the connection is open and no exceptions should be thrown.
+     * @throws IOException if an exception needs to be thrown
+     */
+    public void ensureOpen() throws IOException {
+        mParent.ensureOpen();
+
+        if (mExceptionMessage != null) {
+            throw new IOException(mExceptionMessage);
+        }
+        if (!mInputOpen) {
+            throw new IOException("Operation has already ended");
+        }
+    }
+
+    /**
+     * Verifies that the connection is open and the proper data has been read.
+     * @throws IOException if an IO error occurs
+     */
+    private void validateConnection() throws IOException {
+        ensureOpen();
+
+        // Make sure that a response has been recieved from remote
+        // before continuing
+        if (mPrivateInput == null || mReplyHeader.responseCode == -1) {
+            startProcessing();
+        }
+    }
+
+    /**
+     * Sends a request to the client of the specified type.
+     * This function will enable SRM and set SRM active if the server
+     * response allows this.
+     * @param opCode the request code to send to the client
+     * @return <code>true</code> if there is more data to send;
+     *         <code>false</code> if there is no more data to send
+     * @throws IOException if an IO error occurs
+     */
+    private boolean sendRequest(int opCode) throws IOException {
+        boolean returnValue = false;
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        int bodyLength = -1;
+        byte[] headerArray = ObexHelper.createHeader(mRequestHeader, true);
+        if (mPrivateOutput != null) {
+            bodyLength = mPrivateOutput.size();
+        }
+
+        /*
+         * Determine if there is space to add a body request.  At present
+         * this method checks to see if there is room for at least a 17
+         * byte body header.  This number needs to be at least 6 so that
+         * there is room for the header ID and length and the reply ID and
+         * length, but it is a waste of resources if we can't send much of
+         * the body.
+         */
+        final int MINIMUM_BODY_LENGTH = 3;
+        if ((ObexHelper.BASE_PACKET_LENGTH + headerArray.length + MINIMUM_BODY_LENGTH)
+                > mMaxPacketSize) {
+            int end = 0;
+            int start = 0;
+            // split & send the headerArray in multiple packets.
+
+            while (end != headerArray.length) {
+                //split the headerArray
+
+                end = ObexHelper.findHeaderEnd(headerArray, start, mMaxPacketSize
+                        - ObexHelper.BASE_PACKET_LENGTH);
+                // can not split
+                if (end == -1) {
+                    mOperationDone = true;
+                    abort();
+                    mExceptionMessage = "Header larger then can be sent in a packet";
+                    mInputOpen = false;
+
+                    if (mPrivateInput != null) {
+                        mPrivateInput.close();
+                    }
+
+                    if (mPrivateOutput != null) {
+                        mPrivateOutput.close();
+                    }
+                    throw new IOException("OBEX Packet exceeds max packet size");
+                }
+
+                byte[] sendHeader = new byte[end - start];
+                System.arraycopy(headerArray, start, sendHeader, 0, sendHeader.length);
+                if (!mParent.sendRequest(opCode, sendHeader, mReplyHeader, mPrivateInput, false)) {
+                    return false;
+                }
+
+                if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
+                    return false;
+                }
+
+                start = end;
+            }
+
+            // Enable SRM if it should be enabled
+            checkForSrm();
+
+            if (bodyLength > 0) {
+                return true;
+            } else {
+                return false;
+            }
+        } else {
+            /* All headers will fit into a single package */
+            if(mSendBodyHeader == false) {
+                /* As we are not to send any body data, set the FINAL_BIT */
+                opCode |= ObexHelper.OBEX_OPCODE_FINAL_BIT_MASK;
+            }
+            out.write(headerArray);
+        }
+
+        if (bodyLength > 0) {
+            /*
+             * Determine if we can send the whole body or just part of
+             * the body.  Remember that there is the 3 bytes for the
+             * response message and 3 bytes for the header ID and length
+             */
+            if (bodyLength > (mMaxPacketSize - headerArray.length - 6)) {
+                returnValue = true;
+
+                bodyLength = mMaxPacketSize - headerArray.length - 6;
+            }
+
+            byte[] body = mPrivateOutput.readBytes(bodyLength);
+
+            /*
+             * Since this is a put request if the final bit is set or
+             * the output stream is closed we need to send the 0x49
+             * (End of Body) otherwise, we need to send 0x48 (Body)
+             */
+            if ((mPrivateOutput.isClosed()) && (!returnValue) && (!mEndOfBodySent)
+                    && ((opCode & ObexHelper.OBEX_OPCODE_FINAL_BIT_MASK) != 0)) {
+                out.write(HeaderSet.END_OF_BODY);
+                mEndOfBodySent = true;
+            } else {
+                out.write(HeaderSet.BODY);
+            }
+
+            bodyLength += 3;
+            out.write((byte)(bodyLength >> 8));
+            out.write((byte)bodyLength);
+
+            if (body != null) {
+                out.write(body);
+            }
+        }
+
+        if (mPrivateOutputOpen && bodyLength <= 0 && !mEndOfBodySent) {
+            // only 0x82 or 0x83 can send 0x49
+            if ((opCode & ObexHelper.OBEX_OPCODE_FINAL_BIT_MASK) == 0) {
+                out.write(HeaderSet.BODY);
+            } else {
+                out.write(HeaderSet.END_OF_BODY);
+                mEndOfBodySent = true;
+            }
+
+            bodyLength = 3;
+            out.write((byte)(bodyLength >> 8));
+            out.write((byte)bodyLength);
+        }
+
+        if (out.size() == 0) {
+            if (!mParent.sendRequest(opCode, null, mReplyHeader, mPrivateInput, mSrmActive)) {
+                return false;
+            }
+            // Enable SRM if it should be enabled
+            checkForSrm();
+            return returnValue;
+        }
+        if ((out.size() > 0)
+                && (!mParent.sendRequest(opCode, out.toByteArray(),
+                        mReplyHeader, mPrivateInput, mSrmActive))) {
+            return false;
+        }
+        // Enable SRM if it should be enabled
+        checkForSrm();
+
+        // send all of the output data in 0x48,
+        // send 0x49 with empty body
+        if ((mPrivateOutput != null) && (mPrivateOutput.size() > 0))
+            returnValue = true;
+
+        return returnValue;
+    }
+
+    private void checkForSrm() throws IOException {
+        Byte srmMode = (Byte)mReplyHeader.getHeader(HeaderSet.SINGLE_RESPONSE_MODE);
+        if(mParent.isSrmSupported() == true && srmMode != null
+                && srmMode == ObexHelper.OBEX_SRM_ENABLE) {
+            mSrmEnabled = true;
+        }
+        /**
+         * Call this only when a complete obex packet have been received.
+         * (This is not optimal, but the current design is not really suited to
+         * the way SRM is specified.)
+         * The BT usage of SRM is not really safe - it assumes that the SRMP will fit
+         * into every OBEX packet, hence if another header occupies the entire packet,
+         * the scheme will not work - unlikely though.
+         */
+        if(mSrmEnabled) {
+            mSrmWaitingForRemote = false;
+            Byte srmp = (Byte)mReplyHeader.getHeader(HeaderSet.SINGLE_RESPONSE_MODE_PARAMETER);
+            if(srmp != null && srmp == ObexHelper.OBEX_SRMP_WAIT) {
+                mSrmWaitingForRemote = true;
+                // Clear the wait header, as the absence of the header in the next packet
+                // indicates don't wait anymore.
+                mReplyHeader.setHeader(HeaderSet.SINGLE_RESPONSE_MODE_PARAMETER, null);
+            }
+        }
+        if((mSrmWaitingForRemote == false) && (mSrmEnabled == true)) {
+            mSrmActive = true;
+        }
+    }
+
+    /**
+     * This method starts the processing thread results. It will send the
+     * initial request. If the response takes more then one packet, a thread
+     * will be started to handle additional requests
+     * @throws IOException if an IO error occurs
+     */
+    private synchronized void startProcessing() throws IOException {
+
+        if (mPrivateInput == null) {
+            mPrivateInput = new PrivateInputStream(this);
+        }
+        boolean more = true;
+
+        if (mGetOperation) {
+            if (!mOperationDone) {
+                if (!mGetFinalFlag) {
+                    mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
+                    while ((more) && (mReplyHeader.responseCode ==
+                            ResponseCodes.OBEX_HTTP_CONTINUE)) {
+                        more = sendRequest(ObexHelper.OBEX_OPCODE_GET);
+                    }
+                    // For GET we need to loop until all headers have been sent,
+                    // And then we wait for the first continue package with the
+                    // reply.
+                    if (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
+                        mParent.sendRequest(ObexHelper.OBEX_OPCODE_GET_FINAL,
+                                null, mReplyHeader, mPrivateInput, mSrmActive);
+                    }
+                    if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
+                        mOperationDone = true;
+                    } else {
+                        checkForSrm();
+                    }
+                } else {
+                    more = sendRequest(ObexHelper.OBEX_OPCODE_GET_FINAL);
+
+                    if (more) {
+                        throw new IOException("FINAL_GET forced, data didn't fit into one packet");
+                    }
+
+                    mOperationDone = true;
+                }
+            }
+        } else {
+            // PUT operation
+            if (!mOperationDone) {
+                mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
+                while ((more) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
+                    more = sendRequest(ObexHelper.OBEX_OPCODE_PUT);
+                }
+            }
+
+            if (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
+                mParent.sendRequest(ObexHelper.OBEX_OPCODE_PUT_FINAL,
+                        null, mReplyHeader, mPrivateInput, mSrmActive);
+            }
+
+            if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
+                mOperationDone = true;
+            }
+        }
+    }
+
+    /**
+     * Continues the operation since there is no data to read.
+     * @param sendEmpty <code>true</code> if the operation should send an empty
+     *        packet or not send anything if there is no data to send
+     * @param inStream <code>true</code> if the stream is input stream or is
+     *        output stream
+     * @throws IOException if an IO error occurs
+     */
+    public synchronized boolean continueOperation(boolean sendEmpty, boolean inStream)
+            throws IOException {
+
+        // One path to the first put operation - the other one does not need to
+        // handle SRM, as all will fit into one packet.
+
+        if (mGetOperation) {
+            if ((inStream) && (!mOperationDone)) {
+                // to deal with inputstream in get operation
+                mParent.sendRequest(ObexHelper.OBEX_OPCODE_GET_FINAL,
+                        null, mReplyHeader, mPrivateInput, mSrmActive);
+                /*
+                  * Determine if that was not the last packet in the operation
+                  */
+                if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
+                    mOperationDone = true;
+                } else {
+                    checkForSrm();
+                }
+
+                return true;
+
+            } else if ((!inStream) && (!mOperationDone)) {
+                // to deal with outputstream in get operation
+
+                if (mPrivateInput == null) {
+                    mPrivateInput = new PrivateInputStream(this);
+                }
+
+                if (!mGetFinalFlag) {
+                    sendRequest(ObexHelper.OBEX_OPCODE_GET);
+                } else {
+                    sendRequest(ObexHelper.OBEX_OPCODE_GET_FINAL);
+                }
+                if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
+                    mOperationDone = true;
+                }
+                return true;
+
+            } else if (mOperationDone) {
+                return false;
+            }
+
+        } else {
+            // PUT operation
+            if ((!inStream) && (!mOperationDone)) {
+                // to deal with outputstream in put operation
+                if (mReplyHeader.responseCode == -1) {
+                    mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
+                }
+                sendRequest(ObexHelper.OBEX_OPCODE_PUT);
+                return true;
+            } else if ((inStream) && (!mOperationDone)) {
+                // How to deal with inputstream  in put operation ?
+                return false;
+
+            } else if (mOperationDone) {
+                return false;
+            }
+
+        }
+        return false;
+    }
+
+    /**
+     * Called when the output or input stream is closed.
+     * @param inStream <code>true</code> if the input stream is closed;
+     *        <code>false</code> if the output stream is closed
+     * @throws IOException if an IO error occurs
+     */
+    public void streamClosed(boolean inStream) throws IOException {
+        if (!mGetOperation) {
+            if ((!inStream) && (!mOperationDone)) {
+                // to deal with outputstream in put operation
+
+                boolean more = true;
+
+                if ((mPrivateOutput != null) && (mPrivateOutput.size() <= 0)) {
+                    byte[] headerArray = ObexHelper.createHeader(mRequestHeader, false);
+                    if (headerArray.length <= 0)
+                        more = false;
+                }
+                // If have not sent any data so send  all now
+                if (mReplyHeader.responseCode == -1) {
+                    mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
+                }
+
+                while ((more) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
+                    more = sendRequest(ObexHelper.OBEX_OPCODE_PUT);
+                }
+
+                /*
+                 * According to the IrOBEX specification, after the final put, you
+                 * only have a single reply to send.  so we don't need the while
+                 * loop.
+                 */
+                while (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
+
+                    sendRequest(ObexHelper.OBEX_OPCODE_PUT_FINAL);
+                }
+                mOperationDone = true;
+            } else if ((inStream) && (mOperationDone)) {
+                // how to deal with input stream in put stream ?
+                mOperationDone = true;
+            }
+        } else {
+            if ((inStream) && (!mOperationDone)) {
+
+                // to deal with inputstream in get operation
+                // Have not sent any data so send it all now
+
+                if (mReplyHeader.responseCode == -1) {
+                    mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
+                }
+
+                while (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE && !mOperationDone) {
+                    if (!sendRequest(ObexHelper.OBEX_OPCODE_GET_FINAL)) {
+                        break;
+                    }
+                }
+                while (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE && !mOperationDone) {
+                    mParent.sendRequest(ObexHelper.OBEX_OPCODE_GET_FINAL, null,
+                            mReplyHeader, mPrivateInput, false);
+                    // Regardless of the SRM state, wait for the response.
+                }
+                mOperationDone = true;
+            } else if ((!inStream) && (!mOperationDone)) {
+                // to deal with outputstream in get operation
+                // part of the data may have been sent in continueOperation.
+
+                boolean more = true;
+
+                if ((mPrivateOutput != null) && (mPrivateOutput.size() <= 0)) {
+                    byte[] headerArray = ObexHelper.createHeader(mRequestHeader, false);
+                    if (headerArray.length <= 0)
+                        more = false;
+                }
+
+                if (mPrivateInput == null) {
+                    mPrivateInput = new PrivateInputStream(this);
+                }
+                if ((mPrivateOutput != null) && (mPrivateOutput.size() <= 0))
+                    more = false;
+
+                mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
+                while ((more) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
+                    more = sendRequest(ObexHelper.OBEX_OPCODE_GET);
+                }
+                sendRequest(ObexHelper.OBEX_OPCODE_GET_FINAL);
+                //                parent.sendRequest(0x83, null, replyHeaders, privateInput);
+                if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
+                    mOperationDone = true;
+                }
+            }
+        }
+    }
+
+    public void noBodyHeader(){
+        mSendBodyHeader = false;
+    }
+}
diff --git a/javax/obex/ClientSession.java b/javax/obex/ClientSession.java
new file mode 100644
index 0000000..272a920
--- /dev/null
+++ b/javax/obex/ClientSession.java
@@ -0,0 +1,616 @@
+/*
+ * Copyright (c) 2015 The Android Open Source Project
+ * Copyright (C) 2015 Samsung LSI
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * 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 the Motorola, Inc. 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 HOLDER 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 javax.obex;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import android.util.Log;
+
+/**
+ * This class in an implementation of the OBEX ClientSession.
+ * @hide
+ */
+public final class ClientSession extends ObexSession {
+
+    private static final String TAG = "ClientSession";
+
+    private boolean mOpen;
+
+    // Determines if an OBEX layer connection has been established
+    private boolean mObexConnected;
+
+    private byte[] mConnectionId = null;
+
+    /*
+     * The max Packet size must be at least 255 according to the OBEX
+     * specification.
+     */
+    private int mMaxTxPacketSize = ObexHelper.LOWER_LIMIT_MAX_PACKET_SIZE;
+
+    private boolean mRequestActive;
+
+    private final InputStream mInput;
+
+    private final OutputStream mOutput;
+
+    private final boolean mLocalSrmSupported;
+
+    private final ObexTransport mTransport;
+
+    public ClientSession(final ObexTransport trans) throws IOException {
+        mInput = trans.openInputStream();
+        mOutput = trans.openOutputStream();
+        mOpen = true;
+        mRequestActive = false;
+        mLocalSrmSupported = trans.isSrmSupported();
+        mTransport = trans;
+    }
+
+    /**
+     * Create a ClientSession
+     * @param trans The transport to use for OBEX transactions
+     * @param supportsSrm True if Single Response Mode should be used e.g. if the
+     *        supplied transport is a TCP or l2cap channel.
+     * @throws IOException if it occurs while opening the transport streams.
+     */
+    public ClientSession(final ObexTransport trans, final boolean supportsSrm) throws IOException {
+        mInput = trans.openInputStream();
+        mOutput = trans.openOutputStream();
+        mOpen = true;
+        mRequestActive = false;
+        mLocalSrmSupported = supportsSrm;
+        mTransport = trans;
+    }
+
+    public HeaderSet connect(final HeaderSet header) throws IOException {
+        ensureOpen();
+        if (mObexConnected) {
+            throw new IOException("Already connected to server");
+        }
+        setRequestActive();
+
+        int totalLength = 4;
+        byte[] head = null;
+
+        // Determine the header byte array
+        if (header != null) {
+            if (header.nonce != null) {
+                mChallengeDigest = new byte[16];
+                System.arraycopy(header.nonce, 0, mChallengeDigest, 0, 16);
+            }
+            head = ObexHelper.createHeader(header, false);
+            totalLength += head.length;
+        }
+        /*
+        * Write the OBEX CONNECT packet to the server.
+        * Byte 0: 0x80
+        * Byte 1&2: Connect Packet Length
+        * Byte 3: OBEX Version Number (Presently, 0x10)
+        * Byte 4: Flags (For TCP 0x00)
+        * Byte 5&6: Max OBEX Packet Length (Defined in MAX_PACKET_SIZE)
+        * Byte 7 to n: headers
+        */
+        byte[] requestPacket = new byte[totalLength];
+        int maxRxPacketSize = ObexHelper.getMaxRxPacketSize(mTransport);
+        // We just need to start at  byte 3 since the sendRequest() method will
+        // handle the length and 0x80.
+        requestPacket[0] = (byte)0x10;
+        requestPacket[1] = (byte)0x00;
+        requestPacket[2] = (byte)(maxRxPacketSize >> 8);
+        requestPacket[3] = (byte)(maxRxPacketSize & 0xFF);
+        if (head != null) {
+            System.arraycopy(head, 0, requestPacket, 4, head.length);
+        }
+
+        // Since we are not yet connected, the peer max packet size is unknown,
+        // hence we are only guaranteed the server will use the first 7 bytes.
+        if ((requestPacket.length + 3) > ObexHelper.MAX_PACKET_SIZE_INT) {
+            throw new IOException("Packet size exceeds max packet size for connect");
+        }
+
+        HeaderSet returnHeaderSet = new HeaderSet();
+        sendRequest(ObexHelper.OBEX_OPCODE_CONNECT, requestPacket, returnHeaderSet, null, false);
+
+        /*
+        * Read the response from the OBEX server.
+        * Byte 0: Response Code (If successful then OBEX_HTTP_OK)
+        * Byte 1&2: Packet Length
+        * Byte 3: OBEX Version Number
+        * Byte 4: Flags3
+        * Byte 5&6: Max OBEX packet Length
+        * Byte 7 to n: Optional HeaderSet
+        */
+        if (returnHeaderSet.responseCode == ResponseCodes.OBEX_HTTP_OK) {
+            mObexConnected = true;
+        }
+        setRequestInactive();
+
+        return returnHeaderSet;
+    }
+
+    public Operation get(HeaderSet header) throws IOException {
+
+        if (!mObexConnected) {
+            throw new IOException("Not connected to the server");
+        }
+        setRequestActive();
+
+        ensureOpen();
+
+        HeaderSet head;
+        if (header == null) {
+            head = new HeaderSet();
+        } else {
+            head = header;
+            if (head.nonce != null) {
+                mChallengeDigest = new byte[16];
+                System.arraycopy(head.nonce, 0, mChallengeDigest, 0, 16);
+            }
+        }
+        // Add the connection ID if one exists
+        if (mConnectionId != null) {
+            head.mConnectionID = new byte[4];
+            System.arraycopy(mConnectionId, 0, head.mConnectionID, 0, 4);
+        }
+
+        if(mLocalSrmSupported) {
+            head.setHeader(HeaderSet.SINGLE_RESPONSE_MODE, ObexHelper.OBEX_SRM_ENABLE);
+            /* TODO: Consider creating an interface to get the wait state.
+             * On an android system, I cannot see when this is to be used.
+             * except perhaps if we are to wait for user accept on a push message.
+            if(getLocalWaitState()) {
+                head.setHeader(HeaderSet.SINGLE_RESPONSE_MODE_PARAMETER, ObexHelper.OBEX_SRMP_WAIT);
+            }
+            */
+        }
+
+        return new ClientOperation(mMaxTxPacketSize, this, head, true);
+    }
+
+    /**
+     * 0xCB Connection Id an identifier used for OBEX connection multiplexing
+     */
+    public void setConnectionID(long id) {
+        if ((id < 0) || (id > 0xFFFFFFFFL)) {
+            throw new IllegalArgumentException("Connection ID is not in a valid range");
+        }
+        mConnectionId = ObexHelper.convertToByteArray(id);
+    }
+
+    public HeaderSet delete(HeaderSet header) throws IOException {
+
+        Operation op = put(header);
+        op.getResponseCode();
+        HeaderSet returnValue = op.getReceivedHeader();
+        op.close();
+
+        return returnValue;
+    }
+
+    public HeaderSet disconnect(HeaderSet header) throws IOException {
+        if (!mObexConnected) {
+            throw new IOException("Not connected to the server");
+        }
+        setRequestActive();
+
+        ensureOpen();
+        // Determine the header byte array
+        byte[] head = null;
+        if (header != null) {
+            if (header.nonce != null) {
+                mChallengeDigest = new byte[16];
+                System.arraycopy(header.nonce, 0, mChallengeDigest, 0, 16);
+            }
+            // Add the connection ID if one exists
+            if (mConnectionId != null) {
+                header.mConnectionID = new byte[4];
+                System.arraycopy(mConnectionId, 0, header.mConnectionID, 0, 4);
+            }
+            head = ObexHelper.createHeader(header, false);
+
+            if ((head.length + 3) > mMaxTxPacketSize) {
+                throw new IOException("Packet size exceeds max packet size");
+            }
+        } else {
+            // Add the connection ID if one exists
+            if (mConnectionId != null) {
+                head = new byte[5];
+                head[0] = (byte)HeaderSet.CONNECTION_ID;
+                System.arraycopy(mConnectionId, 0, head, 1, 4);
+            }
+        }
+
+        HeaderSet returnHeaderSet = new HeaderSet();
+        sendRequest(ObexHelper.OBEX_OPCODE_DISCONNECT, head, returnHeaderSet, null, false);
+
+        /*
+         * An OBEX DISCONNECT reply from the server:
+         * Byte 1: Response code
+         * Bytes 2 & 3: packet size
+         * Bytes 4 & up: headers
+         */
+
+        /* response code , and header are ignored
+         * */
+
+        synchronized (this) {
+            mObexConnected = false;
+            setRequestInactive();
+        }
+
+        return returnHeaderSet;
+    }
+
+    public long getConnectionID() {
+
+        if (mConnectionId == null) {
+            return -1;
+        }
+        return ObexHelper.convertToLong(mConnectionId);
+    }
+
+    public Operation put(HeaderSet header) throws IOException {
+        if (!mObexConnected) {
+            throw new IOException("Not connected to the server");
+        }
+        setRequestActive();
+
+        ensureOpen();
+        HeaderSet head;
+        if (header == null) {
+            head = new HeaderSet();
+        } else {
+            head = header;
+            // when auth is initiated by client ,save the digest
+            if (head.nonce != null) {
+                mChallengeDigest = new byte[16];
+                System.arraycopy(head.nonce, 0, mChallengeDigest, 0, 16);
+            }
+        }
+
+        // Add the connection ID if one exists
+        if (mConnectionId != null) {
+
+            head.mConnectionID = new byte[4];
+            System.arraycopy(mConnectionId, 0, head.mConnectionID, 0, 4);
+        }
+
+        if(mLocalSrmSupported) {
+            head.setHeader(HeaderSet.SINGLE_RESPONSE_MODE, ObexHelper.OBEX_SRM_ENABLE);
+            /* TODO: Consider creating an interface to get the wait state.
+             * On an android system, I cannot see when this is to be used.
+            if(getLocalWaitState()) {
+                head.setHeader(HeaderSet.SINGLE_RESPONSE_MODE_PARAMETER, ObexHelper.OBEX_SRMP_WAIT);
+            }
+             */
+        }
+        return new ClientOperation(mMaxTxPacketSize, this, head, false);
+    }
+
+    public void setAuthenticator(Authenticator auth) throws IOException {
+        if (auth == null) {
+            throw new IOException("Authenticator may not be null");
+        }
+        mAuthenticator = auth;
+    }
+
+    public HeaderSet setPath(HeaderSet header, boolean backup, boolean create) throws IOException {
+        if (!mObexConnected) {
+            throw new IOException("Not connected to the server");
+        }
+        setRequestActive();
+        ensureOpen();
+
+        int totalLength = 2;
+        byte[] head = null;
+        HeaderSet headset;
+        if (header == null) {
+            headset = new HeaderSet();
+        } else {
+            headset = header;
+            if (headset.nonce != null) {
+                mChallengeDigest = new byte[16];
+                System.arraycopy(headset.nonce, 0, mChallengeDigest, 0, 16);
+            }
+        }
+
+        // when auth is initiated by client ,save the digest
+        if (headset.nonce != null) {
+            mChallengeDigest = new byte[16];
+            System.arraycopy(headset.nonce, 0, mChallengeDigest, 0, 16);
+        }
+
+        // Add the connection ID if one exists
+        if (mConnectionId != null) {
+            headset.mConnectionID = new byte[4];
+            System.arraycopy(mConnectionId, 0, headset.mConnectionID, 0, 4);
+        }
+
+        head = ObexHelper.createHeader(headset, false);
+        totalLength += head.length;
+
+        if (totalLength > mMaxTxPacketSize) {
+            throw new IOException("Packet size exceeds max packet size");
+        }
+
+        int flags = 0;
+        /*
+         * The backup flag bit is bit 0 so if we add 1, this will set that bit
+         */
+        if (backup) {
+            flags++;
+        }
+        /*
+         * The create bit is bit 1 so if we or with 2 the bit will be set.
+         */
+        if (!create) {
+            flags |= 2;
+        }
+
+        /*
+         * An OBEX SETPATH packet to the server:
+         * Byte 1: 0x85
+         * Byte 2 & 3: packet size
+         * Byte 4: flags
+         * Byte 5: constants
+         * Byte 6 & up: headers
+         */
+        byte[] packet = new byte[totalLength];
+        packet[0] = (byte)flags;
+        packet[1] = (byte)0x00;
+        if (headset != null) {
+            System.arraycopy(head, 0, packet, 2, head.length);
+        }
+
+        HeaderSet returnHeaderSet = new HeaderSet();
+        sendRequest(ObexHelper.OBEX_OPCODE_SETPATH, packet, returnHeaderSet, null, false);
+
+        /*
+         * An OBEX SETPATH reply from the server:
+         * Byte 1: Response code
+         * Bytes 2 & 3: packet size
+         * Bytes 4 & up: headers
+         */
+
+        setRequestInactive();
+
+        return returnHeaderSet;
+    }
+
+    /**
+     * Verifies that the connection is open.
+     * @throws IOException if the connection is closed
+     */
+    public synchronized void ensureOpen() throws IOException {
+        if (!mOpen) {
+            throw new IOException("Connection closed");
+        }
+    }
+
+    /**
+     * Set request inactive. Allows Put and get operation objects to tell this
+     * object when they are done.
+     */
+    /*package*/synchronized void setRequestInactive() {
+        mRequestActive = false;
+    }
+
+    /**
+     * Set request to active.
+     * @throws IOException if already active
+     */
+    private synchronized void setRequestActive() throws IOException {
+        if (mRequestActive) {
+            throw new IOException("OBEX request is already being performed");
+        }
+        mRequestActive = true;
+    }
+
+    /**
+     * Sends a standard request to the client. It will then wait for the reply
+     * and update the header set object provided. If any authentication headers
+     * (i.e. authentication challenge or authentication response) are received,
+     * they will be processed.
+     * @param opCode the type of request to send to the client
+     * @param head the headers to send to the client
+     * @param header the header object to update with the response
+     * @param privateInput the input stream used by the Operation object; null
+     *        if this is called on a CONNECT, SETPATH or DISCONNECT
+     * @return
+     *        <code>true</code> if the operation completed successfully;
+     *        <code>false</code> if an authentication response failed to pass
+     * @throws IOException if an IO error occurs
+     */
+    public boolean sendRequest(int opCode, byte[] head, HeaderSet header,
+            PrivateInputStream privateInput, boolean srmActive) throws IOException {
+        //check header length with local max size
+        if (head != null) {
+            if ((head.length + 3) > ObexHelper.MAX_PACKET_SIZE_INT) {
+                // TODO: This is an implementation limit - not a specification requirement.
+                throw new IOException("header too large ");
+            }
+        }
+
+        boolean skipSend = false;
+        boolean skipReceive = false;
+        if (srmActive == true) {
+            if (opCode == ObexHelper.OBEX_OPCODE_PUT) {
+                // we are in the middle of a SRM PUT operation, don't expect a continue.
+                skipReceive = true;
+            } else if (opCode == ObexHelper.OBEX_OPCODE_GET) {
+                // We are still sending the get request, send, but don't expect continue
+                // until the request is transfered (the final bit is set)
+                skipReceive = true;
+            } else if (opCode == ObexHelper.OBEX_OPCODE_GET_FINAL) {
+                // All done sending the request, expect data from the server, without
+                // sending continue.
+                skipSend = true;
+            }
+
+        }
+
+        int bytesReceived;
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        out.write((byte)opCode);
+
+        // Determine if there are any headers to send
+        if (head == null) {
+            out.write(0x00);
+            out.write(0x03);
+        } else {
+            out.write((byte)((head.length + 3) >> 8));
+            out.write((byte)(head.length + 3));
+            out.write(head);
+        }
+
+        if (!skipSend) {
+            // Write the request to the output stream and flush the stream
+            mOutput.write(out.toByteArray());
+            // TODO: is this really needed? if this flush is implemented
+            //       correctly, we will get a gap between each obex packet.
+            //       which is kind of the idea behind SRM to avoid.
+            //  Consider offloading to another thread (async action)
+            mOutput.flush();
+        }
+
+        if (!skipReceive) {
+            header.responseCode = mInput.read();
+
+            int length = ((mInput.read() << 8) | (mInput.read()));
+
+            if (length > ObexHelper.getMaxRxPacketSize(mTransport)) {
+                throw new IOException("Packet received exceeds packet size limit");
+            }
+            if (length > ObexHelper.BASE_PACKET_LENGTH) {
+                byte[] data = null;
+                if (opCode == ObexHelper.OBEX_OPCODE_CONNECT) {
+                    @SuppressWarnings("unused")
+                    int version = mInput.read();
+                    @SuppressWarnings("unused")
+                    int flags = mInput.read();
+                    mMaxTxPacketSize = (mInput.read() << 8) + mInput.read();
+
+                    //check with local max size
+                    if (mMaxTxPacketSize > ObexHelper.MAX_CLIENT_PACKET_SIZE) {
+                        mMaxTxPacketSize = ObexHelper.MAX_CLIENT_PACKET_SIZE;
+                    }
+
+                    // check with transport maximum size
+                    if(mMaxTxPacketSize > ObexHelper.getMaxTxPacketSize(mTransport)) {
+                        // To increase this size, increase the buffer size in L2CAP layer
+                        // in Bluedroid.
+                        Log.w(TAG, "An OBEX packet size of " + mMaxTxPacketSize + "was"
+                                + " requested. Transport only allows: "
+                                + ObexHelper.getMaxTxPacketSize(mTransport)
+                                + " Lowering limit to this value.");
+                        mMaxTxPacketSize = ObexHelper.getMaxTxPacketSize(mTransport);
+                    }
+
+                    if (length > 7) {
+                        data = new byte[length - 7];
+
+                        bytesReceived = mInput.read(data);
+                        while (bytesReceived != (length - 7)) {
+                            bytesReceived += mInput.read(data, bytesReceived, data.length
+                                    - bytesReceived);
+                        }
+                    } else {
+                        return true;
+                    }
+                } else {
+                    data = new byte[length - 3];
+                    bytesReceived = mInput.read(data);
+
+                    while (bytesReceived != (length - 3)) {
+                        bytesReceived += mInput.read(data, bytesReceived, data.length - bytesReceived);
+                    }
+                    if (opCode == ObexHelper.OBEX_OPCODE_ABORT) {
+                        return true;
+                    }
+                }
+
+                byte[] body = ObexHelper.updateHeaderSet(header, data);
+                if ((privateInput != null) && (body != null)) {
+                    privateInput.writeBytes(body, 1);
+                }
+
+                if (header.mConnectionID != null) {
+                    mConnectionId = new byte[4];
+                    System.arraycopy(header.mConnectionID, 0, mConnectionId, 0, 4);
+                }
+
+                if (header.mAuthResp != null) {
+                    if (!handleAuthResp(header.mAuthResp)) {
+                        setRequestInactive();
+                        throw new IOException("Authentication Failed");
+                    }
+                }
+
+                if ((header.responseCode == ResponseCodes.OBEX_HTTP_UNAUTHORIZED)
+                        && (header.mAuthChall != null)) {
+
+                    if (handleAuthChall(header)) {
+                        out.write((byte)HeaderSet.AUTH_RESPONSE);
+                        out.write((byte)((header.mAuthResp.length + 3) >> 8));
+                        out.write((byte)(header.mAuthResp.length + 3));
+                        out.write(header.mAuthResp);
+                        header.mAuthChall = null;
+                        header.mAuthResp = null;
+
+                        byte[] sendHeaders = new byte[out.size() - 3];
+                        System.arraycopy(out.toByteArray(), 3, sendHeaders, 0, sendHeaders.length);
+
+                        return sendRequest(opCode, sendHeaders, header, privateInput, false);
+                    }
+                }
+            }
+        }
+
+        return true;
+    }
+
+    public void close() throws IOException {
+        mOpen = false;
+        mInput.close();
+        mOutput.close();
+    }
+
+    public boolean isSrmSupported() {
+        return mLocalSrmSupported;
+    }
+}
diff --git a/javax/obex/HeaderSet.java b/javax/obex/HeaderSet.java
new file mode 100644
index 0000000..35fe186
--- /dev/null
+++ b/javax/obex/HeaderSet.java
@@ -0,0 +1,710 @@
+/*
+ * Copyright (c) 2014 The Android Open Source Project
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * 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 the Motorola, Inc. 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 HOLDER 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 javax.obex;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Calendar;
+import java.security.SecureRandom;
+
+/**
+ * This class implements the javax.obex.HeaderSet interface for OBEX over
+ * RFCOMM or OBEX over l2cap.
+ * @hide
+ */
+public final class HeaderSet {
+
+    /**
+     * Represents the OBEX Count header. This allows the connection statement to
+     * tell the server how many objects it plans to send or retrieve.
+     * <P>
+     * The value of <code>COUNT</code> is 0xC0 (192).
+     */
+    public static final int COUNT = 0xC0;
+
+    /**
+     * Represents the OBEX Name header. This specifies the name of the object.
+     * <P>
+     * The value of <code>NAME</code> is 0x01 (1).
+     */
+    public static final int NAME = 0x01;
+
+    /**
+     * Represents the OBEX Type header. This allows a request to specify the
+     * type of the object (e.g. text, html, binary, etc.).
+     * <P>
+     * The value of <code>TYPE</code> is 0x42 (66).
+     */
+    public static final int TYPE = 0x42;
+
+    /**
+     * Represents the OBEX Length header. This is the length of the object in
+     * bytes.
+     * <P>
+     * The value of <code>LENGTH</code> is 0xC3 (195).
+     */
+    public static final int LENGTH = 0xC3;
+
+    /**
+     * Represents the OBEX Time header using the ISO 8601 standards. This is the
+     * preferred time header.
+     * <P>
+     * The value of <code>TIME_ISO_8601</code> is 0x44 (68).
+     */
+    public static final int TIME_ISO_8601 = 0x44;
+
+    /**
+     * Represents the OBEX Time header using the 4 byte representation. This is
+     * only included for backwards compatibility. It represents the number of
+     * seconds since January 1, 1970.
+     * <P>
+     * The value of <code>TIME_4_BYTE</code> is 0xC4 (196).
+     */
+    public static final int TIME_4_BYTE = 0xC4;
+
+    /**
+     * Represents the OBEX Description header. This is a text description of the
+     * object.
+     * <P>
+     * The value of <code>DESCRIPTION</code> is 0x05 (5).
+     */
+    public static final int DESCRIPTION = 0x05;
+
+    /**
+     * Represents the OBEX Target header. This is the name of the service an
+     * operation is targeted to.
+     * <P>
+     * The value of <code>TARGET</code> is 0x46 (70).
+     */
+    public static final int TARGET = 0x46;
+
+    /**
+     * Represents the OBEX HTTP header. This allows an HTTP 1.X header to be
+     * included in a request or reply.
+     * <P>
+     * The value of <code>HTTP</code> is 0x47 (71).
+     */
+    public static final int HTTP = 0x47;
+
+    /**
+     * Represents the OBEX BODY header.
+     * <P>
+     * The value of <code>BODY</code> is 0x48 (72).
+     */
+    public static final int BODY = 0x48;
+
+    /**
+     * Represents the OBEX End of BODY header.
+     * <P>
+     * The value of <code>BODY</code> is 0x49 (73).
+     */
+    public static final int END_OF_BODY = 0x49;
+
+    /**
+     * Represents the OBEX Who header. Identifies the OBEX application to
+     * determine if the two peers are talking to each other.
+     * <P>
+     * The value of <code>WHO</code> is 0x4A (74).
+     */
+    public static final int WHO = 0x4A;
+
+    /**
+     * Represents the OBEX Connection ID header. Identifies used for OBEX
+     * connection multiplexing.
+     * <P>
+     * The value of <code>CONNECTION_ID</code> is 0xCB (203).
+     */
+
+    public static final int CONNECTION_ID = 0xCB;
+
+    /**
+     * Represents the OBEX Application Parameter header. This header specifies
+     * additional application request and response information.
+     * <P>
+     * The value of <code>APPLICATION_PARAMETER</code> is 0x4C (76).
+     */
+    public static final int APPLICATION_PARAMETER = 0x4C;
+
+    /**
+     * Represents the OBEX authentication digest-challenge.
+     * <P>
+     * The value of <code>AUTH_CHALLENGE</code> is 0x4D (77).
+     */
+    public static final int AUTH_CHALLENGE = 0x4D;
+
+    /**
+     * Represents the OBEX authentication digest-response.
+     * <P>
+     * The value of <code>AUTH_RESPONSE</code> is 0x4E (78).
+     */
+    public static final int AUTH_RESPONSE = 0x4E;
+
+    /**
+     * Represents the OBEX Object Class header. This header specifies the OBEX
+     * object class of the object.
+     * <P>
+     * The value of <code>OBJECT_CLASS</code> is 0x4F (79).
+     */
+    public static final int OBJECT_CLASS = 0x4F;
+
+    /**
+     * Represents the OBEX Single Response Mode (SRM). This header is used
+     * for Single response mode, introduced in OBEX 1.5.
+     * <P>
+     * The value of <code>SINGLE_RESPONSE_MODE</code> is 0x97 (151).
+     */
+    public static final int SINGLE_RESPONSE_MODE = 0x97;
+
+    /**
+     * Represents the OBEX Single Response Mode Parameters. This header is used
+     * for Single response mode, introduced in OBEX 1.5.
+     * <P>
+     * The value of <code>SINGLE_RESPONSE_MODE_PARAMETER</code> is 0x98 (152).
+     */
+    public static final int SINGLE_RESPONSE_MODE_PARAMETER = 0x98;
+
+    private Long mCount; // 4 byte unsigned integer
+
+    private String mName; // null terminated Unicode text string
+
+    private boolean mEmptyName;
+
+    private String mType; // null terminated ASCII text string
+
+    private Long mLength; // 4 byte unsigend integer
+
+    private Calendar mIsoTime; // String of the form YYYYMMDDTHHMMSSZ
+
+    private Calendar mByteTime; // 4 byte unsigned integer
+
+    private String mDescription; // null terminated Unicode text String
+
+    private byte[] mTarget; // byte sequence
+
+    private byte[] mHttpHeader; // byte sequence
+
+    private byte[] mWho; // length prefixed byte sequence
+
+    private byte[] mAppParam; // byte sequence of the form tag length value
+
+    private byte[] mObjectClass; // byte sequence
+
+    private String[] mUnicodeUserDefined; // null terminated unicode string
+
+    private byte[][] mSequenceUserDefined; // byte sequence user defined
+
+    private Byte[] mByteUserDefined; // 1 byte
+
+    private Long[] mIntegerUserDefined; // 4 byte unsigned integer
+
+    private SecureRandom mRandom = null;
+
+    private Byte mSingleResponseMode; // byte to indicate enable/disable/support for SRM
+
+    private Byte mSrmParam; // byte representing the SRM parameters - only "wait"
+                            // is supported by Bluetooth
+
+    /*package*/ byte[] nonce;
+
+    public byte[] mAuthChall; // The authentication challenge header
+
+    public byte[] mAuthResp; // The authentication response header
+
+    public byte[] mConnectionID; // THe connection ID
+
+    public int responseCode;
+
+    /**
+     * Creates new <code>HeaderSet</code> object.
+     * @param size the max packet size for this connection
+     */
+    public HeaderSet() {
+        mUnicodeUserDefined = new String[16];
+        mSequenceUserDefined = new byte[16][];
+        mByteUserDefined = new Byte[16];
+        mIntegerUserDefined = new Long[16];
+        responseCode = -1;
+    }
+
+    /**
+     * Sets flag for special "value" of NAME header which should be empty. This
+     * is not the same as NAME header with empty string in which case it will
+     * have length of 5 bytes. It should be 3 bytes with only header id and
+     * length field.
+     */
+    public void setEmptyNameHeader() {
+        mName = null;
+        mEmptyName = true;
+    }
+
+    /**
+     * Gets flag for special "value" of NAME header which should be empty. See
+     * above.
+     */
+    public boolean getEmptyNameHeader() {
+        return mEmptyName;
+    }
+
+    /**
+     * Sets the value of the header identifier to the value provided. The type
+     * of object must correspond to the Java type defined in the description of
+     * this interface. If <code>null</code> is passed as the
+     * <code>headerValue</code> then the header will be removed from the set of
+     * headers to include in the next request.
+     * @param headerID the identifier to include in the message
+     * @param headerValue the value of the header identifier
+     * @throws IllegalArgumentException if the header identifier provided is not
+     *         one defined in this interface or a user-defined header; if the
+     *         type of <code>headerValue</code> is not the correct Java type as
+     *         defined in the description of this interface\
+     */
+    public void setHeader(int headerID, Object headerValue) {
+        long temp = -1;
+
+        switch (headerID) {
+            case COUNT:
+                if (!(headerValue instanceof Long)) {
+                    if (headerValue == null) {
+                        mCount = null;
+                        break;
+                    }
+                    throw new IllegalArgumentException("Count must be a Long");
+                }
+                temp = ((Long)headerValue).longValue();
+                if ((temp < 0L) || (temp > 0xFFFFFFFFL)) {
+                    throw new IllegalArgumentException("Count must be between 0 and 0xFFFFFFFF");
+                }
+                mCount = (Long)headerValue;
+                break;
+            case NAME:
+                if ((headerValue != null) && (!(headerValue instanceof String))) {
+                    throw new IllegalArgumentException("Name must be a String");
+                }
+                mEmptyName = false;
+                mName = (String)headerValue;
+                break;
+            case TYPE:
+                if ((headerValue != null) && (!(headerValue instanceof String))) {
+                    throw new IllegalArgumentException("Type must be a String");
+                }
+                mType = (String)headerValue;
+                break;
+            case LENGTH:
+                if (!(headerValue instanceof Long)) {
+                    if (headerValue == null) {
+                        mLength = null;
+                        break;
+                    }
+                    throw new IllegalArgumentException("Length must be a Long");
+                }
+                temp = ((Long)headerValue).longValue();
+                if ((temp < 0L) || (temp > 0xFFFFFFFFL)) {
+                    throw new IllegalArgumentException("Length must be between 0 and 0xFFFFFFFF");
+                }
+                mLength = (Long)headerValue;
+                break;
+            case TIME_ISO_8601:
+                if ((headerValue != null) && (!(headerValue instanceof Calendar))) {
+                    throw new IllegalArgumentException("Time ISO 8601 must be a Calendar");
+                }
+                mIsoTime = (Calendar)headerValue;
+                break;
+            case TIME_4_BYTE:
+                if ((headerValue != null) && (!(headerValue instanceof Calendar))) {
+                    throw new IllegalArgumentException("Time 4 Byte must be a Calendar");
+                }
+                mByteTime = (Calendar)headerValue;
+                break;
+            case DESCRIPTION:
+                if ((headerValue != null) && (!(headerValue instanceof String))) {
+                    throw new IllegalArgumentException("Description must be a String");
+                }
+                mDescription = (String)headerValue;
+                break;
+            case TARGET:
+                if (headerValue == null) {
+                    mTarget = null;
+                } else {
+                    if (!(headerValue instanceof byte[])) {
+                        throw new IllegalArgumentException("Target must be a byte array");
+                    } else {
+                        mTarget = new byte[((byte[])headerValue).length];
+                        System.arraycopy(headerValue, 0, mTarget, 0, mTarget.length);
+                    }
+                }
+                break;
+            case HTTP:
+                if (headerValue == null) {
+                    mHttpHeader = null;
+                } else {
+                    if (!(headerValue instanceof byte[])) {
+                        throw new IllegalArgumentException("HTTP must be a byte array");
+                    } else {
+                        mHttpHeader = new byte[((byte[])headerValue).length];
+                        System.arraycopy(headerValue, 0, mHttpHeader, 0, mHttpHeader.length);
+                    }
+                }
+                break;
+            case WHO:
+                if (headerValue == null) {
+                    mWho = null;
+                } else {
+                    if (!(headerValue instanceof byte[])) {
+                        throw new IllegalArgumentException("WHO must be a byte array");
+                    } else {
+                        mWho = new byte[((byte[])headerValue).length];
+                        System.arraycopy(headerValue, 0, mWho, 0, mWho.length);
+                    }
+                }
+                break;
+            case OBJECT_CLASS:
+                if (headerValue == null) {
+                    mObjectClass = null;
+                } else {
+                    if (!(headerValue instanceof byte[])) {
+                        throw new IllegalArgumentException("Object Class must be a byte array");
+                    } else {
+                        mObjectClass = new byte[((byte[])headerValue).length];
+                        System.arraycopy(headerValue, 0, mObjectClass, 0, mObjectClass.length);
+                    }
+                }
+                break;
+            case APPLICATION_PARAMETER:
+                if (headerValue == null) {
+                    mAppParam = null;
+                } else {
+                    if (!(headerValue instanceof byte[])) {
+                        throw new IllegalArgumentException(
+                                "Application Parameter must be a byte array");
+                    } else {
+                        mAppParam = new byte[((byte[])headerValue).length];
+                        System.arraycopy(headerValue, 0, mAppParam, 0, mAppParam.length);
+                    }
+                }
+                break;
+            case SINGLE_RESPONSE_MODE:
+                if (headerValue == null) {
+                    mSingleResponseMode = null;
+                } else {
+                    if (!(headerValue instanceof Byte)) {
+                        throw new IllegalArgumentException(
+                                "Single Response Mode must be a Byte");
+                    } else {
+                        mSingleResponseMode = (Byte)headerValue;
+                    }
+                }
+                break;
+            case SINGLE_RESPONSE_MODE_PARAMETER:
+                if (headerValue == null) {
+                    mSrmParam = null;
+                } else {
+                    if (!(headerValue instanceof Byte)) {
+                        throw new IllegalArgumentException(
+                                "Single Response Mode Parameter must be a Byte");
+                    } else {
+                        mSrmParam = (Byte)headerValue;
+                    }
+                }
+                break;
+            default:
+                // Verify that it was not a Unicode String user Defined
+                if ((headerID >= 0x30) && (headerID <= 0x3F)) {
+                    if ((headerValue != null) && (!(headerValue instanceof String))) {
+                        throw new IllegalArgumentException(
+                                "Unicode String User Defined must be a String");
+                    }
+                    mUnicodeUserDefined[headerID - 0x30] = (String)headerValue;
+
+                    break;
+                }
+                // Verify that it was not a byte sequence user defined value
+                if ((headerID >= 0x70) && (headerID <= 0x7F)) {
+
+                    if (headerValue == null) {
+                        mSequenceUserDefined[headerID - 0x70] = null;
+                    } else {
+                        if (!(headerValue instanceof byte[])) {
+                            throw new IllegalArgumentException(
+                                    "Byte Sequence User Defined must be a byte array");
+                        } else {
+                            mSequenceUserDefined[headerID - 0x70] = new byte[((byte[])headerValue).length];
+                            System.arraycopy(headerValue, 0, mSequenceUserDefined[headerID - 0x70],
+                                    0, mSequenceUserDefined[headerID - 0x70].length);
+                        }
+                    }
+                    break;
+                }
+                // Verify that it was not a Byte user Defined
+                if ((headerID >= 0xB0) && (headerID <= 0xBF)) {
+                    if ((headerValue != null) && (!(headerValue instanceof Byte))) {
+                        throw new IllegalArgumentException("ByteUser Defined must be a Byte");
+                    }
+                    mByteUserDefined[headerID - 0xB0] = (Byte)headerValue;
+
+                    break;
+                }
+                // Verify that is was not the 4 byte unsigned integer user
+                // defined header
+                if ((headerID >= 0xF0) && (headerID <= 0xFF)) {
+                    if (!(headerValue instanceof Long)) {
+                        if (headerValue == null) {
+                            mIntegerUserDefined[headerID - 0xF0] = null;
+                            break;
+                        }
+                        throw new IllegalArgumentException("Integer User Defined must be a Long");
+                    }
+                    temp = ((Long)headerValue).longValue();
+                    if ((temp < 0L) || (temp > 0xFFFFFFFFL)) {
+                        throw new IllegalArgumentException(
+                                "Integer User Defined must be between 0 and 0xFFFFFFFF");
+                    }
+                    mIntegerUserDefined[headerID - 0xF0] = (Long)headerValue;
+                    break;
+                }
+                throw new IllegalArgumentException("Invalid Header Identifier");
+        }
+    }
+
+    /**
+     * Retrieves the value of the header identifier provided. The type of the
+     * Object returned is defined in the description of this interface.
+     * @param headerID the header identifier whose value is to be returned
+     * @return the value of the header provided or <code>null</code> if the
+     *         header identifier specified is not part of this
+     *         <code>HeaderSet</code> object
+     * @throws IllegalArgumentException if the <code>headerID</code> is not one
+     *         defined in this interface or any of the user-defined headers
+     * @throws IOException if an error occurred in the transport layer during
+     *         the operation or if the connection has been closed
+     */
+    public Object getHeader(int headerID) throws IOException {
+
+        switch (headerID) {
+            case COUNT:
+                return mCount;
+            case NAME:
+                return mName;
+            case TYPE:
+                return mType;
+            case LENGTH:
+                return mLength;
+            case TIME_ISO_8601:
+                return mIsoTime;
+            case TIME_4_BYTE:
+                return mByteTime;
+            case DESCRIPTION:
+                return mDescription;
+            case TARGET:
+                return mTarget;
+            case HTTP:
+                return mHttpHeader;
+            case WHO:
+                return mWho;
+            case CONNECTION_ID:
+                return mConnectionID;
+            case OBJECT_CLASS:
+                return mObjectClass;
+            case APPLICATION_PARAMETER:
+                return mAppParam;
+            case SINGLE_RESPONSE_MODE:
+                return mSingleResponseMode;
+            case SINGLE_RESPONSE_MODE_PARAMETER:
+                return mSrmParam;
+            default:
+                // Verify that it was not a Unicode String user Defined
+                if ((headerID >= 0x30) && (headerID <= 0x3F)) {
+                    return mUnicodeUserDefined[headerID - 0x30];
+                }
+                // Verify that it was not a byte sequence user defined header
+                if ((headerID >= 0x70) && (headerID <= 0x7F)) {
+                    return mSequenceUserDefined[headerID - 0x70];
+                }
+                // Verify that it was not a byte user defined header
+                if ((headerID >= 0xB0) && (headerID <= 0xBF)) {
+                    return mByteUserDefined[headerID - 0xB0];
+                }
+                // Verify that it was not a integer user defined header
+                if ((headerID >= 0xF0) && (headerID <= 0xFF)) {
+                    return mIntegerUserDefined[headerID - 0xF0];
+                }
+                throw new IllegalArgumentException("Invalid Header Identifier");
+        }
+    }
+
+    /**
+     * Retrieves the list of headers that may be retrieved via the
+     * <code>getHeader</code> method that will not return <code>null</code>. In
+     * other words, this method returns all the headers that are available in
+     * this object.
+     * @see #getHeader
+     * @return the array of headers that are set in this object or
+     *         <code>null</code> if no headers are available
+     * @throws IOException if an error occurred in the transport layer during
+     *         the operation or the connection has been closed
+     */
+    public int[] getHeaderList() throws IOException {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+        if (mCount != null) {
+            out.write(COUNT);
+        }
+        if (mName != null) {
+            out.write(NAME);
+        }
+        if (mType != null) {
+            out.write(TYPE);
+        }
+        if (mLength != null) {
+            out.write(LENGTH);
+        }
+        if (mIsoTime != null) {
+            out.write(TIME_ISO_8601);
+        }
+        if (mByteTime != null) {
+            out.write(TIME_4_BYTE);
+        }
+        if (mDescription != null) {
+            out.write(DESCRIPTION);
+        }
+        if (mTarget != null) {
+            out.write(TARGET);
+        }
+        if (mHttpHeader != null) {
+            out.write(HTTP);
+        }
+        if (mWho != null) {
+            out.write(WHO);
+        }
+        if (mAppParam != null) {
+            out.write(APPLICATION_PARAMETER);
+        }
+        if (mObjectClass != null) {
+            out.write(OBJECT_CLASS);
+        }
+        if(mSingleResponseMode != null) {
+            out.write(SINGLE_RESPONSE_MODE);
+        }
+        if(mSrmParam != null) {
+            out.write(SINGLE_RESPONSE_MODE_PARAMETER);
+        }
+
+        for (int i = 0x30; i < 0x40; i++) {
+            if (mUnicodeUserDefined[i - 0x30] != null) {
+                out.write(i);
+            }
+        }
+
+        for (int i = 0x70; i < 0x80; i++) {
+            if (mSequenceUserDefined[i - 0x70] != null) {
+                out.write(i);
+            }
+        }
+
+        for (int i = 0xB0; i < 0xC0; i++) {
+            if (mByteUserDefined[i - 0xB0] != null) {
+                out.write(i);
+            }
+        }
+
+        for (int i = 0xF0; i < 0x100; i++) {
+            if (mIntegerUserDefined[i - 0xF0] != null) {
+                out.write(i);
+            }
+        }
+
+        byte[] headers = out.toByteArray();
+        out.close();
+
+        if ((headers == null) || (headers.length == 0)) {
+            return null;
+        }
+
+        int[] result = new int[headers.length];
+        for (int i = 0; i < headers.length; i++) {
+            // Convert the byte to a positive integer.  That is, an integer
+            // between 0 and 256.
+            result[i] = headers[i] & 0xFF;
+        }
+
+        return result;
+    }
+
+    /**
+     * Sets the authentication challenge header. The <code>realm</code> will be
+     * encoded based upon the default encoding scheme used by the implementation
+     * to encode strings. Therefore, the encoding scheme used to encode the
+     * <code>realm</code> is application dependent.
+     * @param realm a short description that describes what password to use; if
+     *        <code>null</code> no realm will be sent in the authentication
+     *        challenge header
+     * @param userID if <code>true</code>, a user ID is required in the reply;
+     *        if <code>false</code>, no user ID is required
+     * @param access if <code>true</code> then full access will be granted if
+     *        successful; if <code>false</code> then read-only access will be
+     *        granted if successful
+     * @throws IOException
+     */
+    public void createAuthenticationChallenge(String realm, boolean userID, boolean access)
+            throws IOException {
+
+        nonce = new byte[16];
+        if(mRandom == null) {
+            mRandom = new SecureRandom();
+        }
+        for (int i = 0; i < 16; i++) {
+            nonce[i] = (byte)mRandom.nextInt();
+        }
+
+        mAuthChall = ObexHelper.computeAuthenticationChallenge(nonce, realm, access, userID);
+    }
+
+    /**
+     * Returns the response code received from the server. Response codes are
+     * defined in the <code>ResponseCodes</code> class.
+     * @see ResponseCodes
+     * @return the response code retrieved from the server
+     * @throws IOException if an error occurred in the transport layer during
+     *         the transaction; if this method is called on a
+     *         <code>HeaderSet</code> object created by calling
+     *         <code>createHeaderSet()</code> in a <code>ClientSession</code>
+     *         object; if this object was created by an OBEX server
+     */
+    public int getResponseCode() throws IOException {
+        if (responseCode == -1) {
+            throw new IOException("May not be called on a server");
+        } else {
+            return responseCode;
+        }
+    }
+}
diff --git a/javax/obex/ObexHelper.java b/javax/obex/ObexHelper.java
new file mode 100644
index 0000000..478297f
--- /dev/null
+++ b/javax/obex/ObexHelper.java
@@ -0,0 +1,1098 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2015 Samsung LSI
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * 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 the Motorola, Inc. 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 HOLDER 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 javax.obex;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.TimeZone;
+
+import android.util.Log;
+
+/**
+ * This class defines a set of helper methods for the implementation of Obex.
+ * @hide
+ */
+public final class ObexHelper {
+
+    private static final String TAG = "ObexHelper";
+    public static final boolean VDBG = false;
+    /**
+     * Defines the basic packet length used by OBEX. Every OBEX packet has the
+     * same basic format:<BR>
+     * Byte 0: Request or Response Code Byte 1&2: Length of the packet.
+     */
+    public static final int BASE_PACKET_LENGTH = 3;
+
+    /** Prevent object construction of helper class */
+    private ObexHelper() {
+    }
+
+    /**
+     * The maximum packet size for OBEX packets that this client can handle. At
+     * present, this must be changed for each port. TODO: The max packet size
+     * should be the Max incoming MTU minus TODO: L2CAP package headers and
+     * RFCOMM package headers. TODO: Retrieve the max incoming MTU from TODO:
+     * LocalDevice.getProperty().
+     * NOTE: This value must be larger than or equal to the L2CAP SDU
+     */
+    /*
+     * android note set as 0xFFFE to match remote MPS
+     */
+    public static final int MAX_PACKET_SIZE_INT = 0xFFFE;
+
+    // The minimum allowed max packet size is 255 according to the OBEX specification
+    public static final int LOWER_LIMIT_MAX_PACKET_SIZE = 255;
+
+    // The length of OBEX Byte Sequency Header Id according to the OBEX specification
+    public static final int OBEX_BYTE_SEQ_HEADER_LEN = 0x03;
+
+    /**
+     * Temporary workaround to be able to push files to Windows 7.
+     * TODO: Should be removed as soon as Microsoft updates their driver.
+     */
+    public static final int MAX_CLIENT_PACKET_SIZE = 0xFC00;
+
+    public static final int OBEX_OPCODE_FINAL_BIT_MASK = 0x80;
+
+    public static final int OBEX_OPCODE_CONNECT = 0x80;
+
+    public static final int OBEX_OPCODE_DISCONNECT = 0x81;
+
+    public static final int OBEX_OPCODE_PUT = 0x02;
+
+    public static final int OBEX_OPCODE_PUT_FINAL = 0x82;
+
+    public static final int OBEX_OPCODE_GET = 0x03;
+
+    public static final int OBEX_OPCODE_GET_FINAL = 0x83;
+
+    public static final int OBEX_OPCODE_RESERVED = 0x04;
+
+    public static final int OBEX_OPCODE_RESERVED_FINAL = 0x84;
+
+    public static final int OBEX_OPCODE_SETPATH = 0x85;
+
+    public static final int OBEX_OPCODE_ABORT = 0xFF;
+
+    public static final int OBEX_AUTH_REALM_CHARSET_ASCII = 0x00;
+
+    public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_1 = 0x01;
+
+    public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_2 = 0x02;
+
+    public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_3 = 0x03;
+
+    public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_4 = 0x04;
+
+    public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_5 = 0x05;
+
+    public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_6 = 0x06;
+
+    public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_7 = 0x07;
+
+    public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_8 = 0x08;
+
+    public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_9 = 0x09;
+
+    public static final int OBEX_AUTH_REALM_CHARSET_UNICODE = 0xFF;
+
+    public static final byte OBEX_SRM_ENABLE         = 0x01; // For BT we only need enable/disable
+    public static final byte OBEX_SRM_DISABLE        = 0x00;
+    public static final byte OBEX_SRM_SUPPORT        = 0x02; // Unused for now
+
+    public static final byte OBEX_SRMP_WAIT          = 0x01; // Only SRMP value used by BT
+
+    /**
+     * Updates the HeaderSet with the headers received in the byte array
+     * provided. Invalid headers are ignored.
+     * <P>
+     * The first two bits of an OBEX Header specifies the type of object that is
+     * being sent. The table below specifies the meaning of the high bits.
+     * <TABLE>
+     * <TR>
+     * <TH>Bits 8 and 7</TH>
+     * <TH>Value</TH>
+     * <TH>Description</TH>
+     * </TR>
+     * <TR>
+     * <TD>00</TD>
+     * <TD>0x00</TD>
+     * <TD>Null Terminated Unicode text, prefixed with 2 byte unsigned integer</TD>
+     * </TR>
+     * <TR>
+     * <TD>01</TD>
+     * <TD>0x40</TD>
+     * <TD>Byte Sequence, length prefixed with 2 byte unsigned integer</TD>
+     * </TR>
+     * <TR>
+     * <TD>10</TD>
+     * <TD>0x80</TD>
+     * <TD>1 byte quantity</TD>
+     * </TR>
+     * <TR>
+     * <TD>11</TD>
+     * <TD>0xC0</TD>
+     * <TD>4 byte quantity - transmitted in network byte order (high byte first</TD>
+     * </TR>
+     * </TABLE>
+     * This method uses the information in this table to determine the type of
+     * Java object to create and passes that object with the full header to
+     * setHeader() to update the HeaderSet object. Invalid headers will cause an
+     * exception to be thrown. When it is thrown, it is ignored.
+     * @param header the HeaderSet to update
+     * @param headerArray the byte array containing headers
+     * @return the result of the last start body or end body header provided;
+     *         the first byte in the result will specify if a body or end of
+     *         body is received
+     * @throws IOException if an invalid header was found
+     */
+    public static byte[] updateHeaderSet(HeaderSet header, byte[] headerArray) throws IOException {
+        int index = 0;
+        int length = 0;
+        int headerID;
+        byte[] value = null;
+        byte[] body = null;
+        HeaderSet headerImpl = header;
+        try {
+            while (index < headerArray.length) {
+                headerID = 0xFF & headerArray[index];
+                switch (headerID & (0xC0)) {
+
+                    /*
+                     * 0x00 is a unicode null terminate string with the first
+                     * two bytes after the header identifier being the length
+                     */
+                    case 0x00:
+                        // Fall through
+                        /*
+                         * 0x40 is a byte sequence with the first
+                         * two bytes after the header identifier being the length
+                         */
+                    case 0x40:
+                        boolean trimTail = true;
+                        index++;
+                        length = ((0xFF & headerArray[index]) << 8) +
+                                 (0xFF & headerArray[index + 1]);
+                        index += 2;
+                        if (length <= OBEX_BYTE_SEQ_HEADER_LEN) {
+                            Log.e(TAG, "Remote sent an OBEX packet with " +
+                                  "incorrect header length = " + length);
+                            break;
+                        }
+                        length -= OBEX_BYTE_SEQ_HEADER_LEN;
+                        value = new byte[length];
+                        System.arraycopy(headerArray, index, value, 0, length);
+                        if (length == 0 || (length > 0 && (value[length - 1] != 0))) {
+                            trimTail = false;
+                        }
+                        switch (headerID) {
+                            case HeaderSet.TYPE:
+                                try {
+                                    // Remove trailing null
+                                    if (trimTail == false) {
+                                        headerImpl.setHeader(headerID, new String(value, 0,
+                                                value.length, "ISO8859_1"));
+                                    } else {
+                                        headerImpl.setHeader(headerID, new String(value, 0,
+                                                value.length - 1, "ISO8859_1"));
+                                    }
+                                } catch (UnsupportedEncodingException e) {
+                                    throw e;
+                                }
+                                break;
+
+                            case HeaderSet.AUTH_CHALLENGE:
+                                headerImpl.mAuthChall = new byte[length];
+                                System.arraycopy(headerArray, index, headerImpl.mAuthChall, 0,
+                                        length);
+                                break;
+
+                            case HeaderSet.AUTH_RESPONSE:
+                                headerImpl.mAuthResp = new byte[length];
+                                System.arraycopy(headerArray, index, headerImpl.mAuthResp, 0,
+                                        length);
+                                break;
+
+                            case HeaderSet.BODY:
+                                /* Fall Through */
+                            case HeaderSet.END_OF_BODY:
+                                body = new byte[length + 1];
+                                body[0] = (byte)headerID;
+                                System.arraycopy(headerArray, index, body, 1, length);
+                                break;
+
+                            case HeaderSet.TIME_ISO_8601:
+                                try {
+                                    String dateString = new String(value, "ISO8859_1");
+                                    Calendar temp = Calendar.getInstance();
+                                    if ((dateString.length() == 16)
+                                            && (dateString.charAt(15) == 'Z')) {
+                                        temp.setTimeZone(TimeZone.getTimeZone("UTC"));
+                                    }
+                                    temp.set(Calendar.YEAR, Integer.parseInt(dateString.substring(
+                                            0, 4)));
+                                    temp.set(Calendar.MONTH, Integer.parseInt(dateString.substring(
+                                            4, 6)));
+                                    temp.set(Calendar.DAY_OF_MONTH, Integer.parseInt(dateString
+                                            .substring(6, 8)));
+                                    temp.set(Calendar.HOUR_OF_DAY, Integer.parseInt(dateString
+                                            .substring(9, 11)));
+                                    temp.set(Calendar.MINUTE, Integer.parseInt(dateString
+                                            .substring(11, 13)));
+                                    temp.set(Calendar.SECOND, Integer.parseInt(dateString
+                                            .substring(13, 15)));
+                                    headerImpl.setHeader(HeaderSet.TIME_ISO_8601, temp);
+                                } catch (UnsupportedEncodingException e) {
+                                    throw e;
+                                }
+                                break;
+
+                            default:
+                                if ((headerID & 0xC0) == 0x00) {
+                                    headerImpl.setHeader(headerID, ObexHelper.convertToUnicode(
+                                            value, true));
+                                } else {
+                                    headerImpl.setHeader(headerID, value);
+                                }
+                        }
+
+                        index += length;
+                        break;
+
+                    /*
+                     * 0x80 is a byte header.  The only valid byte headers are
+                     * the 16 user defined byte headers.
+                     */
+                    case 0x80:
+                        index++;
+                        try {
+                            headerImpl.setHeader(headerID, Byte.valueOf(headerArray[index]));
+                        } catch (Exception e) {
+                            // Not a valid header so ignore
+                        }
+                        index++;
+                        break;
+
+                    /*
+                     * 0xC0 is a 4 byte unsigned integer header and with the
+                     * exception of TIME_4_BYTE will be converted to a Long
+                     * and added.
+                     */
+                    case 0xC0:
+                        index++;
+                        value = new byte[4];
+                        System.arraycopy(headerArray, index, value, 0, 4);
+                        try {
+                            if (headerID != HeaderSet.TIME_4_BYTE) {
+                                // Determine if it is a connection ID.  These
+                                // need to be handled differently
+                                if (headerID == HeaderSet.CONNECTION_ID) {
+                                    headerImpl.mConnectionID = new byte[4];
+                                    System.arraycopy(value, 0, headerImpl.mConnectionID, 0, 4);
+                                } else {
+                                    headerImpl.setHeader(headerID, Long
+                                            .valueOf(convertToLong(value)));
+                                }
+                            } else {
+                                Calendar temp = Calendar.getInstance();
+                                temp.setTime(new Date(convertToLong(value) * 1000L));
+                                headerImpl.setHeader(HeaderSet.TIME_4_BYTE, temp);
+                            }
+                        } catch (Exception e) {
+                            // Not a valid header so ignore
+                            throw new IOException("Header was not formatted properly", e);
+                        }
+                        index += 4;
+                        break;
+                }
+
+            }
+        } catch (IOException e) {
+            throw new IOException("Header was not formatted properly", e);
+        }
+
+        return body;
+    }
+
+    /**
+     * Creates the header part of OBEX packet based on the header provided.
+     * TODO: Could use getHeaderList() to get the array of headers to include
+     * and then use the high two bits to determine the the type of the object
+     * and construct the byte array from that. This will make the size smaller.
+     * @param head the header used to construct the byte array
+     * @param nullOut <code>true</code> if the header should be set to
+     *        <code>null</code> once it is added to the array or
+     *        <code>false</code> if it should not be nulled out
+     * @return the header of an OBEX packet
+     */
+    public static byte[] createHeader(HeaderSet head, boolean nullOut) {
+        Long intHeader = null;
+        String stringHeader = null;
+        Calendar dateHeader = null;
+        Byte byteHeader = null;
+        StringBuffer buffer = null;
+        byte[] value = null;
+        byte[] result = null;
+        byte[] lengthArray = new byte[2];
+        int length;
+        HeaderSet headImpl = null;
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        headImpl = head;
+
+        try {
+            /*
+             * Determine if there is a connection ID to send.  If there is,
+             * then it should be the first header in the packet.
+             */
+            if ((headImpl.mConnectionID != null) && (headImpl.getHeader(HeaderSet.TARGET) == null)) {
+
+                out.write((byte)HeaderSet.CONNECTION_ID);
+                out.write(headImpl.mConnectionID);
+            }
+
+            // Count Header
+            intHeader = (Long)headImpl.getHeader(HeaderSet.COUNT);
+            if (intHeader != null) {
+                out.write((byte)HeaderSet.COUNT);
+                value = ObexHelper.convertToByteArray(intHeader.longValue());
+                out.write(value);
+                if (nullOut) {
+                    headImpl.setHeader(HeaderSet.COUNT, null);
+                }
+            }
+
+            // Name Header
+            stringHeader = (String)headImpl.getHeader(HeaderSet.NAME);
+            if (stringHeader != null) {
+                out.write((byte)HeaderSet.NAME);
+                value = ObexHelper.convertToUnicodeByteArray(stringHeader);
+                length = value.length + 3;
+                lengthArray[0] = (byte)(0xFF & (length >> 8));
+                lengthArray[1] = (byte)(0xFF & length);
+                out.write(lengthArray);
+                out.write(value);
+                if (nullOut) {
+                    headImpl.setHeader(HeaderSet.NAME, null);
+                }
+            } else if (headImpl.getEmptyNameHeader()) {
+                out.write((byte) HeaderSet.NAME);
+                lengthArray[0] = (byte) 0x00;
+                lengthArray[1] = (byte) 0x03;
+                out.write(lengthArray);
+            }
+
+            // Type Header
+            stringHeader = (String)headImpl.getHeader(HeaderSet.TYPE);
+            if (stringHeader != null) {
+                out.write((byte)HeaderSet.TYPE);
+                try {
+                    value = stringHeader.getBytes("ISO8859_1");
+                } catch (UnsupportedEncodingException e) {
+                    throw e;
+                }
+
+                length = value.length + 4;
+                lengthArray[0] = (byte)(255 & (length >> 8));
+                lengthArray[1] = (byte)(255 & length);
+                out.write(lengthArray);
+                out.write(value);
+                out.write(0x00);
+                if (nullOut) {
+                    headImpl.setHeader(HeaderSet.TYPE, null);
+                }
+            }
+
+            // Length Header
+            intHeader = (Long)headImpl.getHeader(HeaderSet.LENGTH);
+            if (intHeader != null) {
+                out.write((byte)HeaderSet.LENGTH);
+                value = ObexHelper.convertToByteArray(intHeader.longValue());
+                out.write(value);
+                if (nullOut) {
+                    headImpl.setHeader(HeaderSet.LENGTH, null);
+                }
+            }
+
+            // Time ISO Header
+            dateHeader = (Calendar)headImpl.getHeader(HeaderSet.TIME_ISO_8601);
+            if (dateHeader != null) {
+
+                /*
+                 * The ISO Header should take the form YYYYMMDDTHHMMSSZ.  The
+                 * 'Z' will only be included if it is a UTC time.
+                 */
+                buffer = new StringBuffer();
+                int temp = dateHeader.get(Calendar.YEAR);
+                for (int i = temp; i < 1000; i = i * 10) {
+                    buffer.append("0");
+                }
+                buffer.append(temp);
+                temp = dateHeader.get(Calendar.MONTH);
+                if (temp < 10) {
+                    buffer.append("0");
+                }
+                buffer.append(temp);
+                temp = dateHeader.get(Calendar.DAY_OF_MONTH);
+                if (temp < 10) {
+                    buffer.append("0");
+                }
+                buffer.append(temp);
+                buffer.append("T");
+                temp = dateHeader.get(Calendar.HOUR_OF_DAY);
+                if (temp < 10) {
+                    buffer.append("0");
+                }
+                buffer.append(temp);
+                temp = dateHeader.get(Calendar.MINUTE);
+                if (temp < 10) {
+                    buffer.append("0");
+                }
+                buffer.append(temp);
+                temp = dateHeader.get(Calendar.SECOND);
+                if (temp < 10) {
+                    buffer.append("0");
+                }
+                buffer.append(temp);
+
+                if (dateHeader.getTimeZone().getID().equals("UTC")) {
+                    buffer.append("Z");
+                }
+
+                try {
+                    value = buffer.toString().getBytes("ISO8859_1");
+                } catch (UnsupportedEncodingException e) {
+                    throw e;
+                }
+
+                length = value.length + 3;
+                lengthArray[0] = (byte)(255 & (length >> 8));
+                lengthArray[1] = (byte)(255 & length);
+                out.write(HeaderSet.TIME_ISO_8601);
+                out.write(lengthArray);
+                out.write(value);
+                if (nullOut) {
+                    headImpl.setHeader(HeaderSet.TIME_ISO_8601, null);
+                }
+            }
+
+            // Time 4 Byte Header
+            dateHeader = (Calendar)headImpl.getHeader(HeaderSet.TIME_4_BYTE);
+            if (dateHeader != null) {
+                out.write(HeaderSet.TIME_4_BYTE);
+
+                /*
+                 * Need to call getTime() twice.  The first call will return
+                 * a java.util.Date object.  The second call returns the number
+                 * of milliseconds since January 1, 1970.  We need to convert
+                 * it to seconds since the TIME_4_BYTE expects the number of
+                 * seconds since January 1, 1970.
+                 */
+                value = ObexHelper.convertToByteArray(dateHeader.getTime().getTime() / 1000L);
+                out.write(value);
+                if (nullOut) {
+                    headImpl.setHeader(HeaderSet.TIME_4_BYTE, null);
+                }
+            }
+
+            // Description Header
+            stringHeader = (String)headImpl.getHeader(HeaderSet.DESCRIPTION);
+            if (stringHeader != null) {
+                out.write((byte)HeaderSet.DESCRIPTION);
+                value = ObexHelper.convertToUnicodeByteArray(stringHeader);
+                length = value.length + 3;
+                lengthArray[0] = (byte)(255 & (length >> 8));
+                lengthArray[1] = (byte)(255 & length);
+                out.write(lengthArray);
+                out.write(value);
+                if (nullOut) {
+                    headImpl.setHeader(HeaderSet.DESCRIPTION, null);
+                }
+            }
+
+            // Target Header
+            value = (byte[])headImpl.getHeader(HeaderSet.TARGET);
+            if (value != null) {
+                out.write((byte)HeaderSet.TARGET);
+                length = value.length + 3;
+                lengthArray[0] = (byte)(255 & (length >> 8));
+                lengthArray[1] = (byte)(255 & length);
+                out.write(lengthArray);
+                out.write(value);
+                if (nullOut) {
+                    headImpl.setHeader(HeaderSet.TARGET, null);
+                }
+            }
+
+            // HTTP Header
+            value = (byte[])headImpl.getHeader(HeaderSet.HTTP);
+            if (value != null) {
+                out.write((byte)HeaderSet.HTTP);
+                length = value.length + 3;
+                lengthArray[0] = (byte)(255 & (length >> 8));
+                lengthArray[1] = (byte)(255 & length);
+                out.write(lengthArray);
+                out.write(value);
+                if (nullOut) {
+                    headImpl.setHeader(HeaderSet.HTTP, null);
+                }
+            }
+
+            // Who Header
+            value = (byte[])headImpl.getHeader(HeaderSet.WHO);
+            if (value != null) {
+                out.write((byte)HeaderSet.WHO);
+                length = value.length + 3;
+                lengthArray[0] = (byte)(255 & (length >> 8));
+                lengthArray[1] = (byte)(255 & length);
+                out.write(lengthArray);
+                out.write(value);
+                if (nullOut) {
+                    headImpl.setHeader(HeaderSet.WHO, null);
+                }
+            }
+
+            // Connection ID Header
+            value = (byte[])headImpl.getHeader(HeaderSet.APPLICATION_PARAMETER);
+            if (value != null) {
+                out.write((byte)HeaderSet.APPLICATION_PARAMETER);
+                length = value.length + 3;
+                lengthArray[0] = (byte)(255 & (length >> 8));
+                lengthArray[1] = (byte)(255 & length);
+                out.write(lengthArray);
+                out.write(value);
+                if (nullOut) {
+                    headImpl.setHeader(HeaderSet.APPLICATION_PARAMETER, null);
+                }
+            }
+
+            // Object Class Header
+            value = (byte[])headImpl.getHeader(HeaderSet.OBJECT_CLASS);
+            if (value != null) {
+                out.write((byte)HeaderSet.OBJECT_CLASS);
+                length = value.length + 3;
+                lengthArray[0] = (byte)(255 & (length >> 8));
+                lengthArray[1] = (byte)(255 & length);
+                out.write(lengthArray);
+                out.write(value);
+                if (nullOut) {
+                    headImpl.setHeader(HeaderSet.OBJECT_CLASS, null);
+                }
+            }
+
+            // Check User Defined Headers
+            for (int i = 0; i < 16; i++) {
+
+                //Unicode String Header
+                stringHeader = (String)headImpl.getHeader(i + 0x30);
+                if (stringHeader != null) {
+                    out.write((byte)i + 0x30);
+                    value = ObexHelper.convertToUnicodeByteArray(stringHeader);
+                    length = value.length + 3;
+                    lengthArray[0] = (byte)(255 & (length >> 8));
+                    lengthArray[1] = (byte)(255 & length);
+                    out.write(lengthArray);
+                    out.write(value);
+                    if (nullOut) {
+                        headImpl.setHeader(i + 0x30, null);
+                    }
+                }
+
+                // Byte Sequence Header
+                value = (byte[])headImpl.getHeader(i + 0x70);
+                if (value != null) {
+                    out.write((byte)i + 0x70);
+                    length = value.length + 3;
+                    lengthArray[0] = (byte)(255 & (length >> 8));
+                    lengthArray[1] = (byte)(255 & length);
+                    out.write(lengthArray);
+                    out.write(value);
+                    if (nullOut) {
+                        headImpl.setHeader(i + 0x70, null);
+                    }
+                }
+
+                // Byte Header
+                byteHeader = (Byte)headImpl.getHeader(i + 0xB0);
+                if (byteHeader != null) {
+                    out.write((byte)i + 0xB0);
+                    out.write(byteHeader.byteValue());
+                    if (nullOut) {
+                        headImpl.setHeader(i + 0xB0, null);
+                    }
+                }
+
+                // Integer header
+                intHeader = (Long)headImpl.getHeader(i + 0xF0);
+                if (intHeader != null) {
+                    out.write((byte)i + 0xF0);
+                    out.write(ObexHelper.convertToByteArray(intHeader.longValue()));
+                    if (nullOut) {
+                        headImpl.setHeader(i + 0xF0, null);
+                    }
+                }
+            }
+
+            // Add the authentication challenge header
+            if (headImpl.mAuthChall != null) {
+                out.write((byte)HeaderSet.AUTH_CHALLENGE);
+                length = headImpl.mAuthChall.length + 3;
+                lengthArray[0] = (byte)(255 & (length >> 8));
+                lengthArray[1] = (byte)(255 & length);
+                out.write(lengthArray);
+                out.write(headImpl.mAuthChall);
+                if (nullOut) {
+                    headImpl.mAuthChall = null;
+                }
+            }
+
+            // Add the authentication response header
+            if (headImpl.mAuthResp != null) {
+                out.write((byte)HeaderSet.AUTH_RESPONSE);
+                length = headImpl.mAuthResp.length + 3;
+                lengthArray[0] = (byte)(255 & (length >> 8));
+                lengthArray[1] = (byte)(255 & length);
+                out.write(lengthArray);
+                out.write(headImpl.mAuthResp);
+                if (nullOut) {
+                    headImpl.mAuthResp = null;
+                }
+            }
+
+            // TODO:
+            // If the SRM and SRMP header is in use, they must be send in the same OBEX packet
+            // But the current structure of the obex code cannot handle this, and therefore
+            // it makes sense to put them in the tail of the headers, since we then reduce the
+            // chance of enabling SRM to soon. The down side is that SRM cannot be used while
+            // transferring non-body headers
+
+            // Add the SRM header
+            byteHeader = (Byte)headImpl.getHeader(HeaderSet.SINGLE_RESPONSE_MODE);
+            if (byteHeader != null) {
+                out.write((byte)HeaderSet.SINGLE_RESPONSE_MODE);
+                out.write(byteHeader.byteValue());
+                if (nullOut) {
+                    headImpl.setHeader(HeaderSet.SINGLE_RESPONSE_MODE, null);
+                }
+            }
+
+            // Add the SRM parameter header
+            byteHeader = (Byte)headImpl.getHeader(HeaderSet.SINGLE_RESPONSE_MODE_PARAMETER);
+            if (byteHeader != null) {
+                out.write((byte)HeaderSet.SINGLE_RESPONSE_MODE_PARAMETER);
+                out.write(byteHeader.byteValue());
+                if (nullOut) {
+                    headImpl.setHeader(HeaderSet.SINGLE_RESPONSE_MODE_PARAMETER, null);
+                }
+            }
+
+        } catch (IOException e) {
+        } finally {
+            result = out.toByteArray();
+            try {
+                out.close();
+            } catch (Exception ex) {
+            }
+        }
+
+        return result;
+
+    }
+
+    /**
+     * Determines where the maximum divide is between headers. This method is
+     * used by put and get operations to separate headers to a size that meets
+     * the max packet size allowed.
+     * @param headerArray the headers to separate
+     * @param start the starting index to search
+     * @param maxSize the maximum size of a packet
+     * @return the index of the end of the header block to send or -1 if the
+     *         header could not be divided because the header is too large
+     */
+    public static int findHeaderEnd(byte[] headerArray, int start, int maxSize) {
+
+        int fullLength = 0;
+        int lastLength = -1;
+        int index = start;
+        int length = 0;
+
+        // TODO: Ensure SRM and SRMP headers are not split into two OBEX packets
+
+        while ((fullLength < maxSize) && (index < headerArray.length)) {
+            int headerID = (headerArray[index] < 0 ? headerArray[index] + 256 : headerArray[index]);
+            lastLength = fullLength;
+
+            switch (headerID & (0xC0)) {
+
+                case 0x00:
+                    // Fall through
+                case 0x40:
+
+                    index++;
+                    length = (headerArray[index] < 0 ? headerArray[index] + 256
+                            : headerArray[index]);
+                    length = length << 8;
+                    index++;
+                    length += (headerArray[index] < 0 ? headerArray[index] + 256
+                            : headerArray[index]);
+                    length -= 3;
+                    index++;
+                    index += length;
+                    fullLength += length + 3;
+                    break;
+
+                case 0x80:
+
+                    index++;
+                    index++;
+                    fullLength += 2;
+                    break;
+
+                case 0xC0:
+
+                    index += 5;
+                    fullLength += 5;
+                    break;
+
+            }
+
+        }
+
+        /*
+         * Determine if this is the last header or not
+         */
+        if (lastLength == 0) {
+            /*
+             * Since this is the last header, check to see if the size of this
+             * header is less then maxSize.  If it is, return the length of the
+             * header, otherwise return -1.  The length of the header is
+             * returned since it would be the start of the next header
+             */
+            if (fullLength < maxSize) {
+                return headerArray.length;
+            } else {
+                return -1;
+            }
+        } else {
+            return lastLength + start;
+        }
+    }
+
+    /**
+     * Converts the byte array to a long.
+     * @param b the byte array to convert to a long
+     * @return the byte array as a long
+     */
+    public static long convertToLong(byte[] b) {
+        long result = 0;
+        long value = 0;
+        long power = 0;
+
+        for (int i = (b.length - 1); i >= 0; i--) {
+            value = b[i];
+            if (value < 0) {
+                value += 256;
+            }
+
+            result = result | (value << power);
+            power += 8;
+        }
+
+        return result;
+    }
+
+    /**
+     * Converts the long to a 4 byte array. The long must be non negative.
+     * @param l the long to convert
+     * @return a byte array that is the same as the long
+     */
+    public static byte[] convertToByteArray(long l) {
+        byte[] b = new byte[4];
+
+        b[0] = (byte)(255 & (l >> 24));
+        b[1] = (byte)(255 & (l >> 16));
+        b[2] = (byte)(255 & (l >> 8));
+        b[3] = (byte)(255 & l);
+
+        return b;
+    }
+
+    /**
+     * Converts the String to a UNICODE byte array. It will also add the ending
+     * null characters to the end of the string.
+     * @param s the string to convert
+     * @return the unicode byte array of the string
+     */
+    public static byte[] convertToUnicodeByteArray(String s) {
+        if (s == null) {
+            return null;
+        }
+
+        char c[] = s.toCharArray();
+        byte[] result = new byte[(c.length * 2) + 2];
+        for (int i = 0; i < c.length; i++) {
+            result[(i * 2)] = (byte)(c[i] >> 8);
+            result[((i * 2) + 1)] = (byte)c[i];
+        }
+
+        // Add the UNICODE null character
+        result[result.length - 2] = 0;
+        result[result.length - 1] = 0;
+
+        return result;
+    }
+
+    /**
+     * Retrieves the value from the byte array for the tag value specified. The
+     * array should be of the form Tag - Length - Value triplet.
+     * @param tag the tag to retrieve from the byte array
+     * @param triplet the byte sequence containing the tag length value form
+     * @return the value of the specified tag
+     */
+    public static byte[] getTagValue(byte tag, byte[] triplet) {
+
+        int index = findTag(tag, triplet);
+        if (index == -1) {
+            return null;
+        }
+
+        index++;
+        int length = triplet[index] & 0xFF;
+
+        byte[] result = new byte[length];
+        index++;
+        System.arraycopy(triplet, index, result, 0, length);
+
+        return result;
+    }
+
+    /**
+     * Finds the index that starts the tag value pair in the byte array provide.
+     * @param tag the tag to look for
+     * @param value the byte array to search
+     * @return the starting index of the tag or -1 if the tag could not be found
+     */
+    public static int findTag(byte tag, byte[] value) {
+        int length = 0;
+
+        if (value == null) {
+            return -1;
+        }
+
+        int index = 0;
+
+        while ((index < value.length) && (value[index] != tag)) {
+            length = value[index + 1] & 0xFF;
+            index += length + 2;
+        }
+
+        if (index >= value.length) {
+            return -1;
+        }
+
+        return index;
+    }
+
+    /**
+     * Converts the byte array provided to a unicode string.
+     * @param b the byte array to convert to a string
+     * @param includesNull determine if the byte string provided contains the
+     *        UNICODE null character at the end or not; if it does, it will be
+     *        removed
+     * @return a Unicode string
+     * @throws IllegalArgumentException if the byte array has an odd length
+     */
+    public static String convertToUnicode(byte[] b, boolean includesNull) {
+        if (b == null || b.length == 0) {
+            return null;
+        }
+        int arrayLength = b.length;
+        if (!((arrayLength % 2) == 0)) {
+            throw new IllegalArgumentException("Byte array not of a valid form");
+        }
+        arrayLength = (arrayLength >> 1);
+        if (includesNull) {
+            arrayLength -= 1;
+        }
+
+        char[] c = new char[arrayLength];
+        for (int i = 0; i < arrayLength; i++) {
+            int upper = b[2 * i];
+            int lower = b[(2 * i) + 1];
+            if (upper < 0) {
+                upper += 256;
+            }
+            if (lower < 0) {
+                lower += 256;
+            }
+            // If upper and lower both equal 0, it should be the end of string.
+            // Ignore left bytes from array to avoid potential issues
+            if (upper == 0 && lower == 0) {
+                return new String(c, 0, i);
+            }
+
+            c[i] = (char)((upper << 8) | lower);
+        }
+
+        return new String(c);
+    }
+
+    /**
+     * Compute the MD5 hash of the byte array provided. Does not accumulate
+     * input.
+     * @param in the byte array to hash
+     * @return the MD5 hash of the byte array
+     */
+    public static byte[] computeMd5Hash(byte[] in) {
+        try {
+            MessageDigest md5 = MessageDigest.getInstance("MD5");
+            return md5.digest(in);
+        } catch (NoSuchAlgorithmException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Computes an authentication challenge header.
+     * @param nonce the challenge that will be provided to the peer; the
+     *        challenge must be 16 bytes long
+     * @param realm a short description that describes what password to use
+     * @param access if <code>true</code> then full access will be granted if
+     *        successful; if <code>false</code> then read only access will be
+     *        granted if successful
+     * @param userID if <code>true</code>, a user ID is required in the reply;
+     *        if <code>false</code>, no user ID is required
+     * @throws IllegalArgumentException if the challenge is not 16 bytes long;
+     *         if the realm can not be encoded in less then 255 bytes
+     * @throws IOException if the encoding scheme ISO 8859-1 is not supported
+     */
+    public static byte[] computeAuthenticationChallenge(byte[] nonce, String realm, boolean access,
+            boolean userID) throws IOException {
+        byte[] authChall = null;
+
+        if (nonce.length != 16) {
+            throw new IllegalArgumentException("Nonce must be 16 bytes long");
+        }
+
+        /*
+         * The authentication challenge is a byte sequence of the following form
+         * byte 0: 0x00 - the tag for the challenge
+         * byte 1: 0x10 - the length of the challenge; must be 16
+         * byte 2-17: the authentication challenge
+         * byte 18: 0x01 - the options tag; this is optional in the spec, but
+         *                 we are going to include it in every message
+         * byte 19: 0x01 - length of the options; must be 1
+         * byte 20: the value of the options; bit 0 is set if user ID is
+         *          required; bit 1 is set if access mode is read only
+         * byte 21: 0x02 - the tag for authentication realm; only included if
+         *                 an authentication realm is specified
+         * byte 22: the length of the authentication realm; only included if
+         *          the authentication realm is specified
+         * byte 23: the encoding scheme of the authentication realm; we will use
+         *          the ISO 8859-1 encoding scheme since it is part of the KVM
+         * byte 24 & up: the realm if one is specified.
+         */
+        if (realm == null) {
+            authChall = new byte[21];
+        } else {
+            if (realm.length() >= 255) {
+                throw new IllegalArgumentException("Realm must be less then 255 bytes");
+            }
+            authChall = new byte[24 + realm.length()];
+            authChall[21] = 0x02;
+            authChall[22] = (byte)(realm.length() + 1);
+            authChall[23] = 0x01; // ISO 8859-1 Encoding
+            System.arraycopy(realm.getBytes("ISO8859_1"), 0, authChall, 24, realm.length());
+        }
+
+        // Include the nonce field in the header
+        authChall[0] = 0x00;
+        authChall[1] = 0x10;
+        System.arraycopy(nonce, 0, authChall, 2, 16);
+
+        // Include the options header
+        authChall[18] = 0x01;
+        authChall[19] = 0x01;
+        authChall[20] = 0x00;
+
+        if (!access) {
+            authChall[20] = (byte)(authChall[20] | 0x02);
+        }
+        if (userID) {
+            authChall[20] = (byte)(authChall[20] | 0x01);
+        }
+
+        return authChall;
+    }
+
+    /**
+     * Return the maximum allowed OBEX packet to transmit.
+     * OBEX packets transmitted must be smaller than this value.
+     * @param transport Reference to the ObexTransport in use.
+     * @return the maximum allowed OBEX packet to transmit
+     */
+    public static int getMaxTxPacketSize(ObexTransport transport) {
+        int size = transport.getMaxTransmitPacketSize();
+        return validateMaxPacketSize(size);
+    }
+
+    /**
+     * Return the maximum allowed OBEX packet to receive - used in OBEX connect.
+     * @param transport
+     * @return he maximum allowed OBEX packet to receive
+     */
+    public static int getMaxRxPacketSize(ObexTransport transport) {
+        int size = transport.getMaxReceivePacketSize();
+        return validateMaxPacketSize(size);
+    }
+
+    private static int validateMaxPacketSize(int size) {
+        if(VDBG && (size > MAX_PACKET_SIZE_INT)) Log.w(TAG,
+                "The packet size supported for the connection (" + size + ") is larger"
+                + " than the configured OBEX packet size: " + MAX_PACKET_SIZE_INT);
+        if(size != -1) {
+            if(size < LOWER_LIMIT_MAX_PACKET_SIZE) {
+                throw new IllegalArgumentException(size + " is less that the lower limit: "
+                        + LOWER_LIMIT_MAX_PACKET_SIZE);
+            }
+            return size;
+        }
+        return MAX_PACKET_SIZE_INT;
+    }
+}
diff --git a/javax/obex/ObexPacket.java b/javax/obex/ObexPacket.java
new file mode 100644
index 0000000..bb6c96e
--- /dev/null
+++ b/javax/obex/ObexPacket.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2015 The Android Open Source Project
+ * Copyright (c) 2015 Samsung LSI
+ *
+ * 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 javax.obex;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ObexPacket {
+    public int mHeaderId;
+    public int mLength;
+    public byte[] mPayload = null;
+
+    private ObexPacket(int headerId, int length) {
+        mHeaderId = headerId;
+        mLength = length;
+    }
+
+    /**
+     * Create a complete OBEX packet by reading data from an InputStream.
+     * @param is the input stream to read from.
+     * @return the OBEX packet read.
+     * @throws IOException if an IO exception occurs during read.
+     */
+    public static ObexPacket read(InputStream is) throws IOException {
+        int headerId = is.read();
+        return read(headerId, is);
+    }
+
+    /**
+     * Read the remainder of an OBEX packet, with a specified headerId.
+     * @param headerId the headerId already read from the stream.
+     * @param is the stream to read from, assuming 1 byte have already been read.
+     * @return the OBEX packet read.
+     * @throws IOException
+     */
+    public static ObexPacket read(int headerId, InputStream is) throws IOException {
+        // Read the 2 byte length field from the stream
+        int length = is.read();
+        length = (length << 8) + is.read();
+
+        ObexPacket newPacket = new ObexPacket(headerId, length);
+
+        int bytesReceived;
+        byte[] temp = null;
+        if (length > 3) {
+            // First three bytes already read, compensating for this
+            temp = new byte[length - 3];
+            bytesReceived = is.read(temp);
+            while (bytesReceived != temp.length) {
+                bytesReceived += is.read(temp, bytesReceived, temp.length - bytesReceived);
+            }
+        }
+        newPacket.mPayload = temp;
+        return newPacket;
+    }
+}
diff --git a/javax/obex/ObexSession.java b/javax/obex/ObexSession.java
new file mode 100644
index 0000000..542b9c8
--- /dev/null
+++ b/javax/obex/ObexSession.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * 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 the Motorola, Inc. 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 HOLDER 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 javax.obex;
+
+import java.io.IOException;
+
+import android.util.Log;
+
+/**
+ * The <code>ObexSession</code> interface characterizes the term
+ * "OBEX Connection" as defined in the IrDA Object Exchange Protocol v1.2, which
+ * could be the server-side view of an OBEX connection, or the client-side view
+ * of the same connection, which is established by server's accepting of a
+ * client issued "CONNECT".
+ * <P>
+ * This interface serves as the common super class for
+ * <CODE>ClientSession</CODE> and <CODE>ServerSession</CODE>.
+ * @hide
+ */
+public class ObexSession {
+
+    private static final String TAG = "ObexSession";
+    private static final boolean V = ObexHelper.VDBG;
+
+    protected Authenticator mAuthenticator;
+
+    protected byte[] mChallengeDigest;
+
+    /**
+     * Called when the server received an authentication challenge header. This
+     * will cause the authenticator to handle the authentication challenge.
+     * @param header the header with the authentication challenge
+     * @return <code>true</code> if the last request should be resent;
+     *         <code>false</code> if the last request should not be resent
+     * @throws IOException
+     */
+    public boolean handleAuthChall(HeaderSet header) throws IOException {
+        if (mAuthenticator == null) {
+            return false;
+        }
+
+        /*
+         * An authentication challenge is made up of one required and two
+         * optional tag length value triplets. The tag 0x00 is required to be in
+         * the authentication challenge and it represents the challenge digest
+         * that was received. The tag 0x01 is the options tag. This tag tracks
+         * if user ID is required and if full access will be granted. The tag
+         * 0x02 is the realm, which provides a description of which user name
+         * and password to use.
+         */
+        byte[] challenge = ObexHelper.getTagValue((byte)0x00, header.mAuthChall);
+        byte[] option = ObexHelper.getTagValue((byte)0x01, header.mAuthChall);
+        byte[] description = ObexHelper.getTagValue((byte)0x02, header.mAuthChall);
+
+        String realm = null;
+        if (description != null) {
+            byte[] realmString = new byte[description.length - 1];
+            System.arraycopy(description, 1, realmString, 0, realmString.length);
+
+            switch (description[0] & 0xFF) {
+
+                case ObexHelper.OBEX_AUTH_REALM_CHARSET_ASCII:
+                    // ASCII encoding
+                    // Fall through
+                case ObexHelper.OBEX_AUTH_REALM_CHARSET_ISO_8859_1:
+                    // ISO-8859-1 encoding
+                    try {
+                        realm = new String(realmString, "ISO8859_1");
+                    } catch (Exception e) {
+                        throw new IOException("Unsupported Encoding Scheme");
+                    }
+                    break;
+
+                case ObexHelper.OBEX_AUTH_REALM_CHARSET_UNICODE:
+                    // UNICODE Encoding
+                    realm = ObexHelper.convertToUnicode(realmString, false);
+                    break;
+
+                default:
+                    throw new IOException("Unsupported Encoding Scheme");
+            }
+        }
+
+        boolean isUserIDRequired = false;
+        boolean isFullAccess = true;
+        if (option != null) {
+            if ((option[0] & 0x01) != 0) {
+                isUserIDRequired = true;
+            }
+
+            if ((option[0] & 0x02) != 0) {
+                isFullAccess = false;
+            }
+        }
+
+        PasswordAuthentication result = null;
+        header.mAuthChall = null;
+
+        try {
+            result = mAuthenticator
+                    .onAuthenticationChallenge(realm, isUserIDRequired, isFullAccess);
+        } catch (Exception e) {
+            if (V) Log.d(TAG, "Exception occured - returning false", e);
+            return false;
+        }
+
+        /*
+         * If no password is provided then we not resent the request
+         */
+        if (result == null) {
+            return false;
+        }
+
+        byte[] password = result.getPassword();
+        if (password == null) {
+            return false;
+        }
+
+        byte[] userName = result.getUserName();
+
+        /*
+         * Create the authentication response header. It includes 1 required and
+         * 2 option tag length value triples. The required triple has a tag of
+         * 0x00 and is the response digest. The first optional tag is 0x01 and
+         * represents the user ID. If no user ID is provided, then no user ID
+         * will be sent. The second optional tag is 0x02 and is the challenge
+         * that was received. This will always be sent
+         */
+        if (userName != null) {
+            header.mAuthResp = new byte[38 + userName.length];
+            header.mAuthResp[36] = (byte)0x01;
+            header.mAuthResp[37] = (byte)userName.length;
+            System.arraycopy(userName, 0, header.mAuthResp, 38, userName.length);
+        } else {
+            header.mAuthResp = new byte[36];
+        }
+
+        // Create the secret String
+        byte[] digest = new byte[challenge.length + password.length + 1];
+        System.arraycopy(challenge, 0, digest, 0, challenge.length);
+        // Insert colon between challenge and password
+        digest[challenge.length] = (byte)0x3A;
+        System.arraycopy(password, 0, digest, challenge.length + 1, password.length);
+
+        // Add the Response Digest
+        header.mAuthResp[0] = (byte)0x00;
+        header.mAuthResp[1] = (byte)0x10;
+
+        System.arraycopy(ObexHelper.computeMd5Hash(digest), 0, header.mAuthResp, 2, 16);
+
+        // Add the challenge
+        header.mAuthResp[18] = (byte)0x02;
+        header.mAuthResp[19] = (byte)0x10;
+        System.arraycopy(challenge, 0, header.mAuthResp, 20, 16);
+
+        return true;
+    }
+
+    /**
+     * Called when the server received an authentication response header. This
+     * will cause the authenticator to handle the authentication response.
+     * @param authResp the authentication response
+     * @return <code>true</code> if the response passed; <code>false</code> if
+     *         the response failed
+     */
+    public boolean handleAuthResp(byte[] authResp) {
+        if (mAuthenticator == null) {
+            return false;
+        }
+        // get the correct password from the application
+        byte[] correctPassword = mAuthenticator.onAuthenticationResponse(ObexHelper.getTagValue(
+                (byte)0x01, authResp));
+        if (correctPassword == null) {
+            return false;
+        }
+
+        byte[] temp = new byte[correctPassword.length + 16];
+
+        System.arraycopy(mChallengeDigest, 0, temp, 0, 16);
+        System.arraycopy(correctPassword, 0, temp, 16, correctPassword.length);
+
+        byte[] correctResponse = ObexHelper.computeMd5Hash(temp);
+        byte[] actualResponse = ObexHelper.getTagValue((byte)0x00, authResp);
+
+        // compare the MD5 hash array .
+        for (int i = 0; i < 16; i++) {
+            if (correctResponse[i] != actualResponse[i]) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+}
diff --git a/javax/obex/ObexTransport.java b/javax/obex/ObexTransport.java
new file mode 100644
index 0000000..a5a75f5
--- /dev/null
+++ b/javax/obex/ObexTransport.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * 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 the Motorola, Inc. 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 HOLDER 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 javax.obex;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * The <code>ObexTransport</code> interface defines the underlying transport
+ * connection which carries the OBEX protocol( such as TCP, RFCOMM device file
+ * exposed by Bluetooth or USB in kernel, RFCOMM socket emulated in Android
+ * platform, Irda). This interface provides an abstract layer to be used by the
+ * <code>ObexConnection</code>. Each kind of medium shall have its own
+ * implementation to wrap and follow the same interface.
+ * <P>
+ * See section 1.2.2 of IrDA Object Exchange Protocol specification.
+ * <P>
+ * Different kind of medium may have different construction - for example, the
+ * RFCOMM device file medium may be constructed from a file descriptor or simply
+ * a string while the TCP medium usually from a socket.
+ * @hide
+ */
+public interface ObexTransport {
+
+    void create() throws IOException;
+
+    void listen() throws IOException;
+
+    void close() throws IOException;
+
+    void connect() throws IOException;
+
+    void disconnect() throws IOException;
+
+    InputStream openInputStream() throws IOException;
+
+    OutputStream openOutputStream() throws IOException;
+
+    DataInputStream openDataInputStream() throws IOException;
+
+    DataOutputStream openDataOutputStream() throws IOException;
+
+    /**
+     * Must return the maximum allowed OBEX packet that can be sent over
+     * the transport. For L2CAP this will be the Max SDU reported by the
+     * peer device.
+     * The returned value will be used to set the outgoing OBEX packet
+     * size. Therefore this value shall not change.
+     * For RFCOMM or other transport types where the OBEX packets size
+     * is unrelated to the transport packet size, return -1;
+     * @return the maximum allowed OBEX packet that can be send over
+     *         the transport. Or -1 in case of don't care.
+     */
+    int getMaxTransmitPacketSize();
+
+    /**
+     * Must return the maximum allowed OBEX packet that can be received over
+     * the transport. For L2CAP this will be the Max SDU configured for the
+     * L2CAP channel.
+     * The returned value will be used to validate the incoming packet size
+     * values.
+     * For RFCOMM or other transport types where the OBEX packets size
+     * is unrelated to the transport packet size, return -1;
+     * @return the maximum allowed OBEX packet that can be send over
+     *         the transport. Or -1 in case of don't care.
+     */
+    int getMaxReceivePacketSize();
+
+    /**
+     * Shall return true if the transport in use supports SRM.
+     * @return
+     *        <code>true</code> if SRM operation is supported, and is to be enabled.
+     *        <code>false</code> if SRM operations are not supported, or should not be used.
+     */
+    boolean isSrmSupported();
+
+
+}
diff --git a/javax/obex/Operation.java b/javax/obex/Operation.java
new file mode 100644
index 0000000..5b4d5ac
--- /dev/null
+++ b/javax/obex/Operation.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * 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 the Motorola, Inc. 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 HOLDER 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 javax.obex;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * The <code>Operation</code> interface provides ways to manipulate a single
+ * OBEX PUT or GET operation. The implementation of this interface sends OBEX
+ * packets as they are built. If during the operation the peer in the operation
+ * ends the operation, an <code>IOException</code> is thrown on the next read
+ * from the input stream, write to the output stream, or call to
+ * <code>sendHeaders()</code>.
+ * <P>
+ * <STRONG>Definition of methods inherited from <code>ContentConnection</code>
+ * </STRONG>
+ * <P>
+ * <code>getEncoding()</code> will always return <code>null</code>. <BR>
+ * <code>getLength()</code> will return the length specified by the OBEX Length
+ * header or -1 if the OBEX Length header was not included. <BR>
+ * <code>getType()</code> will return the value specified in the OBEX Type
+ * header or <code>null</code> if the OBEX Type header was not included.<BR>
+ * <P>
+ * <STRONG>How Headers are Handled</STRONG>
+ * <P>
+ * As headers are received, they may be retrieved through the
+ * <code>getReceivedHeaders()</code> method. If new headers are set during the
+ * operation, the new headers will be sent during the next packet exchange.
+ * <P>
+ * <STRONG>PUT example</STRONG>
+ * <P>
+ * <PRE>
+ * void putObjectViaOBEX(ClientSession conn, HeaderSet head, byte[] obj) throws IOException {
+ *     // Include the length header
+ *     head.setHeader(head.LENGTH, new Long(obj.length));
+ *     // Initiate the PUT request
+ *     Operation op = conn.put(head);
+ *     // Open the output stream to put the object to it
+ *     DataOutputStream out = op.openDataOutputStream();
+ *     // Send the object to the server
+ *     out.write(obj);
+ *     // End the transaction
+ *     out.close();
+ *     op.close();
+ * }
+ * </PRE>
+ * <P>
+ * <STRONG>GET example</STRONG>
+ * <P>
+ * <PRE>
+ * byte[] getObjectViaOBEX(ClientSession conn, HeaderSet head) throws IOException {
+ *     // Send the initial GET request to the server
+ *     Operation op = conn.get(head);
+ *     // Retrieve the length of the object being sent back
+ *     int length = op.getLength();
+ *     // Create space for the object
+ *     byte[] obj = new byte[length];
+ *     // Get the object from the input stream
+ *     DataInputStream in = trans.openDataInputStream();
+ *     in.read(obj);
+ *     // End the transaction
+ *     in.close();
+ *     op.close();
+ *     return obj;
+ * }
+ * </PRE>
+ *
+ * <H3>Client PUT Operation Flow</H3> For PUT operations, a call to
+ * <code>close()</code> the <code>OutputStream</code> returned from
+ * <code>openOutputStream()</code> or <code>openDataOutputStream()</code> will
+ * signal that the request is done. (In OBEX terms, the End-Of-Body header
+ * should be sent and the final bit in the request will be set.) At this point,
+ * the reply from the server may begin to be processed. A call to
+ * <code>getResponseCode()</code> will do an implicit close on the
+ * <code>OutputStream</code> and therefore signal that the request is done.
+ * <H3>Client GET Operation Flow</H3> For GET operation, a call to
+ * <code>openInputStream()</code> or <code>openDataInputStream()</code> will
+ * signal that the request is done. (In OBEX terms, the final bit in the request
+ * will be set.) A call to <code>getResponseCode()</code> will cause an implicit
+ * close on the <code>InputStream</code>. No further data may be read at this
+ * point.
+ * @hide
+ */
+public interface Operation {
+
+    /**
+     * Sends an ABORT message to the server. By calling this method, the
+     * corresponding input and output streams will be closed along with this
+     * object. No headers are sent in the abort request. This will end the
+     * operation since <code>close()</code> will be called by this method.
+     * @throws IOException if the transaction has already ended or if an OBEX
+     *         server calls this method
+     */
+    void abort() throws IOException;
+
+    /**
+     * Returns the headers that have been received during the operation.
+     * Modifying the object returned has no effect on the headers that are sent
+     * or retrieved.
+     * @return the headers received during this <code>Operation</code>
+     * @throws IOException if this <code>Operation</code> has been closed
+     */
+    HeaderSet getReceivedHeader() throws IOException;
+
+    /**
+     * Specifies the headers that should be sent in the next OBEX message that
+     * is sent.
+     * @param headers the headers to send in the next message
+     * @throws IOException if this <code>Operation</code> has been closed or the
+     *         transaction has ended and no further messages will be exchanged
+     * @throws IllegalArgumentException if <code>headers</code> was not created
+     *         by a call to <code>ServerRequestHandler.createHeaderSet()</code>
+     *         or <code>ClientSession.createHeaderSet()</code>
+     * @throws NullPointerException if <code>headers</code> if <code>null</code>
+     */
+    void sendHeaders(HeaderSet headers) throws IOException;
+
+    /**
+     * Returns the response code received from the server. Response codes are
+     * defined in the <code>ResponseCodes</code> class.
+     * @see ResponseCodes
+     * @return the response code retrieved from the server
+     * @throws IOException if an error occurred in the transport layer during
+     *         the transaction; if this object was created by an OBEX server
+     */
+    int getResponseCode() throws IOException;
+
+    String getEncoding();
+
+    long getLength();
+
+    int getHeaderLength();
+
+    String getType();
+
+    InputStream openInputStream() throws IOException;
+
+    DataInputStream openDataInputStream() throws IOException;
+
+    OutputStream openOutputStream() throws IOException;
+
+    DataOutputStream openDataOutputStream() throws IOException;
+
+    void close() throws IOException;
+
+    int getMaxPacketSize();
+
+    public void noBodyHeader();
+}
diff --git a/javax/obex/PasswordAuthentication.java b/javax/obex/PasswordAuthentication.java
new file mode 100644
index 0000000..326b1ff
--- /dev/null
+++ b/javax/obex/PasswordAuthentication.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * 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 the Motorola, Inc. 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 HOLDER 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 javax.obex;
+
+/**
+ * This class holds user name and password combinations.
+ * @hide
+ */
+public final class PasswordAuthentication {
+
+    private byte[] mUserName;
+
+    private final byte[] mPassword;
+
+    /**
+     * Creates a new <code>PasswordAuthentication</code> with the user name and
+     * password provided.
+     * @param userName the user name to include; this may be <code>null</code>
+     * @param password the password to include in the response
+     * @throws NullPointerException if <code>password</code> is
+     *         <code>null</code>
+     */
+    public PasswordAuthentication(final byte[] userName, final byte[] password) {
+        if (userName != null) {
+            mUserName = new byte[userName.length];
+            System.arraycopy(userName, 0, mUserName, 0, userName.length);
+        }
+
+        mPassword = new byte[password.length];
+        System.arraycopy(password, 0, mPassword, 0, password.length);
+    }
+
+    /**
+     * Retrieves the user name that was specified in the constructor. The user
+     * name may be <code>null</code>.
+     * @return the user name
+     */
+    public byte[] getUserName() {
+        return mUserName;
+    }
+
+    /**
+     * Retrieves the password.
+     * @return the password
+     */
+    public byte[] getPassword() {
+        return mPassword;
+    }
+}
diff --git a/javax/obex/PrivateInputStream.java b/javax/obex/PrivateInputStream.java
new file mode 100644
index 0000000..5daee72
--- /dev/null
+++ b/javax/obex/PrivateInputStream.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * 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 the Motorola, Inc. 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 HOLDER 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 javax.obex;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * This object provides an input stream to the Operation objects used in this
+ * package.
+ * @hide
+ */
+public final class PrivateInputStream extends InputStream {
+
+    private BaseStream mParent;
+
+    private byte[] mData;
+
+    private int mIndex;
+
+    private boolean mOpen;
+
+    /**
+     * Creates an input stream for the <code>Operation</code> to read from
+     * @param p the connection this input stream is for
+     */
+    public PrivateInputStream(BaseStream p) {
+        mParent = p;
+        mData = new byte[0];
+        mIndex = 0;
+        mOpen = true;
+    }
+
+    /**
+     * Returns 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 or another
+     * thread.
+     * @return the number of bytes that can be read from this input stream
+     *         without blocking
+     * @throws IOException if an I/O error occurs
+     */
+    @Override
+    public synchronized int available() throws IOException {
+        ensureOpen();
+        return mData.length - mIndex;
+    }
+
+    /**
+     * Reads the next byte of data from the input stream. The value byte is
+     * returned as an int in the range 0 to 255. If no byte is available because
+     * the end of the stream has been reached, the value -1 is returned. This
+     * method blocks until input data is available, the end of the stream is
+     * detected, or an exception is thrown.
+     * @return the byte read from the input stream or -1 if it reaches the end of
+     *         stream
+     * @throws IOException if an I/O error occurs
+     */
+    @Override
+    public synchronized int read() throws IOException {
+        ensureOpen();
+        while (mData.length == mIndex) {
+            if (!mParent.continueOperation(true, true)) {
+                return -1;
+            }
+        }
+        return (mData[mIndex++] & 0xFF);
+    }
+
+    @Override
+    public int read(byte[] b) throws IOException {
+        return read(b, 0, b.length);
+    }
+
+    @Override
+    public synchronized int read(byte[] b, int offset, int length) throws IOException {
+
+        if (b == null) {
+            throw new IOException("buffer is null");
+        }
+        if ((offset | length) < 0 || length > b.length - offset) {
+            throw new ArrayIndexOutOfBoundsException("index outof bound");
+        }
+        ensureOpen();
+
+        int currentDataLength = mData.length - mIndex;
+        int remainReadLength = length;
+        int offset1 = offset;
+        int result = 0;
+
+        while (currentDataLength <= remainReadLength) {
+            System.arraycopy(mData, mIndex, b, offset1, currentDataLength);
+            mIndex += currentDataLength;
+            offset1 += currentDataLength;
+            result += currentDataLength;
+            remainReadLength -= currentDataLength;
+
+            if (!mParent.continueOperation(true, true)) {
+                return result == 0 ? -1 : result;
+            }
+            currentDataLength = mData.length - mIndex;
+        }
+        if (remainReadLength > 0) {
+            System.arraycopy(mData, mIndex, b, offset1, remainReadLength);
+            mIndex += remainReadLength;
+            result += remainReadLength;
+        }
+        return result;
+    }
+
+    /**
+     * Allows the <code>OperationImpl</code> thread to add body data to the
+     * input stream.
+     * @param body the data to add to the stream
+     * @param start the start of the body to array to copy
+     */
+    public synchronized void writeBytes(byte[] body, int start) {
+
+        int length = (body.length - start) + (mData.length - mIndex);
+        byte[] temp = new byte[length];
+
+        System.arraycopy(mData, mIndex, temp, 0, mData.length - mIndex);
+        System.arraycopy(body, start, temp, mData.length - mIndex, body.length - start);
+
+        mData = temp;
+        mIndex = 0;
+        notifyAll();
+    }
+
+    /**
+     * Verifies that this stream is open
+     * @throws IOException if the stream is not open
+     */
+    private void ensureOpen() throws IOException {
+        mParent.ensureOpen();
+        if (!mOpen) {
+            throw new IOException("Input stream is closed");
+        }
+    }
+
+    /**
+     * Closes the input stream. If the input stream is already closed, do
+     * nothing.
+     * @throws IOException this will never happen
+     */
+    @Override
+    public void close() throws IOException {
+        mOpen = false;
+        mParent.streamClosed(true);
+    }
+}
diff --git a/javax/obex/PrivateOutputStream.java b/javax/obex/PrivateOutputStream.java
new file mode 100644
index 0000000..713f4ae
--- /dev/null
+++ b/javax/obex/PrivateOutputStream.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * 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 the Motorola, Inc. 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 HOLDER 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 javax.obex;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.ByteArrayOutputStream;
+
+/**
+ * This object provides an output stream to the Operation objects used in this
+ * package.
+ * @hide
+ */
+public final class PrivateOutputStream extends OutputStream {
+
+    private BaseStream mParent;
+
+    private ByteArrayOutputStream mArray;
+
+    private boolean mOpen;
+
+    private int mMaxPacketSize;
+
+    /**
+     * Creates an empty <code>PrivateOutputStream</code> to write to.
+     * @param p the connection that this stream runs over
+     */
+    public PrivateOutputStream(BaseStream p, int maxSize) {
+        mParent = p;
+        mArray = new ByteArrayOutputStream();
+        mMaxPacketSize = maxSize;
+        mOpen = true;
+    }
+
+    /**
+     * Determines how many bytes have been written to the output stream.
+     * @return the number of bytes written to the output stream
+     */
+    public int size() {
+        return mArray.size();
+    }
+
+    /**
+     * Writes the specified byte to this output stream. The general contract for
+     * write is that one byte is written to the output stream. The byte to be
+     * written is the eight low-order bits of the argument b. The 24 high-order
+     * bits of b are ignored.
+     * @param b the byte to write
+     * @throws IOException if an I/O error occurs
+     */
+    @Override
+    public synchronized void write(int b) throws IOException {
+        ensureOpen();
+        mParent.ensureNotDone();
+        mArray.write(b);
+        if (mArray.size() == mMaxPacketSize) {
+            mParent.continueOperation(true, false);
+        }
+    }
+
+    @Override
+    public void write(byte[] buffer) throws IOException {
+        write(buffer, 0, buffer.length);
+    }
+
+    @Override
+    public synchronized void write(byte[] buffer, int offset, int count) throws IOException {
+        int offset1 = offset;
+        int remainLength = count;
+
+        if (buffer == null) {
+            throw new IOException("buffer is null");
+        }
+        if ((offset | count) < 0 || count > buffer.length - offset) {
+            throw new IndexOutOfBoundsException("index outof bound");
+        }
+
+        ensureOpen();
+        mParent.ensureNotDone();
+        while ((mArray.size() + remainLength) >= mMaxPacketSize) {
+            int bufferLeft = mMaxPacketSize - mArray.size();
+            mArray.write(buffer, offset1, bufferLeft);
+            offset1 += bufferLeft;
+            remainLength -= bufferLeft;
+            mParent.continueOperation(true, false);
+        }
+        if (remainLength > 0) {
+            mArray.write(buffer, offset1, remainLength);
+        }
+    }
+
+    /**
+     * Reads the bytes that have been written to this stream.
+     * @param size the size of the array to return
+     * @return the byte array that is written
+     */
+    public synchronized byte[] readBytes(int size) {
+        if (mArray.size() > 0) {
+            byte[] temp = mArray.toByteArray();
+            mArray.reset();
+            byte[] result = new byte[size];
+            System.arraycopy(temp, 0, result, 0, size);
+            if (temp.length != size) {
+                mArray.write(temp, size, temp.length - size);
+            }
+            return result;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Verifies that this stream is open
+     * @throws IOException if the stream is not open
+     */
+    private void ensureOpen() throws IOException {
+        mParent.ensureOpen();
+        if (!mOpen) {
+            throw new IOException("Output stream is closed");
+        }
+    }
+
+    /**
+     * Closes the output stream. If the input stream is already closed, do
+     * nothing.
+     * @throws IOException this will never happen
+     */
+    @Override
+    public void close() throws IOException {
+        mOpen = false;
+        mParent.streamClosed(false);
+    }
+
+    /**
+     * Determines if the connection is closed
+     * @return <code>true</code> if the connection is closed; <code>false</code>
+     *         if the connection is open
+     */
+    public boolean isClosed() {
+        return !mOpen;
+    }
+}
diff --git a/javax/obex/ResponseCodes.java b/javax/obex/ResponseCodes.java
new file mode 100644
index 0000000..a2b9a37
--- /dev/null
+++ b/javax/obex/ResponseCodes.java
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * 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 the Motorola, Inc. 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 HOLDER 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 javax.obex;
+
+/**
+ * The <code>ResponseCodes</code> class contains the list of valid response
+ * codes a server may send to a client.
+ * <P>
+ * <STRONG>IMPORTANT NOTE</STRONG>
+ * <P>
+ * The values in this interface represent the values defined in the IrOBEX
+ * specification, which is different with the HTTP specification.
+ * <P>
+ * <code>OBEX_DATABASE_FULL</code> and <code>OBEX_DATABASE_LOCKED</code> require
+ * further description since they are not defined in HTTP. The server will send
+ * an <code>OBEX_DATABASE_FULL</code> message when the client requests that
+ * something be placed into a database but the database is full (cannot take
+ * more data). <code>OBEX_DATABASE_LOCKED</code> will be returned when the
+ * client wishes to access a database, database table, or database record that
+ * has been locked.
+ * @hide
+ */
+public final class ResponseCodes {
+
+    /**
+     * Defines the OBEX CONTINUE response code.
+     * <P>
+     * The value of <code>OBEX_HTTP_CONTINUE</code> is 0x90 (144).
+     */
+    public static final int OBEX_HTTP_CONTINUE = 0x90;
+
+    /**
+     * Defines the OBEX SUCCESS response code.
+     * <P>
+     * The value of <code>OBEX_HTTP_OK</code> is 0xA0 (160).
+     */
+    public static final int OBEX_HTTP_OK = 0xA0;
+
+    /**
+     * Defines the OBEX CREATED response code.
+     * <P>
+     * The value of <code>OBEX_HTTP_CREATED</code> is 0xA1 (161).
+     */
+    public static final int OBEX_HTTP_CREATED = 0xA1;
+
+    /**
+     * Defines the OBEX ACCEPTED response code.
+     * <P>
+     * The value of <code>OBEX_HTTP_ACCEPTED</code> is 0xA2 (162).
+     */
+    public static final int OBEX_HTTP_ACCEPTED = 0xA2;
+
+    /**
+     * Defines the OBEX NON-AUTHORITATIVE INFORMATION response code.
+     * <P>
+     * The value of <code>OBEX_HTTP_NOT_AUTHORITATIVE</code> is 0xA3 (163).
+     */
+    public static final int OBEX_HTTP_NOT_AUTHORITATIVE = 0xA3;
+
+    /**
+     * Defines the OBEX NO CONTENT response code.
+     * <P>
+     * The value of <code>OBEX_HTTP_NO_CONTENT</code> is 0xA4 (164).
+     */
+    public static final int OBEX_HTTP_NO_CONTENT = 0xA4;
+
+    /**
+     * Defines the OBEX RESET CONTENT response code.
+     * <P>
+     * The value of <code>OBEX_HTTP_RESET</code> is 0xA5 (165).
+     */
+    public static final int OBEX_HTTP_RESET = 0xA5;
+
+    /**
+     * Defines the OBEX PARTIAL CONTENT response code.
+     * <P>
+     * The value of <code>OBEX_HTTP_PARTIAL</code> is 0xA6 (166).
+     */
+    public static final int OBEX_HTTP_PARTIAL = 0xA6;
+
+    /**
+     * Defines the OBEX MULTIPLE_CHOICES response code.
+     * <P>
+     * The value of <code>OBEX_HTTP_MULT_CHOICE</code> is 0xB0 (176).
+     */
+    public static final int OBEX_HTTP_MULT_CHOICE = 0xB0;
+
+    /**
+     * Defines the OBEX MOVED PERMANENTLY response code.
+     * <P>
+     * The value of <code>OBEX_HTTP_MOVED_PERM</code> is 0xB1 (177).
+     */
+    public static final int OBEX_HTTP_MOVED_PERM = 0xB1;
+
+    /**
+     * Defines the OBEX MOVED TEMPORARILY response code.
+     * <P>
+     * The value of <code>OBEX_HTTP_MOVED_TEMP</code> is 0xB2 (178).
+     */
+    public static final int OBEX_HTTP_MOVED_TEMP = 0xB2;
+
+    /**
+     * Defines the OBEX SEE OTHER response code.
+     * <P>
+     * The value of <code>OBEX_HTTP_SEE_OTHER</code> is 0xB3 (179).
+     */
+    public static final int OBEX_HTTP_SEE_OTHER = 0xB3;
+
+    /**
+     * Defines the OBEX NOT MODIFIED response code.
+     * <P>
+     * The value of <code>OBEX_HTTP_NOT_MODIFIED</code> is 0xB4 (180).
+     */
+    public static final int OBEX_HTTP_NOT_MODIFIED = 0xB4;
+
+    /**
+     * Defines the OBEX USE PROXY response code.
+     * <P>
+     * The value of <code>OBEX_HTTP_USE_PROXY</code> is 0xB5 (181).
+     */
+    public static final int OBEX_HTTP_USE_PROXY = 0xB5;
+
+    /**
+     * Defines the OBEX BAD REQUEST response code.
+     * <P>
+     * The value of <code>OBEX_HTTP_BAD_REQUEST</code> is 0xC0 (192).
+     */
+    public static final int OBEX_HTTP_BAD_REQUEST = 0xC0;
+
+    /**
+     * Defines the OBEX UNAUTHORIZED response code.
+     * <P>
+     * The value of <code>OBEX_HTTP_UNAUTHORIZED</code> is 0xC1 (193).
+     */
+    public static final int OBEX_HTTP_UNAUTHORIZED = 0xC1;
+
+    /**
+     * Defines the OBEX PAYMENT REQUIRED response code.
+     * <P>
+     * The value of <code>OBEX_HTTP_PAYMENT_REQUIRED</code> is 0xC2 (194).
+     */
+    public static final int OBEX_HTTP_PAYMENT_REQUIRED = 0xC2;
+
+    /**
+     * Defines the OBEX FORBIDDEN response code.
+     * <P>
+     * The value of <code>OBEX_HTTP_FORBIDDEN</code> is 0xC3 (195).
+     */
+    public static final int OBEX_HTTP_FORBIDDEN = 0xC3;
+
+    /**
+     * Defines the OBEX NOT FOUND response code.
+     * <P>
+     * The value of <code>OBEX_HTTP_NOT_FOUND</code> is 0xC4 (196).
+     */
+    public static final int OBEX_HTTP_NOT_FOUND = 0xC4;
+
+    /**
+     * Defines the OBEX METHOD NOT ALLOWED response code.
+     * <P>
+     * The value of <code>OBEX_HTTP_BAD_METHOD</code> is 0xC5 (197).
+     */
+    public static final int OBEX_HTTP_BAD_METHOD = 0xC5;
+
+    /**
+     * Defines the OBEX NOT ACCEPTABLE response code.
+     * <P>
+     * The value of <code>OBEX_HTTP_NOT_ACCEPTABLE</code> is 0xC6 (198).
+     */
+    public static final int OBEX_HTTP_NOT_ACCEPTABLE = 0xC6;
+
+    /**
+     * Defines the OBEX PROXY AUTHENTICATION REQUIRED response code.
+     * <P>
+     * The value of <code>OBEX_HTTP_PROXY_AUTH</code> is 0xC7 (199).
+     */
+    public static final int OBEX_HTTP_PROXY_AUTH = 0xC7;
+
+    /**
+     * Defines the OBEX REQUEST TIME OUT response code.
+     * <P>
+     * The value of <code>OBEX_HTTP_TIMEOUT</code> is 0xC8 (200).
+     */
+    public static final int OBEX_HTTP_TIMEOUT = 0xC8;
+
+    /**
+     * Defines the OBEX METHOD CONFLICT response code.
+     * <P>
+     * The value of <code>OBEX_HTTP_CONFLICT</code> is 0xC9 (201).
+     */
+    public static final int OBEX_HTTP_CONFLICT = 0xC9;
+
+    /**
+     * Defines the OBEX METHOD GONE response code.
+     * <P>
+     * The value of <code>OBEX_HTTP_GONE</code> is 0xCA (202).
+     */
+    public static final int OBEX_HTTP_GONE = 0xCA;
+
+    /**
+     * Defines the OBEX METHOD LENGTH REQUIRED response code.
+     * <P>
+     * The value of <code>OBEX_HTTP_LENGTH_REQUIRED</code> is 0xCB (203).
+     */
+    public static final int OBEX_HTTP_LENGTH_REQUIRED = 0xCB;
+
+    /**
+     * Defines the OBEX PRECONDITION FAILED response code.
+     * <P>
+     * The value of <code>OBEX_HTTP_PRECON_FAILED</code> is 0xCC (204).
+     */
+    public static final int OBEX_HTTP_PRECON_FAILED = 0xCC;
+
+    /**
+     * Defines the OBEX REQUESTED ENTITY TOO LARGE response code.
+     * <P>
+     * The value of <code>OBEX_HTTP_ENTITY_TOO_LARGE</code> is 0xCD (205).
+     */
+    public static final int OBEX_HTTP_ENTITY_TOO_LARGE = 0xCD;
+
+    /**
+     * Defines the OBEX REQUESTED URL TOO LARGE response code.
+     * <P>
+     * The value of <code>OBEX_HTTP_REQ_TOO_LARGE</code> is 0xCE (206).
+     */
+    public static final int OBEX_HTTP_REQ_TOO_LARGE = 0xCE;
+
+    /**
+     * Defines the OBEX UNSUPPORTED MEDIA TYPE response code.
+     * <P>
+     * The value of <code>OBEX_HTTP_UNSUPPORTED_TYPE</code> is 0xCF (207).
+     */
+    public static final int OBEX_HTTP_UNSUPPORTED_TYPE = 0xCF;
+
+    /**
+     * Defines the OBEX INTERNAL SERVER ERROR response code.
+     * <P>
+     * The value of <code>OBEX_HTTP_INTERNAL_ERROR</code> is 0xD0 (208).
+     */
+    public static final int OBEX_HTTP_INTERNAL_ERROR = 0xD0;
+
+    /**
+     * Defines the OBEX NOT IMPLEMENTED response code.
+     * <P>
+     * The value of <code>OBEX_HTTP_NOT_IMPLEMENTED</code> is 0xD1 (209).
+     */
+    public static final int OBEX_HTTP_NOT_IMPLEMENTED = 0xD1;
+
+    /**
+     * Defines the OBEX BAD GATEWAY response code.
+     * <P>
+     * The value of <code>OBEX_HTTP_BAD_GATEWAY</code> is 0xD2 (210).
+     */
+    public static final int OBEX_HTTP_BAD_GATEWAY = 0xD2;
+
+    /**
+     * Defines the OBEX SERVICE UNAVAILABLE response code.
+     * <P>
+     * The value of <code>OBEX_HTTP_UNAVAILABLE</code> is 0xD3 (211).
+     */
+    public static final int OBEX_HTTP_UNAVAILABLE = 0xD3;
+
+    /**
+     * Defines the OBEX GATEWAY TIMEOUT response code.
+     * <P>
+     * The value of <code>OBEX_HTTP_GATEWAY_TIMEOUT</code> is 0xD4 (212).
+     */
+    public static final int OBEX_HTTP_GATEWAY_TIMEOUT = 0xD4;
+
+    /**
+     * Defines the OBEX HTTP VERSION NOT SUPPORTED response code.
+     * <P>
+     * The value of <code>OBEX_HTTP_VERSION</code> is 0xD5 (213).
+     */
+    public static final int OBEX_HTTP_VERSION = 0xD5;
+
+    /**
+     * Defines the OBEX DATABASE FULL response code.
+     * <P>
+     * The value of <code>OBEX_DATABASE_FULL</code> is 0xE0 (224).
+     */
+    public static final int OBEX_DATABASE_FULL = 0xE0;
+
+    /**
+     * Defines the OBEX DATABASE LOCKED response code.
+     * <P>
+     * The value of <code>OBEX_DATABASE_LOCKED</code> is 0xE1 (225).
+     */
+    public static final int OBEX_DATABASE_LOCKED = 0xE1;
+
+    /**
+     * Constructor does nothing.
+     */
+    private ResponseCodes() {
+    }
+}
diff --git a/javax/obex/ServerOperation.java b/javax/obex/ServerOperation.java
new file mode 100644
index 0000000..15ea367
--- /dev/null
+++ b/javax/obex/ServerOperation.java
@@ -0,0 +1,861 @@
+/* Copyright (c) 2015 The Android Open Source Project
+ * Copyright (C) 2015 Samsung LSI
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * 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 the Motorola, Inc. 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 HOLDER 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 javax.obex;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.DataInputStream;
+import java.io.OutputStream;
+import java.io.DataOutputStream;
+import java.io.ByteArrayOutputStream;
+
+import android.util.Log;
+
+/**
+ * This class implements the Operation interface for server side connections.
+ * <P>
+ * <STRONG>Request Codes</STRONG> There are four different request codes that
+ * are in this class. 0x02 is a PUT request that signals that the request is not
+ * complete and requires an additional OBEX packet. 0x82 is a PUT request that
+ * says that request is complete. In this case, the server can begin sending the
+ * response. The 0x03 is a GET request that signals that the request is not
+ * finished. When the server receives a 0x83, the client is signaling the server
+ * that it is done with its request. TODO: Extend the ClientOperation and reuse
+ * the methods defined TODO: in that class.
+ * @hide
+ */
+public final class ServerOperation implements Operation, BaseStream {
+
+    private static final String TAG = "ServerOperation";
+
+    private static final boolean V = ObexHelper.VDBG; // Verbose debugging
+
+    public boolean isAborted;
+
+    public HeaderSet requestHeader;
+
+    public HeaderSet replyHeader;
+
+    public boolean finalBitSet;
+
+    private InputStream mInput;
+
+    private ServerSession mParent;
+
+    private int mMaxPacketLength;
+
+    private int mResponseSize;
+
+    private boolean mClosed;
+
+    private boolean mGetOperation;
+
+    private PrivateInputStream mPrivateInput;
+
+    private PrivateOutputStream mPrivateOutput;
+
+    private ObexTransport mTransport;
+
+    private boolean mPrivateOutputOpen;
+
+    private String mExceptionString;
+
+    private ServerRequestHandler mListener;
+
+    private boolean mRequestFinished;
+
+    private boolean mHasBody;
+
+    private boolean mSendBodyHeader = true;
+    // Assume SRM disabled - needs to be explicit
+    // enabled by client
+    private boolean mSrmEnabled = false;
+    // A latch - when triggered, there is not way back ;-)
+    private boolean mSrmActive = false;
+    // Set to true when a SRM enable response have been send
+    private boolean mSrmResponseSent = false;
+    // keep waiting until final-bit is received in request
+    // to handle the case where the SRM enable header is in
+    // a different OBEX packet than the SRMP header.
+    private boolean mSrmWaitingForRemote = true;
+    // Why should we wait? - currently not exposed to apps.
+    private boolean mSrmLocalWait = false;
+
+    /**
+     * Creates new ServerOperation
+     * @param p the parent that created this object
+     * @param in the input stream to read from
+     * @param out the output stream to write to
+     * @param request the initial request that was received from the client
+     * @param maxSize the max packet size that the client will accept
+     * @param listen the listener that is responding to the request
+     * @throws IOException if an IO error occurs
+     */
+    public ServerOperation(ServerSession p, InputStream in, int request, int maxSize,
+            ServerRequestHandler listen) throws IOException {
+
+        isAborted = false;
+        mParent = p;
+        mInput = in;
+        mMaxPacketLength = maxSize;
+        mClosed = false;
+        requestHeader = new HeaderSet();
+        replyHeader = new HeaderSet();
+        mPrivateInput = new PrivateInputStream(this);
+        mResponseSize = 3;
+        mListener = listen;
+        mRequestFinished = false;
+        mPrivateOutputOpen = false;
+        mHasBody = false;
+        ObexPacket packet;
+        mTransport = p.getTransport();
+
+        /*
+         * Determine if this is a PUT request
+         */
+        if ((request == ObexHelper.OBEX_OPCODE_PUT) ||
+                (request == ObexHelper.OBEX_OPCODE_PUT_FINAL)) {
+            /*
+             * It is a PUT request.
+             */
+            mGetOperation = false;
+
+            /*
+             * Determine if the final bit is set
+             */
+            if ((request & ObexHelper.OBEX_OPCODE_FINAL_BIT_MASK) == 0) {
+                finalBitSet = false;
+            } else {
+                finalBitSet = true;
+                mRequestFinished = true;
+            }
+        } else if ((request == ObexHelper.OBEX_OPCODE_GET) ||
+                (request == ObexHelper.OBEX_OPCODE_GET_FINAL)) {
+            /*
+             * It is a GET request.
+             */
+            mGetOperation = true;
+
+            // For Get request, final bit set is decided by server side logic
+            finalBitSet = false;
+
+            if (request == ObexHelper.OBEX_OPCODE_GET_FINAL) {
+                mRequestFinished = true;
+            }
+        } else {
+            throw new IOException("ServerOperation can not handle such request");
+        }
+
+        packet = ObexPacket.read(request, mInput);
+
+        /*
+         * Determine if the packet length is larger than this device can receive
+         */
+        if (packet.mLength > ObexHelper.getMaxRxPacketSize(mTransport)) {
+            mParent.sendResponse(ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE, null);
+            throw new IOException("Packet received was too large. Length: "
+                    + packet.mLength + " maxLength: " + ObexHelper.getMaxRxPacketSize(mTransport));
+        }
+
+        /*
+         * Determine if any headers were sent in the initial request
+         */
+        if (packet.mLength > 3) {
+            if(!handleObexPacket(packet)) {
+                return;
+            }
+            /* Don't Pre-Send continue when Remote requested for SRM
+             * Let the Application confirm.
+             */
+            if (V) Log.v(TAG, "Get App confirmation if SRM ENABLED case: " + mSrmEnabled
+                    + " not hasBody case: " + mHasBody);
+            if (!mHasBody && !mSrmEnabled) {
+                while ((!mGetOperation) && (!finalBitSet)) {
+                    sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
+                    if (mPrivateInput.available() > 0) {
+                        break;
+                    }
+                }
+            }
+        }
+        /* Don't Pre-Send continue when Remote requested for SRM
+          * Let the Application confirm.
+          */
+        if (V) Log.v(TAG, "Get App confirmation if SRM ENABLED case: " + mSrmEnabled
+            + " not finalPacket: " + finalBitSet + " not GETOp Case: " + mGetOperation);
+        while ((!mSrmEnabled) && (!mGetOperation) && (!finalBitSet)
+                && (mPrivateInput.available() == 0)) {
+            sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
+            if (mPrivateInput.available() > 0) {
+                break;
+            }
+        }
+
+        // wait for get request finished !!!!
+        while (mGetOperation && !mRequestFinished) {
+            sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
+        }
+    }
+
+    /**
+     * Parse headers and update member variables
+     * @param packet the received obex packet
+     * @return false for failing authentication - and a OBEX_HTTP_UNAUTHORIZED
+     * response have been send. Else true.
+     * @throws IOException
+     */
+    private boolean handleObexPacket(ObexPacket packet) throws IOException {
+        byte[] body = updateRequestHeaders(packet);
+
+        if (body != null) {
+            mHasBody = true;
+        }
+        if (mListener.getConnectionId() != -1 && requestHeader.mConnectionID != null) {
+            mListener.setConnectionId(ObexHelper
+                    .convertToLong(requestHeader.mConnectionID));
+        } else {
+            mListener.setConnectionId(1);
+        }
+
+        if (requestHeader.mAuthResp != null) {
+            if (!mParent.handleAuthResp(requestHeader.mAuthResp)) {
+                mExceptionString = "Authentication Failed";
+                mParent.sendResponse(ResponseCodes.OBEX_HTTP_UNAUTHORIZED, null);
+                mClosed = true;
+                requestHeader.mAuthResp = null;
+                return false;
+            }
+            requestHeader.mAuthResp = null;
+        }
+
+        if (requestHeader.mAuthChall != null) {
+            mParent.handleAuthChall(requestHeader);
+            // send the auhtResp to the client
+            replyHeader.mAuthResp = new byte[requestHeader.mAuthResp.length];
+            System.arraycopy(requestHeader.mAuthResp, 0, replyHeader.mAuthResp, 0,
+                    replyHeader.mAuthResp.length);
+            requestHeader.mAuthResp = null;
+            requestHeader.mAuthChall = null;
+        }
+
+        if (body != null) {
+            mPrivateInput.writeBytes(body, 1);
+        }
+        return true;
+    }
+
+    /**
+     * Update the request header set, and sniff on SRM headers to update local state.
+     * @param data the OBEX packet data
+     * @return any bytes in a body/end-of-body header returned by {@link ObexHelper.updateHeaderSet}
+     * @throws IOException
+     */
+    private byte[] updateRequestHeaders(ObexPacket packet) throws IOException {
+        byte[] body = null;
+        if (packet.mPayload != null) {
+            body = ObexHelper.updateHeaderSet(requestHeader, packet.mPayload);
+        }
+        Byte srmMode = (Byte)requestHeader.getHeader(HeaderSet.SINGLE_RESPONSE_MODE);
+        if(mTransport.isSrmSupported() && srmMode != null
+                && srmMode == ObexHelper.OBEX_SRM_ENABLE) {
+            mSrmEnabled = true;
+            if(V) Log.d(TAG,"SRM is now ENABLED (but not active) for this operation");
+        }
+        checkForSrmWait(packet.mHeaderId);
+        if((!mSrmWaitingForRemote) && (mSrmEnabled)) {
+            if(V) Log.d(TAG,"SRM is now ACTIVE for this operation");
+            mSrmActive = true;
+        }
+        return body;
+    }
+
+    /**
+     * Call this only when a complete request have been received.
+     * (This is not optimal, but the current design is not really suited to
+     * the way SRM is specified.)
+     */
+    private void checkForSrmWait(int headerId){
+        if (mSrmEnabled && (headerId == ObexHelper.OBEX_OPCODE_GET
+                || headerId == ObexHelper.OBEX_OPCODE_GET_FINAL
+                || headerId == ObexHelper.OBEX_OPCODE_PUT)) {
+            try {
+                mSrmWaitingForRemote = false;
+                Byte srmp = (Byte)requestHeader.getHeader(HeaderSet.SINGLE_RESPONSE_MODE_PARAMETER);
+                if(srmp != null && srmp == ObexHelper.OBEX_SRMP_WAIT) {
+                    mSrmWaitingForRemote = true;
+                    // Clear the wait header, as the absents of the header when the final bit is set
+                    // indicates don't wait.
+                    requestHeader.setHeader(HeaderSet.SINGLE_RESPONSE_MODE_PARAMETER, null);
+                }
+            } catch (IOException e) {if(V){Log.w(TAG,"Exception while extracting header",e);}}
+        }
+    }
+
+    public boolean isValidBody() {
+        return mHasBody;
+    }
+
+    /**
+     * Determines if the operation should continue or should wait. If it should
+     * continue, this method will continue the operation.
+     * @param sendEmpty if <code>true</code> then this will continue the
+     *        operation even if no headers will be sent; if <code>false</code>
+     *        then this method will only continue the operation if there are
+     *        headers to send
+     * @param inStream if<code>true</code> the stream is input stream, otherwise
+     *        output stream
+     * @return <code>true</code> if the operation was completed;
+     *         <code>false</code> if no operation took place
+     */
+    public synchronized boolean continueOperation(boolean sendEmpty, boolean inStream)
+            throws IOException {
+        if (!mGetOperation) {
+            if (!finalBitSet) {
+                if (sendEmpty) {
+                    sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
+                    return true;
+                } else {
+                    if ((mResponseSize > 3) || (mPrivateOutput.size() > 0)) {
+                        sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
+                        return true;
+                    } else {
+                        return false;
+                    }
+                }
+            } else {
+                return false;
+            }
+        } else {
+            sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
+            return true;
+        }
+    }
+
+    /**
+     * Sends a reply to the client. If the reply is a OBEX_HTTP_CONTINUE, it
+     * will wait for a response from the client before ending unless SRM is active.
+     * @param type the response code to send back to the client
+     * @return <code>true</code> if the final bit was not set on the reply;
+     *         <code>false</code> if no reply was received because the operation
+     *         ended, an abort was received, the final bit was set in the
+     *         reply or SRM is active.
+     * @throws IOException if an IO error occurs
+     */
+    public synchronized boolean sendReply(int type) throws IOException {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        boolean skipSend = false;
+        boolean skipReceive = false;
+        boolean srmRespSendPending = false;
+
+        long id = mListener.getConnectionId();
+        if (id == -1) {
+            replyHeader.mConnectionID = null;
+        } else {
+            replyHeader.mConnectionID = ObexHelper.convertToByteArray(id);
+        }
+
+        if(mSrmEnabled && !mSrmResponseSent) {
+            // As we are not ensured that the SRM enable is in the first OBEX packet
+            // We must check for each reply.
+            if(V)Log.v(TAG, "mSrmEnabled==true, sending SRM enable response.");
+            replyHeader.setHeader(HeaderSet.SINGLE_RESPONSE_MODE, (byte)ObexHelper.OBEX_SRM_ENABLE);
+            srmRespSendPending = true;
+        }
+
+        if(mSrmEnabled && !mGetOperation && mSrmLocalWait) {
+            replyHeader.setHeader(HeaderSet.SINGLE_RESPONSE_MODE, (byte)ObexHelper.OBEX_SRMP_WAIT);
+        }
+
+        byte[] headerArray = ObexHelper.createHeader(replyHeader, true); // This clears the headers
+        int bodyLength = -1;
+        int orginalBodyLength = -1;
+
+        if (mPrivateOutput != null) {
+            bodyLength = mPrivateOutput.size();
+            orginalBodyLength = bodyLength;
+        }
+
+        if ((ObexHelper.BASE_PACKET_LENGTH + headerArray.length) > mMaxPacketLength) {
+
+            int end = 0;
+            int start = 0;
+
+            while (end != headerArray.length) {
+                end = ObexHelper.findHeaderEnd(headerArray, start, mMaxPacketLength
+                        - ObexHelper.BASE_PACKET_LENGTH);
+                if (end == -1) {
+
+                    mClosed = true;
+
+                    if (mPrivateInput != null) {
+                        mPrivateInput.close();
+                    }
+
+                    if (mPrivateOutput != null) {
+                        mPrivateOutput.close();
+                    }
+                    mParent.sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
+                    throw new IOException("OBEX Packet exceeds max packet size");
+                }
+                byte[] sendHeader = new byte[end - start];
+                System.arraycopy(headerArray, start, sendHeader, 0, sendHeader.length);
+
+                mParent.sendResponse(type, sendHeader);
+                start = end;
+            }
+
+            if (bodyLength > 0) {
+                return true;
+            } else {
+                return false;
+            }
+
+        } else {
+            out.write(headerArray);
+        }
+
+        // For Get operation: if response code is OBEX_HTTP_OK, then this is the
+        // last packet; so set finalBitSet to true.
+        if (mGetOperation && type == ResponseCodes.OBEX_HTTP_OK) {
+            finalBitSet = true;
+        }
+
+        if(mSrmActive) {
+            if(!mGetOperation && type == ResponseCodes.OBEX_HTTP_CONTINUE &&
+                    mSrmResponseSent == true) {
+                // we are in the middle of a SRM PUT operation, don't send a continue.
+                skipSend = true;
+            } else if(mGetOperation && mRequestFinished == false && mSrmResponseSent == true) {
+                // We are still receiving the get request, receive, but don't send continue.
+                skipSend = true;
+            } else if(mGetOperation && mRequestFinished == true) {
+                // All done receiving the GET request, send data to the client, without
+                // expecting a continue.
+                skipReceive = true;
+            }
+            if(V)Log.v(TAG, "type==" + type + " skipSend==" + skipSend
+                    + " skipReceive==" + skipReceive);
+        }
+        if(srmRespSendPending) {
+            if(V)Log.v(TAG,
+                    "SRM Enabled (srmRespSendPending == true)- sending SRM Enable response");
+            mSrmResponseSent = true;
+        }
+
+        if ((finalBitSet) || (headerArray.length < (mMaxPacketLength - 20))) {
+            if (bodyLength > 0) {
+                /*
+                 * Determine if I can send the whole body or just part of
+                 * the body.  Remember that there is the 3 bytes for the
+                 * response message and 3 bytes for the header ID and length
+                 */
+                if (bodyLength > (mMaxPacketLength - headerArray.length - 6)) {
+                    bodyLength = mMaxPacketLength - headerArray.length - 6;
+                }
+
+                byte[] body = mPrivateOutput.readBytes(bodyLength);
+
+                /*
+                 * Since this is a put request if the final bit is set or
+                 * the output stream is closed we need to send the 0x49
+                 * (End of Body) otherwise, we need to send 0x48 (Body)
+                 */
+                if ((finalBitSet) || (mPrivateOutput.isClosed())) {
+                    if(mSendBodyHeader == true) {
+                        out.write(0x49);
+                        bodyLength += 3;
+                        out.write((byte)(bodyLength >> 8));
+                        out.write((byte)bodyLength);
+                        out.write(body);
+                    }
+                } else {
+                    if(mSendBodyHeader == true) {
+                    out.write(0x48);
+                    bodyLength += 3;
+                    out.write((byte)(bodyLength >> 8));
+                    out.write((byte)bodyLength);
+                    out.write(body);
+                    }
+                }
+
+            }
+        }
+
+        if ((finalBitSet) && (type == ResponseCodes.OBEX_HTTP_OK) && (orginalBodyLength <= 0)) {
+            if(mSendBodyHeader) {
+                out.write(0x49);
+                orginalBodyLength = 3;
+                out.write((byte)(orginalBodyLength >> 8));
+                out.write((byte)orginalBodyLength);
+            }
+        }
+
+        if(skipSend == false) {
+            mResponseSize = 3;
+            mParent.sendResponse(type, out.toByteArray());
+        }
+
+        if (type == ResponseCodes.OBEX_HTTP_CONTINUE) {
+
+            if(mGetOperation && skipReceive) {
+                // Here we need to check for and handle abort (throw an exception).
+                // Any other signal received should be discarded silently (only on server side)
+                checkSrmRemoteAbort();
+            } else {
+                // Receive and handle data (only send reply if !skipSend)
+                // Read a complete OBEX Packet
+                ObexPacket packet = ObexPacket.read(mInput);
+
+                int headerId = packet.mHeaderId;
+                if ((headerId != ObexHelper.OBEX_OPCODE_PUT)
+                        && (headerId != ObexHelper.OBEX_OPCODE_PUT_FINAL)
+                        && (headerId != ObexHelper.OBEX_OPCODE_GET)
+                        && (headerId != ObexHelper.OBEX_OPCODE_GET_FINAL)) {
+
+                    /*
+                     * Determine if an ABORT was sent as the reply
+                     */
+                    if (headerId == ObexHelper.OBEX_OPCODE_ABORT) {
+                        handleRemoteAbort();
+                    } else {
+                        // TODO:shall we send this if it occurs during SRM? Errata on the subject
+                        mParent.sendResponse(ResponseCodes.OBEX_HTTP_BAD_REQUEST, null);
+                        mClosed = true;
+                        mExceptionString = "Bad Request Received";
+                        throw new IOException("Bad Request Received");
+                    }
+                } else {
+
+                    if ((headerId == ObexHelper.OBEX_OPCODE_PUT_FINAL)) {
+                        finalBitSet = true;
+                    } else if (headerId == ObexHelper.OBEX_OPCODE_GET_FINAL) {
+                        mRequestFinished = true;
+                    }
+
+                    /*
+                     * Determine if the packet length is larger than the negotiated packet size
+                     */
+                    if (packet.mLength > ObexHelper.getMaxRxPacketSize(mTransport)) {
+                        mParent.sendResponse(ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE, null);
+                        throw new IOException("Packet received was too large");
+                    }
+
+                    /*
+                     * Determine if any headers were sent in the initial request
+                     */
+                    if (packet.mLength > 3 || (mSrmEnabled && packet.mLength == 3)) {
+                        if(handleObexPacket(packet) == false) {
+                            return false;
+                        }
+                    }
+                }
+
+            }
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * This method will look for an abort from the peer during a SRM transfer.
+     * The function will not block if no data has been received from the remote device.
+     * If data have been received, the function will block while reading the incoming
+     * OBEX package.
+     * An Abort request will be handled, and cause an IOException("Abort Received").
+     * Other messages will be discarded silently as per GOEP specification.
+     * @throws IOException if an abort request have been received.
+     * TODO: I think this is an error in the specification. If we discard other messages,
+     *       the peer device will most likely stall, as it will not receive the expected
+     *       response for the message...
+     *       I'm not sure how to understand "Receipt of invalid or unexpected SRM or SRMP
+     *       header values shall be ignored by the receiving device."
+     *       If any signal is received during an active SRM transfer it is unexpected regardless
+     *       whether or not it contains SRM/SRMP headers...
+     */
+    private void checkSrmRemoteAbort() throws IOException {
+        if(mInput.available() > 0) {
+            ObexPacket packet = ObexPacket.read(mInput);
+            /*
+             * Determine if an ABORT was sent as the reply
+             */
+            if (packet.mHeaderId == ObexHelper.OBEX_OPCODE_ABORT) {
+                handleRemoteAbort();
+            } else {
+                // TODO: should we throw an exception here anyway? - don't see how to
+                //       ignore SRM/SRMP headers without ignoring the complete signal
+                //       (in this particular case).
+                Log.w(TAG, "Received unexpected request from client - discarding...\n"
+                        + "   headerId: " + packet.mHeaderId + " length: " + packet.mLength);
+            }
+        }
+    }
+
+    private void handleRemoteAbort() throws IOException {
+        /* TODO: To increase the speed of the abort operation in SRM, we need
+         *       to be able to flush the L2CAP queue for the PSM in use.
+         *       This could be implemented by introducing a control
+         *       message to be send over the socket, that in the abort case
+         *       could carry a flush command. */
+        mParent.sendResponse(ResponseCodes.OBEX_HTTP_OK, null);
+        mClosed = true;
+        isAborted = true;
+        mExceptionString = "Abort Received";
+        throw new IOException("Abort Received");
+    }
+
+    /**
+     * Sends an ABORT message to the server. By calling this method, the
+     * corresponding input and output streams will be closed along with this
+     * object.
+     * @throws IOException if the transaction has already ended or if an OBEX
+     *         server called this method
+     */
+    public void abort() throws IOException {
+        throw new IOException("Called from a server");
+    }
+
+    /**
+     * Returns the headers that have been received during the operation.
+     * Modifying the object returned has no effect on the headers that are sent
+     * or retrieved.
+     * @return the headers received during this <code>Operation</code>
+     * @throws IOException if this <code>Operation</code> has been closed
+     */
+    public HeaderSet getReceivedHeader() throws IOException {
+        ensureOpen();
+        return requestHeader;
+    }
+
+    /**
+     * Specifies the headers that should be sent in the next OBEX message that
+     * is sent.
+     * @param headers the headers to send in the next message
+     * @throws IOException if this <code>Operation</code> has been closed or the
+     *         transaction has ended and no further messages will be exchanged
+     * @throws IllegalArgumentException if <code>headers</code> was not created
+     *         by a call to <code>ServerRequestHandler.createHeaderSet()</code>
+     */
+    public void sendHeaders(HeaderSet headers) throws IOException {
+        ensureOpen();
+
+        if (headers == null) {
+            throw new IOException("Headers may not be null");
+        }
+
+        int[] headerList = headers.getHeaderList();
+        if (headerList != null) {
+            for (int i = 0; i < headerList.length; i++) {
+                replyHeader.setHeader(headerList[i], headers.getHeader(headerList[i]));
+            }
+
+        }
+    }
+
+    /**
+     * Retrieves the response code retrieved from the server. Response codes are
+     * defined in the <code>ResponseCodes</code> interface.
+     * @return the response code retrieved from the server
+     * @throws IOException if an error occurred in the transport layer during
+     *         the transaction; if this method is called on a
+     *         <code>HeaderSet</code> object created by calling
+     *         <code>createHeaderSet</code> in a <code>ClientSession</code>
+     *         object; if this is called from a server
+     */
+    public int getResponseCode() throws IOException {
+        throw new IOException("Called from a server");
+    }
+
+    /**
+     * Always returns <code>null</code>
+     * @return <code>null</code>
+     */
+    public String getEncoding() {
+        return null;
+    }
+
+    /**
+     * Returns the type of content that the resource connected to is providing.
+     * E.g. if the connection is via HTTP, then the value of the content-type
+     * header field is returned.
+     * @return the content type of the resource that the URL references, or
+     *         <code>null</code> if not known
+     */
+    public String getType() {
+        try {
+            return (String)requestHeader.getHeader(HeaderSet.TYPE);
+        } catch (IOException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Returns the length of the content which is being provided. E.g. if the
+     * connection is via HTTP, then the value of the content-length header field
+     * is returned.
+     * @return the content length of the resource that this connection's URL
+     *         references, or -1 if the content length is not known
+     */
+    public long getLength() {
+        try {
+            Long temp = (Long)requestHeader.getHeader(HeaderSet.LENGTH);
+
+            if (temp == null) {
+                return -1;
+            } else {
+                return temp.longValue();
+            }
+        } catch (IOException e) {
+            return -1;
+        }
+    }
+
+    public int getMaxPacketSize() {
+        return mMaxPacketLength - 6 - getHeaderLength();
+    }
+
+    public int getHeaderLength() {
+        long id = mListener.getConnectionId();
+        if (id == -1) {
+            replyHeader.mConnectionID = null;
+        } else {
+            replyHeader.mConnectionID = ObexHelper.convertToByteArray(id);
+        }
+
+        byte[] headerArray = ObexHelper.createHeader(replyHeader, false);
+
+        return headerArray.length;
+    }
+
+    /**
+     * Open and return an input stream for a connection.
+     * @return an input stream
+     * @throws IOException if an I/O error occurs
+     */
+    public InputStream openInputStream() throws IOException {
+        ensureOpen();
+        return mPrivateInput;
+    }
+
+    /**
+     * Open and return a data input stream for a connection.
+     * @return an input stream
+     * @throws IOException if an I/O error occurs
+     */
+    public DataInputStream openDataInputStream() throws IOException {
+        return new DataInputStream(openInputStream());
+    }
+
+    /**
+     * Open and return an output stream for a connection.
+     * @return an output stream
+     * @throws IOException if an I/O error occurs
+     */
+    public OutputStream openOutputStream() throws IOException {
+        ensureOpen();
+
+        if (mPrivateOutputOpen) {
+            throw new IOException("no more input streams available, stream already opened");
+        }
+
+        if (!mRequestFinished) {
+            throw new IOException("no  output streams available ,request not finished");
+        }
+
+        if (mPrivateOutput == null) {
+            mPrivateOutput = new PrivateOutputStream(this, getMaxPacketSize());
+        }
+        mPrivateOutputOpen = true;
+        return mPrivateOutput;
+    }
+
+    /**
+     * Open and return a data output stream for a connection.
+     * @return an output stream
+     * @throws IOException if an I/O error occurs
+     */
+    public DataOutputStream openDataOutputStream() throws IOException {
+        return new DataOutputStream(openOutputStream());
+    }
+
+    /**
+     * Closes the connection and ends the transaction
+     * @throws IOException if the operation has already ended or is closed
+     */
+    public void close() throws IOException {
+        ensureOpen();
+        mClosed = true;
+    }
+
+    /**
+     * Verifies that the connection is open and no exceptions should be thrown.
+     * @throws IOException if an exception needs to be thrown
+     */
+    public void ensureOpen() throws IOException {
+        if (mExceptionString != null) {
+            throw new IOException(mExceptionString);
+        }
+        if (mClosed) {
+            throw new IOException("Operation has already ended");
+        }
+    }
+
+    /**
+     * Verifies that additional information may be sent. In other words, the
+     * operation is not done.
+     * <P>
+     * Included to implement the BaseStream interface only. It does not do
+     * anything on the server side since the operation of the Operation object
+     * is not done until after the handler returns from its method.
+     * @throws IOException if the operation is completed
+     */
+    public void ensureNotDone() throws IOException {
+    }
+
+    /**
+     * Called when the output or input stream is closed. It does not do anything
+     * on the server side since the operation of the Operation object is not
+     * done until after the handler returns from its method.
+     * @param inStream <code>true</code> if the input stream is closed;
+     *        <code>false</code> if the output stream is closed
+     * @throws IOException if an IO error occurs
+     */
+    public void streamClosed(boolean inStream) throws IOException {
+
+    }
+
+    public void noBodyHeader(){
+        mSendBodyHeader = false;
+    }
+}
diff --git a/javax/obex/ServerRequestHandler.java b/javax/obex/ServerRequestHandler.java
new file mode 100644
index 0000000..09cbc2c
--- /dev/null
+++ b/javax/obex/ServerRequestHandler.java
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * 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 the Motorola, Inc. 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 HOLDER 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 javax.obex;
+
+/**
+ * The <code>ServerRequestHandler</code> class defines an event listener that
+ * will respond to OBEX requests made to the server.
+ * <P>
+ * The <code>onConnect()</code>, <code>onSetPath()</code>,
+ * <code>onDelete()</code>, <code>onGet()</code>, and <code>onPut()</code>
+ * methods may return any response code defined in the
+ * <code>ResponseCodes</code> class except for <code>OBEX_HTTP_CONTINUE</code>.
+ * If <code>OBEX_HTTP_CONTINUE</code> or a value not defined in the
+ * <code>ResponseCodes</code> class is returned, the server implementation will
+ * send an <code>OBEX_HTTP_INTERNAL_ERROR</code> response to the client.
+ * <P>
+ * <STRONG>Connection ID and Target Headers</STRONG>
+ * <P>
+ * According to the IrOBEX specification, a packet may not contain a Connection
+ * ID and Target header. Since the Connection ID header is managed by the
+ * implementation, it will not send a Connection ID header, if a Connection ID
+ * was specified, in a packet that has a Target header. In other words, if an
+ * application adds a Target header to a <code>HeaderSet</code> object used in
+ * an OBEX operation and a Connection ID was specified, no Connection ID will be
+ * sent in the packet containing the Target header.
+ * <P>
+ * <STRONG>CREATE-EMPTY Requests</STRONG>
+ * <P>
+ * A CREATE-EMPTY request allows clients to create empty objects on the server.
+ * When a CREATE-EMPTY request is received, the <code>onPut()</code> method will
+ * be called by the implementation. To differentiate between a normal PUT
+ * request and a CREATE-EMPTY request, an application must open the
+ * <code>InputStream</code> from the <code>Operation</code> object passed to the
+ * <code>onPut()</code> method. For a PUT request, the application will be able
+ * to read Body data from this <code>InputStream</code>. For a CREATE-EMPTY
+ * request, there will be no Body data to read. Therefore, a call to
+ * <code>InputStream.read()</code> will return -1.
+ * @hide
+ */
+public class ServerRequestHandler {
+
+    private long mConnectionId;
+
+    /**
+     * Creates a <code>ServerRequestHandler</code>.
+     */
+    protected ServerRequestHandler() {
+        /*
+         * A connection ID of -1 implies there is no conenction ID
+         */
+        mConnectionId = -1;
+    }
+
+    /**
+     * Sets the connection ID header to include in the reply packets.
+     * @param connectionId the connection ID to use; -1 if no connection ID
+     *        should be sent
+     * @throws IllegalArgumentException if <code>id</code> is not in the range
+     *         -1 to 2<sup>32</sup>-1
+     */
+    public void setConnectionId(final long connectionId) {
+        if ((connectionId < -1) || (connectionId > 0xFFFFFFFFL)) {
+            throw new IllegalArgumentException("Illegal Connection ID");
+        }
+        mConnectionId = connectionId;
+    }
+
+    /**
+     * Retrieves the connection ID that is being used in the present connection.
+     * This method will return -1 if no connection ID is being used.
+     * @return the connection id being used or -1 if no connection ID is being
+     *         used
+     */
+    public long getConnectionId() {
+        return mConnectionId;
+    }
+
+    /**
+     * Called when a CONNECT request is received.
+     * <P>
+     * If this method is not implemented by the class that extends this class,
+     * <code>onConnect()</code> will always return an <code>OBEX_HTTP_OK</code>
+     * response code.
+     * <P>
+     * The headers received in the request can be retrieved from the
+     * <code>request</code> argument. The headers that should be sent in the
+     * reply must be specified in the <code>reply</code> argument.
+     * @param request contains the headers sent by the client;
+     *        <code>request</code> will never be <code>null</code>
+     * @param reply the headers that should be sent in the reply;
+     *        <code>reply</code> will never be <code>null</code>
+     * @return a response code defined in <code>ResponseCodes</code> that will
+     *         be returned to the client; if an invalid response code is
+     *         provided, the <code>OBEX_HTTP_INTERNAL_ERROR</code> response code
+     *         will be used
+     */
+    public int onConnect(HeaderSet request, HeaderSet reply) {
+        return ResponseCodes.OBEX_HTTP_OK;
+    }
+
+    /**
+     * Called when a DISCONNECT request is received.
+     * <P>
+     * The headers received in the request can be retrieved from the
+     * <code>request</code> argument. The headers that should be sent in the
+     * reply must be specified in the <code>reply</code> argument.
+     * @param request contains the headers sent by the client;
+     *        <code>request</code> will never be <code>null</code>
+     * @param reply the headers that should be sent in the reply;
+     *        <code>reply</code> will never be <code>null</code>
+     */
+    public void onDisconnect(HeaderSet request, HeaderSet reply) {
+    }
+
+    /**
+     * Called when a SETPATH request is received.
+     * <P>
+     * If this method is not implemented by the class that extends this class,
+     * <code>onSetPath()</code> will always return an
+     * <code>OBEX_HTTP_NOT_IMPLEMENTED</code> response code.
+     * <P>
+     * The headers received in the request can be retrieved from the
+     * <code>request</code> argument. The headers that should be sent in the
+     * reply must be specified in the <code>reply</code> argument.
+     * @param request contains the headers sent by the client;
+     *        <code>request</code> will never be <code>null</code>
+     * @param reply the headers that should be sent in the reply;
+     *        <code>reply</code> will never be <code>null</code>
+     * @param backup <code>true</code> if the client requests that the server
+     *        back up one directory before changing to the path described by
+     *        <code>name</code>; <code>false</code> to apply the request to the
+     *        present path
+     * @param create <code>true</code> if the path should be created if it does
+     *        not already exist; <code>false</code> if the path should not be
+     *        created if it does not exist and an error code should be returned
+     * @return a response code defined in <code>ResponseCodes</code> that will
+     *         be returned to the client; if an invalid response code is
+     *         provided, the <code>OBEX_HTTP_INTERNAL_ERROR</code> response code
+     *         will be used
+     */
+    public int onSetPath(HeaderSet request, HeaderSet reply, boolean backup, boolean create) {
+
+        return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED;
+    }
+
+    /**
+     * Called when a DELETE request is received.
+     * <P>
+     * If this method is not implemented by the class that extends this class,
+     * <code>onDelete()</code> will always return an
+     * <code>OBEX_HTTP_NOT_IMPLEMENTED</code> response code.
+     * <P>
+     * The headers received in the request can be retrieved from the
+     * <code>request</code> argument. The headers that should be sent in the
+     * reply must be specified in the <code>reply</code> argument.
+     * @param request contains the headers sent by the client;
+     *        <code>request</code> will never be <code>null</code>
+     * @param reply the headers that should be sent in the reply;
+     *        <code>reply</code> will never be <code>null</code>
+     * @return a response code defined in <code>ResponseCodes</code> that will
+     *         be returned to the client; if an invalid response code is
+     *         provided, the <code>OBEX_HTTP_INTERNAL_ERROR</code> response code
+     *         will be used
+     */
+    public int onDelete(HeaderSet request, HeaderSet reply) {
+        return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED;
+    }
+
+    /**
+     * Called when a ABORT request is received.
+     */
+    public int onAbort(HeaderSet request, HeaderSet reply) {
+        return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED;
+    }
+
+    /**
+     * Called when a PUT request is received.
+     * <P>
+     * If this method is not implemented by the class that extends this class,
+     * <code>onPut()</code> will always return an
+     * <code>OBEX_HTTP_NOT_IMPLEMENTED</code> response code.
+     * <P>
+     * If an ABORT request is received during the processing of a PUT request,
+     * <code>op</code> will be closed by the implementation.
+     * @param operation contains the headers sent by the client and allows new
+     *        headers to be sent in the reply; <code>op</code> will never be
+     *        <code>null</code>
+     * @return a response code defined in <code>ResponseCodes</code> that will
+     *         be returned to the client; if an invalid response code is
+     *         provided, the <code>OBEX_HTTP_INTERNAL_ERROR</code> response code
+     *         will be used
+     */
+    public int onPut(Operation operation) {
+        return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED;
+    }
+
+    /**
+     * Called when a GET request is received.
+     * <P>
+     * If this method is not implemented by the class that extends this class,
+     * <code>onGet()</code> will always return an
+     * <code>OBEX_HTTP_NOT_IMPLEMENTED</code> response code.
+     * <P>
+     * If an ABORT request is received during the processing of a GET request,
+     * <code>op</code> will be closed by the implementation.
+     * @param operation contains the headers sent by the client and allows new
+     *        headers to be sent in the reply; <code>op</code> will never be
+     *        <code>null</code>
+     * @return a response code defined in <code>ResponseCodes</code> that will
+     *         be returned to the client; if an invalid response code is
+     *         provided, the <code>OBEX_HTTP_INTERNAL_ERROR</code> response code
+     *         will be used
+     */
+    public int onGet(Operation operation) {
+        return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED;
+    }
+
+    /**
+     * Called when this object attempts to authenticate a client and the
+     * authentication request fails because the response digest in the
+     * authentication response header was wrong.
+     * <P>
+     * If this method is not implemented by the class that extends this class,
+     * this method will do nothing.
+     * @param userName the user name returned in the authentication response;
+     *        <code>null</code> if no user name was provided in the response
+     */
+    public void onAuthenticationFailure(byte[] userName) {
+    }
+
+    /**
+     * Called by ServerSession to update the status of current transaction
+     * <P>
+     * If this method is not implemented by the class that extends this class,
+     * this method will do nothing.
+     */
+    public void updateStatus(String message) {
+    }
+
+    /**
+     * Called when session is closed.
+     * <P>
+     * If this method is not implemented by the class that extends this class,
+     * this method will do nothing.
+     */
+    public void onClose() {
+    }
+
+    /**
+     * Override to add Single Response Mode support - e.g. if the supplied
+     * transport is l2cap.
+     * @return True if SRM is supported, else False
+     */
+    public boolean isSrmSupported() {
+        return false;
+    }
+}
diff --git a/javax/obex/ServerSession.java b/javax/obex/ServerSession.java
new file mode 100644
index 0000000..dbfeefd
--- /dev/null
+++ b/javax/obex/ServerSession.java
@@ -0,0 +1,742 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (c) 2015 Samsung LSI
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * 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 the Motorola, Inc. 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 HOLDER 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 javax.obex;
+
+import android.util.Log;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * This class in an implementation of the OBEX ServerSession.
+ * @hide
+ */
+public final class ServerSession extends ObexSession implements Runnable {
+
+    private static final String TAG = "Obex ServerSession";
+    private static final boolean V = ObexHelper.VDBG;
+
+    private ObexTransport mTransport;
+
+    private InputStream mInput;
+
+    private OutputStream mOutput;
+
+    private ServerRequestHandler mListener;
+
+    private Thread mProcessThread;
+
+    private int mMaxPacketLength;
+
+    private boolean mClosed;
+
+    /**
+     * Creates new ServerSession.
+     * @param trans the connection to the client
+     * @param handler the event listener that will process requests
+     * @param auth the authenticator to use with this connection
+     * @throws IOException if an error occurred while opening the input and
+     *         output streams
+     */
+    public ServerSession(ObexTransport trans, ServerRequestHandler handler, Authenticator auth)
+            throws IOException {
+        mAuthenticator = auth;
+        mTransport = trans;
+        mInput = mTransport.openInputStream();
+        mOutput = mTransport.openOutputStream();
+        mListener = handler;
+        mMaxPacketLength = 256;
+
+        mClosed = false;
+        mProcessThread = new Thread(this);
+        mProcessThread.start();
+    }
+
+    /**
+     * Processes requests made to the server and forwards them to the
+     * appropriate event listener.
+     */
+    public void run() {
+        try {
+
+            boolean done = false;
+            while (!done && !mClosed) {
+                if(V) Log.v(TAG, "Waiting for incoming request...");
+                int requestType = mInput.read();
+                if(V) Log.v(TAG, "Read request: " + requestType);
+                switch (requestType) {
+                    case ObexHelper.OBEX_OPCODE_CONNECT:
+                        handleConnectRequest();
+                        break;
+
+                    case ObexHelper.OBEX_OPCODE_DISCONNECT:
+                        handleDisconnectRequest();
+                        break;
+
+                    case ObexHelper.OBEX_OPCODE_GET:
+                    case ObexHelper.OBEX_OPCODE_GET_FINAL:
+                        handleGetRequest(requestType);
+                        break;
+
+                    case ObexHelper.OBEX_OPCODE_PUT:
+                    case ObexHelper.OBEX_OPCODE_PUT_FINAL:
+                        handlePutRequest(requestType);
+                        break;
+
+                    case ObexHelper.OBEX_OPCODE_SETPATH:
+                        handleSetPathRequest();
+                        break;
+                    case ObexHelper.OBEX_OPCODE_ABORT:
+                        handleAbortRequest();
+                        break;
+
+                    case -1:
+                        done = true;
+                        break;
+
+                    default:
+
+                        /*
+                         * Received a request type that is not recognized so I am
+                         * just going to read the packet and send a not implemented
+                         * to the client
+                         */
+                        int length = mInput.read();
+                        length = (length << 8) + mInput.read();
+                        for (int i = 3; i < length; i++) {
+                            mInput.read();
+                        }
+                        sendResponse(ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED, null);
+                }
+            }
+
+        } catch (NullPointerException e) {
+            Log.d(TAG, "Exception occured - ignoring", e);
+        } catch (Exception e) {
+            Log.d(TAG, "Exception occured - ignoring", e);
+        }
+        close();
+    }
+
+    /**
+     * Handles a ABORT request from a client. This method will read the rest of
+     * the request from the client. Assuming the request is valid, it will
+     * create a <code>HeaderSet</code> object to pass to the
+     * <code>ServerRequestHandler</code> object. After the handler processes the
+     * request, this method will create a reply message to send to the server.
+     *
+     * @throws IOException if an error occurred at the transport layer
+     */
+    private void handleAbortRequest() throws IOException {
+        int code = ResponseCodes.OBEX_HTTP_OK;
+        HeaderSet request = new HeaderSet();
+        HeaderSet reply = new HeaderSet();
+
+        int length = mInput.read();
+        length = (length << 8) + mInput.read();
+        if (length > ObexHelper.getMaxRxPacketSize(mTransport)) {
+            code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE;
+        } else {
+            for (int i = 3; i < length; i++) {
+                mInput.read();
+            }
+            code = mListener.onAbort(request, reply);
+            Log.v(TAG, "onAbort request handler return value- " + code);
+            code = validateResponseCode(code);
+        }
+        sendResponse(code, null);
+    }
+
+    /**
+     * Handles a PUT request from a client. This method will provide a
+     * <code>ServerOperation</code> object to the request handler. The
+     * <code>ServerOperation</code> object will handle the rest of the request.
+     * It will also send replies and receive requests until the final reply
+     * should be sent. When the final reply should be sent, this method will get
+     * the response code to use and send the reply. The
+     * <code>ServerOperation</code> object will always reply with a
+     * OBEX_HTTP_CONTINUE reply. It will only reply if further information is
+     * needed.
+     * @param type the type of request received; either 0x02 or 0x82
+     * @throws IOException if an error occurred at the transport layer
+     */
+    private void handlePutRequest(int type) throws IOException {
+        ServerOperation op = new ServerOperation(this, mInput, type, mMaxPacketLength, mListener);
+        try {
+            int response = -1;
+
+            if ((op.finalBitSet) && !op.isValidBody()) {
+                response = validateResponseCode(mListener
+                        .onDelete(op.requestHeader, op.replyHeader));
+            } else {
+                response = validateResponseCode(mListener.onPut(op));
+            }
+            if (response != ResponseCodes.OBEX_HTTP_OK && !op.isAborted) {
+                op.sendReply(response);
+            } else if (!op.isAborted) {
+                // wait for the final bit
+                while (!op.finalBitSet) {
+                    op.sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
+                }
+                op.sendReply(response);
+            }
+        } catch (Exception e) {
+            /*To fix bugs in aborted cases,
+             *(client abort file transfer prior to the last packet which has the end of body header,
+             *internal error should not be sent because server has already replied with
+             *OK response in "sendReply")
+             */
+            if(V) Log.d(TAG,"Exception occured - sending OBEX_HTTP_INTERNAL_ERROR reply",e);
+            if (!op.isAborted) {
+                sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
+            }
+        }
+    }
+
+    /**
+     * Handles a GET request from a client. This method will provide a
+     * <code>ServerOperation</code> object to the request handler. The
+     * <code>ServerOperation</code> object will handle the rest of the request.
+     * It will also send replies and receive requests until the final reply
+     * should be sent. When the final reply should be sent, this method will get
+     * the response code to use and send the reply. The
+     * <code>ServerOperation</code> object will always reply with a
+     * OBEX_HTTP_CONTINUE reply. It will only reply if further information is
+     * needed.
+     * @param type the type of request received; either 0x03 or 0x83
+     * @throws IOException if an error occurred at the transport layer
+     */
+    private void handleGetRequest(int type) throws IOException {
+        ServerOperation op = new ServerOperation(this, mInput, type, mMaxPacketLength, mListener);
+        try {
+            int response = validateResponseCode(mListener.onGet(op));
+
+            if (!op.isAborted) {
+                op.sendReply(response);
+            }
+        } catch (Exception e) {
+            if(V) Log.d(TAG,"Exception occured - sending OBEX_HTTP_INTERNAL_ERROR reply",e);
+            sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
+        }
+    }
+
+    /**
+     * Send standard response.
+     * @param code the response code to send
+     * @param header the headers to include in the response
+     * @throws IOException if an IO error occurs
+     */
+    public void sendResponse(int code, byte[] header) throws IOException {
+        int totalLength = 3;
+        byte[] data = null;
+        OutputStream op = mOutput;
+        if (op == null) {
+            return;
+        }
+
+        if (header != null) {
+            totalLength += header.length;
+            data = new byte[totalLength];
+            data[0] = (byte)code;
+            data[1] = (byte)(totalLength >> 8);
+            data[2] = (byte)totalLength;
+            System.arraycopy(header, 0, data, 3, header.length);
+        } else {
+            data = new byte[totalLength];
+            data[0] = (byte)code;
+            data[1] = (byte)0x00;
+            data[2] = (byte)totalLength;
+        }
+        op.write(data);
+        op.flush(); // TODO: Do we need to flush?
+    }
+
+    /**
+     * Handles a SETPATH request from a client. This method will read the rest
+     * of the request from the client. Assuming the request is valid, it will
+     * create a <code>HeaderSet</code> object to pass to the
+     * <code>ServerRequestHandler</code> object. After the handler processes the
+     * request, this method will create a reply message to send to the server
+     * with the response code provided.
+     * @throws IOException if an error occurred at the transport layer
+     */
+    private void handleSetPathRequest() throws IOException {
+        int length;
+        int flags;
+        @SuppressWarnings("unused")
+        int constants;
+        int totalLength = 3;
+        byte[] head = null;
+        int code = -1;
+        int bytesReceived;
+        HeaderSet request = new HeaderSet();
+        HeaderSet reply = new HeaderSet();
+
+        length = mInput.read();
+        length = (length << 8) + mInput.read();
+        flags = mInput.read();
+        constants = mInput.read();
+
+        if (length > ObexHelper.getMaxRxPacketSize(mTransport)) {
+            code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE;
+            totalLength = 3;
+        } else {
+            if (length > 5) {
+                byte[] headers = new byte[length - 5];
+                bytesReceived = mInput.read(headers);
+
+                while (bytesReceived != headers.length) {
+                    bytesReceived += mInput.read(headers, bytesReceived, headers.length
+                            - bytesReceived);
+                }
+
+                ObexHelper.updateHeaderSet(request, headers);
+
+                if (mListener.getConnectionId() != -1 && request.mConnectionID != null) {
+                    mListener.setConnectionId(ObexHelper.convertToLong(request.mConnectionID));
+                } else {
+                    mListener.setConnectionId(1);
+                }
+                // the Auth chan is initiated by the server, client sent back the authResp .
+                if (request.mAuthResp != null) {
+                    if (!handleAuthResp(request.mAuthResp)) {
+                        code = ResponseCodes.OBEX_HTTP_UNAUTHORIZED;
+                        mListener.onAuthenticationFailure(ObexHelper.getTagValue((byte)0x01,
+                                request.mAuthResp));
+                    }
+                    request.mAuthResp = null;
+                }
+            }
+
+            if (code != ResponseCodes.OBEX_HTTP_UNAUTHORIZED) {
+                // the Auth challenge is initiated by the client
+                // the server will send back the authResp to the client
+                if (request.mAuthChall != null) {
+                    handleAuthChall(request);
+                    reply.mAuthResp = new byte[request.mAuthResp.length];
+                    System.arraycopy(request.mAuthResp, 0, reply.mAuthResp, 0,
+                            reply.mAuthResp.length);
+                    request.mAuthChall = null;
+                    request.mAuthResp = null;
+                }
+                boolean backup = false;
+                boolean create = true;
+                if (!((flags & 1) == 0)) {
+                    backup = true;
+                }
+                if (!((flags & 2) == 0)) {
+                    create = false;
+                }
+
+                try {
+                    code = mListener.onSetPath(request, reply, backup, create);
+                } catch (Exception e) {
+                    if(V) Log.d(TAG,"Exception occured - sending OBEX_HTTP_INTERNAL_ERROR reply",e);
+                    sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
+                    return;
+                }
+
+                code = validateResponseCode(code);
+
+                if (reply.nonce != null) {
+                    mChallengeDigest = new byte[16];
+                    System.arraycopy(reply.nonce, 0, mChallengeDigest, 0, 16);
+                } else {
+                    mChallengeDigest = null;
+                }
+
+                long id = mListener.getConnectionId();
+                if (id == -1) {
+                    reply.mConnectionID = null;
+                } else {
+                    reply.mConnectionID = ObexHelper.convertToByteArray(id);
+                }
+
+                head = ObexHelper.createHeader(reply, false);
+                totalLength += head.length;
+
+                if (totalLength > mMaxPacketLength) {
+                    totalLength = 3;
+                    head = null;
+                    code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
+                }
+            }
+        }
+
+        // Compute Length of OBEX SETPATH packet
+        byte[] replyData = new byte[totalLength];
+        replyData[0] = (byte)code;
+        replyData[1] = (byte)(totalLength >> 8);
+        replyData[2] = (byte)totalLength;
+        if (head != null) {
+            System.arraycopy(head, 0, replyData, 3, head.length);
+        }
+        /*
+         * Write the OBEX SETPATH packet to the server. Byte 0: response code
+         * Byte 1&2: Connect Packet Length Byte 3 to n: headers
+         */
+        mOutput.write(replyData);
+        mOutput.flush();
+    }
+
+    /**
+     * Handles a disconnect request from a client. This method will read the
+     * rest of the request from the client. Assuming the request is valid, it
+     * will create a <code>HeaderSet</code> object to pass to the
+     * <code>ServerRequestHandler</code> object. After the handler processes the
+     * request, this method will create a reply message to send to the server.
+     * @throws IOException if an error occurred at the transport layer
+     */
+    private void handleDisconnectRequest() throws IOException {
+        int length;
+        int code = ResponseCodes.OBEX_HTTP_OK;
+        int totalLength = 3;
+        byte[] head = null;
+        int bytesReceived;
+        HeaderSet request = new HeaderSet();
+        HeaderSet reply = new HeaderSet();
+
+        length = mInput.read();
+        length = (length << 8) + mInput.read();
+
+        if (length > ObexHelper.getMaxRxPacketSize(mTransport)) {
+            code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE;
+            totalLength = 3;
+        } else {
+            if (length > 3) {
+                byte[] headers = new byte[length - 3];
+                bytesReceived = mInput.read(headers);
+
+                while (bytesReceived != headers.length) {
+                    bytesReceived += mInput.read(headers, bytesReceived, headers.length
+                            - bytesReceived);
+                }
+
+                ObexHelper.updateHeaderSet(request, headers);
+            }
+
+            if (mListener.getConnectionId() != -1 && request.mConnectionID != null) {
+                mListener.setConnectionId(ObexHelper.convertToLong(request.mConnectionID));
+            } else {
+                mListener.setConnectionId(1);
+            }
+
+            if (request.mAuthResp != null) {
+                if (!handleAuthResp(request.mAuthResp)) {
+                    code = ResponseCodes.OBEX_HTTP_UNAUTHORIZED;
+                    mListener.onAuthenticationFailure(ObexHelper.getTagValue((byte)0x01,
+                            request.mAuthResp));
+                }
+                request.mAuthResp = null;
+            }
+
+            if (code != ResponseCodes.OBEX_HTTP_UNAUTHORIZED) {
+
+                if (request.mAuthChall != null) {
+                    handleAuthChall(request);
+                    request.mAuthChall = null;
+                }
+
+                try {
+                    mListener.onDisconnect(request, reply);
+                } catch (Exception e) {
+                    if(V) Log.d(TAG,"Exception occured - sending OBEX_HTTP_INTERNAL_ERROR reply",e);
+                    sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
+                    return;
+                }
+
+                long id = mListener.getConnectionId();
+                if (id == -1) {
+                    reply.mConnectionID = null;
+                } else {
+                    reply.mConnectionID = ObexHelper.convertToByteArray(id);
+                }
+
+                head = ObexHelper.createHeader(reply, false);
+                totalLength += head.length;
+
+                if (totalLength > mMaxPacketLength) {
+                    totalLength = 3;
+                    head = null;
+                    code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
+                }
+            }
+        }
+
+        // Compute Length of OBEX CONNECT packet
+        byte[] replyData;
+        if (head != null) {
+            replyData = new byte[3 + head.length];
+        } else {
+            replyData = new byte[3];
+        }
+        replyData[0] = (byte)code;
+        replyData[1] = (byte)(totalLength >> 8);
+        replyData[2] = (byte)totalLength;
+        if (head != null) {
+            System.arraycopy(head, 0, replyData, 3, head.length);
+        }
+        /*
+         * Write the OBEX DISCONNECT packet to the server. Byte 0: response code
+         * Byte 1&2: Connect Packet Length Byte 3 to n: headers
+         */
+        mOutput.write(replyData);
+        mOutput.flush();
+    }
+
+    /**
+     * Handles a connect request from a client. This method will read the rest
+     * of the request from the client. Assuming the request is valid, it will
+     * create a <code>HeaderSet</code> object to pass to the
+     * <code>ServerRequestHandler</code> object. After the handler processes the
+     * request, this method will create a reply message to send to the server
+     * with the response code provided.
+     * @throws IOException if an error occurred at the transport layer
+     */
+    private void handleConnectRequest() throws IOException {
+        int packetLength;
+        @SuppressWarnings("unused")
+        int version;
+        @SuppressWarnings("unused")
+        int flags;
+        int totalLength = 7;
+        byte[] head = null;
+        int code = -1;
+        HeaderSet request = new HeaderSet();
+        HeaderSet reply = new HeaderSet();
+        int bytesReceived;
+
+        if(V) Log.v(TAG,"handleConnectRequest()");
+
+        /*
+         * Read in the length of the OBEX packet, OBEX version, flags, and max
+         * packet length
+         */
+        packetLength = mInput.read();
+        packetLength = (packetLength << 8) + mInput.read();
+        if(V) Log.v(TAG,"handleConnectRequest() - packetLength: " + packetLength);
+
+        version = mInput.read();
+        flags = mInput.read();
+        mMaxPacketLength = mInput.read();
+        mMaxPacketLength = (mMaxPacketLength << 8) + mInput.read();
+
+        if(V) Log.v(TAG,"handleConnectRequest() - version: " + version
+                + " MaxLength: " + mMaxPacketLength + " flags: " + flags);
+
+        // should we check it?
+        if (mMaxPacketLength > ObexHelper.MAX_PACKET_SIZE_INT) {
+            mMaxPacketLength = ObexHelper.MAX_PACKET_SIZE_INT;
+        }
+
+        if(mMaxPacketLength > ObexHelper.getMaxTxPacketSize(mTransport)) {
+            Log.w(TAG, "Requested MaxObexPacketSize " + mMaxPacketLength
+                    + " is larger than the max size supported by the transport: "
+                    + ObexHelper.getMaxTxPacketSize(mTransport)
+                    + " Reducing to this size.");
+            mMaxPacketLength = ObexHelper.getMaxTxPacketSize(mTransport);
+        }
+
+        if (packetLength > ObexHelper.getMaxRxPacketSize(mTransport)) {
+            code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE;
+            totalLength = 7;
+        } else {
+            if (packetLength > 7) {
+                byte[] headers = new byte[packetLength - 7];
+                bytesReceived = mInput.read(headers);
+
+                while (bytesReceived != headers.length) {
+                    bytesReceived += mInput.read(headers, bytesReceived, headers.length
+                            - bytesReceived);
+                }
+
+                ObexHelper.updateHeaderSet(request, headers);
+            }
+
+            if (mListener.getConnectionId() != -1 && request.mConnectionID != null) {
+                mListener.setConnectionId(ObexHelper.convertToLong(request.mConnectionID));
+            } else {
+                mListener.setConnectionId(1);
+            }
+
+            if (request.mAuthResp != null) {
+                if (!handleAuthResp(request.mAuthResp)) {
+                    code = ResponseCodes.OBEX_HTTP_UNAUTHORIZED;
+                    mListener.onAuthenticationFailure(ObexHelper.getTagValue((byte)0x01,
+                            request.mAuthResp));
+                }
+                request.mAuthResp = null;
+            }
+
+            if (code != ResponseCodes.OBEX_HTTP_UNAUTHORIZED) {
+                if (request.mAuthChall != null) {
+                    handleAuthChall(request);
+                    reply.mAuthResp = new byte[request.mAuthResp.length];
+                    System.arraycopy(request.mAuthResp, 0, reply.mAuthResp, 0,
+                            reply.mAuthResp.length);
+                    request.mAuthChall = null;
+                    request.mAuthResp = null;
+                }
+
+                try {
+                    code = mListener.onConnect(request, reply);
+                    code = validateResponseCode(code);
+
+                    if (reply.nonce != null) {
+                        mChallengeDigest = new byte[16];
+                        System.arraycopy(reply.nonce, 0, mChallengeDigest, 0, 16);
+                    } else {
+                        mChallengeDigest = null;
+                    }
+                    long id = mListener.getConnectionId();
+                    if (id == -1) {
+                        reply.mConnectionID = null;
+                    } else {
+                        reply.mConnectionID = ObexHelper.convertToByteArray(id);
+                    }
+
+                    head = ObexHelper.createHeader(reply, false);
+                    totalLength += head.length;
+
+                    if (totalLength > mMaxPacketLength) {
+                        totalLength = 7;
+                        head = null;
+                        code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
+                    }
+                } catch (Exception e) {
+                    if(V) Log.d(TAG,"Exception occured - sending OBEX_HTTP_INTERNAL_ERROR reply",e);
+                    totalLength = 7;
+                    head = null;
+                    code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
+                }
+
+            }
+        }
+
+        // Compute Length of OBEX CONNECT packet
+        byte[] length = ObexHelper.convertToByteArray(totalLength);
+
+        /*
+         * Write the OBEX CONNECT packet to the server. Byte 0: response code
+         * Byte 1&2: Connect Packet Length Byte 3: OBEX Version Number
+         * (Presently, 0x10) Byte 4: Flags (For TCP 0x00) Byte 5&6: Max OBEX
+         * Packet Length (Defined in MAX_PACKET_SIZE) Byte 7 to n: headers
+         */
+        byte[] sendData = new byte[totalLength];
+        int maxRxLength = ObexHelper.getMaxRxPacketSize(mTransport);
+        if (maxRxLength > mMaxPacketLength) {
+            if(V) Log.v(TAG,"Set maxRxLength to min of maxRxServrLen:" + maxRxLength +
+                    " and MaxNegotiated from Client: " + mMaxPacketLength);
+            maxRxLength = mMaxPacketLength;
+        }
+        sendData[0] = (byte)code;
+        sendData[1] = length[2];
+        sendData[2] = length[3];
+        sendData[3] = (byte)0x10;
+        sendData[4] = (byte)0x00;
+        sendData[5] = (byte)(maxRxLength >> 8);
+        sendData[6] = (byte)(maxRxLength & 0xFF);
+
+        if (head != null) {
+            System.arraycopy(head, 0, sendData, 7, head.length);
+        }
+
+        mOutput.write(sendData);
+        mOutput.flush();
+    }
+
+    /**
+     * Closes the server session - in detail close I/O streams and the
+     * underlying transport layer. Internal flag is also set so that later
+     * attempt to read/write will throw an exception.
+     */
+    public synchronized void close() {
+        if (mListener != null) {
+            mListener.onClose();
+        }
+        try {
+            /* Set state to closed before interrupting the thread by closing the streams */
+            mClosed = true;
+            if(mInput != null)
+                mInput.close();
+            if(mOutput != null)
+                mOutput.close();
+            if(mTransport != null)
+                mTransport.close();
+        } catch (Exception e) {
+            if(V) Log.d(TAG,"Exception occured during close() - ignore",e);
+        }
+        mTransport = null;
+        mInput = null;
+        mOutput = null;
+        mListener = null;
+    }
+
+    /**
+     * Verifies that the response code is valid. If it is not valid, it will
+     * return the <code>OBEX_HTTP_INTERNAL_ERROR</code> response code.
+     * @param code the response code to check
+     * @return the valid response code or <code>OBEX_HTTP_INTERNAL_ERROR</code>
+     *         if <code>code</code> is not valid
+     */
+    private int validateResponseCode(int code) {
+
+        if ((code >= ResponseCodes.OBEX_HTTP_OK) && (code <= ResponseCodes.OBEX_HTTP_PARTIAL)) {
+            return code;
+        }
+        if ((code >= ResponseCodes.OBEX_HTTP_MULT_CHOICE)
+                && (code <= ResponseCodes.OBEX_HTTP_USE_PROXY)) {
+            return code;
+        }
+        if ((code >= ResponseCodes.OBEX_HTTP_BAD_REQUEST)
+                && (code <= ResponseCodes.OBEX_HTTP_UNSUPPORTED_TYPE)) {
+            return code;
+        }
+        if ((code >= ResponseCodes.OBEX_HTTP_INTERNAL_ERROR)
+                && (code <= ResponseCodes.OBEX_HTTP_VERSION)) {
+            return code;
+        }
+        if ((code >= ResponseCodes.OBEX_DATABASE_FULL)
+                && (code <= ResponseCodes.OBEX_DATABASE_LOCKED)) {
+            return code;
+        }
+        return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
+    }
+
+    public ObexTransport getTransport() {
+        return mTransport;
+    }
+}
diff --git a/javax/obex/SessionNotifier.java b/javax/obex/SessionNotifier.java
new file mode 100644
index 0000000..9836dd6
--- /dev/null
+++ b/javax/obex/SessionNotifier.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * 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 the Motorola, Inc. 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 HOLDER 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 javax.obex;
+
+import java.io.IOException;
+
+/**
+ * The <code>SessionNotifier</code> interface defines a connection notifier for
+ * server-side OBEX connections. When a <code>SessionNotifier</code> is created
+ * and calls <code>acceptAndOpen()</code>, it will begin listening for clients
+ * to create a connection at the transport layer. When the transport layer
+ * connection is received, the <code>acceptAndOpen()</code> method will return a
+ * <code>javax.microedition.io.Connection</code> that is the connection to the
+ * client. The <code>acceptAndOpen()</code> method also takes a
+ * <code>ServerRequestHandler</code> argument that will process the requests
+ * from the client that connects to the server.
+ * @hide
+ */
+public interface SessionNotifier {
+
+    /**
+     * Waits for a transport layer connection to be established and specifies
+     * the handler to handle the requests from the client. No authenticator is
+     * associated with this connection, therefore, it is implementation
+     * dependent as to how an authentication challenge and authentication
+     * response header will be received and processed.
+     * <P>
+     * <H4>Additional Note for OBEX over Bluetooth</H4> If this method is called
+     * on a <code>SessionNotifier</code> object that does not have a
+     * <code>ServiceRecord</code> in the SDDB, the <code>ServiceRecord</code>
+     * for this object will be added to the SDDB. This method requests the BCC
+     * to put the local device in connectable mode so that it will respond to
+     * connection attempts by clients.
+     * <P>
+     * The following checks are done to verify that the service record provided
+     * is valid. If any of these checks fail, then a
+     * <code>ServiceRegistrationException</code> is thrown.
+     * <UL>
+     * <LI>ServiceClassIDList and ProtocolDescriptorList, the mandatory service
+     * attributes for a <code>btgoep</code> service record, must be present in
+     * the <code>ServiceRecord</code> associated with this notifier.
+     * <LI>L2CAP, RFCOMM and OBEX must all be in the ProtocolDescriptorList
+     * <LI>The <code>ServiceRecord</code> associated with this notifier must not
+     * have changed the RFCOMM server channel number
+     * </UL>
+     * <P>
+     * This method will not ensure that <code>ServiceRecord</code> associated
+     * with this notifier is a completely valid service record. It is the
+     * responsibility of the application to ensure that the service record
+     * follows all of the applicable syntactic and semantic rules for service
+     * record correctness.
+     * @param handler the request handler that will respond to OBEX requests
+     * @return the connection to the client
+     * @throws IOException if an error occurs in the transport layer
+     * @throws NullPointerException if <code>handler</code> is <code>null</code>
+     */
+    ObexSession acceptAndOpen(ServerRequestHandler handler) throws IOException;
+
+    /**
+     * Waits for a transport layer connection to be established and specifies
+     * the handler to handle the requests from the client and the
+     * <code>Authenticator</code> to use to respond to authentication challenge
+     * and authentication response headers.
+     * <P>
+     * <H4>Additional Note for OBEX over Bluetooth</H4> If this method is called
+     * on a <code>SessionNotifier</code> object that does not have a
+     * <code>ServiceRecord</code> in the SDDB, the <code>ServiceRecord</code>
+     * for this object will be added to the SDDB. This method requests the BCC
+     * to put the local device in connectable mode so that it will respond to
+     * connection attempts by clients.
+     * <P>
+     * The following checks are done to verify that the service record provided
+     * is valid. If any of these checks fail, then a
+     * <code>ServiceRegistrationException</code> is thrown.
+     * <UL>
+     * <LI>ServiceClassIDList and ProtocolDescriptorList, the mandatory service
+     * attributes for a <code>btgoep</code> service record, must be present in
+     * the <code>ServiceRecord</code> associated with this notifier.
+     * <LI>L2CAP, RFCOMM and OBEX must all be in the ProtocolDescriptorList
+     * <LI>The <code>ServiceRecord</code> associated with this notifier must not
+     * have changed the RFCOMM server channel number
+     * </UL>
+     * <P>
+     * This method will not ensure that <code>ServiceRecord</code> associated
+     * with this notifier is a completely valid service record. It is the
+     * responsibility of the application to ensure that the service record
+     * follows all of the applicable syntactic and semantic rules for service
+     * record correctness.
+     * @param handler the request handler that will respond to OBEX requests
+     * @param auth the <code>Authenticator</code> to use with this connection;
+     *        if <code>null</code> then no <code>Authenticator</code> will be
+     *        used
+     * @return the connection to the client
+     * @throws IOException if an error occurs in the transport layer
+     * @throws NullPointerException if <code>handler</code> is <code>null</code>
+     */
+    ObexSession acceptAndOpen(ServerRequestHandler handler, Authenticator auth) throws IOException;
+}
diff --git a/javax/security/auth/AuthPermission.java b/javax/security/auth/AuthPermission.java
new file mode 100644
index 0000000..71c3aaf
--- /dev/null
+++ b/javax/security/auth/AuthPermission.java
@@ -0,0 +1,39 @@
+/*
+ * 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 javax.security.auth;
+
+// 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 AuthPermission extends
+java.security.BasicPermission {
+
+    public AuthPermission(String name) { super(""); }
+
+    public AuthPermission(String name, String actions) { super("", ""); }
+}
diff --git a/javax/security/auth/DestroyFailedException.java b/javax/security/auth/DestroyFailedException.java
new file mode 100644
index 0000000..41e99a3
--- /dev/null
+++ b/javax/security/auth/DestroyFailedException.java
@@ -0,0 +1,60 @@
+/*
+ * 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 javax.security.auth;
+
+/**
+ * Signals that a {@code destroy} operation failed.
+ *
+ * <p> This exception is thrown by credentials implementing
+ * the {@code Destroyable} interface when the {@code destroy}
+ * method fails.
+ *
+ */
+public class DestroyFailedException extends Exception {
+
+    private static final long serialVersionUID = -7790152857282749162L;
+
+    /**
+     * Constructs a DestroyFailedException with no detail message. A detail
+     * message is a String that describes this particular exception.
+     */
+    public DestroyFailedException() {
+        super();
+    }
+
+    /**
+     * Constructs a DestroyFailedException with the specified detail
+     * message.  A detail message is a String that describes this particular
+     * exception.
+     *
+     * <p>
+     *
+     * @param msg the detail message.
+     */
+    public DestroyFailedException(String msg) {
+        super(msg);
+    }
+}
diff --git a/javax/security/auth/Destroyable.java b/javax/security/auth/Destroyable.java
new file mode 100644
index 0000000..5ade89e
--- /dev/null
+++ b/javax/security/auth/Destroyable.java
@@ -0,0 +1,80 @@
+/*
+ * 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 javax.security.auth;
+
+/**
+ * Objects such as credentials may optionally implement this interface
+ * to provide the capability to destroy its contents.
+ *
+ * @see javax.security.auth.Subject
+ */
+public interface Destroyable {
+
+    /**
+     * Destroy this {@code Object}.
+     *
+     * <p> Sensitive information associated with this {@code Object}
+     * is destroyed or cleared.  Subsequent calls to certain methods
+     * on this {@code Object} will result in an
+     * {@code IllegalStateException} being thrown.
+     *
+     * <p>
+     * The default implementation throws {@code DestroyFailedException}.
+     *
+     * <p>
+     * Android note: Up to and including API 25 this method did not have a
+     * default implementation. Implementations of this interface must provide
+     * a concrete implementation of this method in order to work on older
+     * versions of Android.
+     *
+     * @exception DestroyFailedException if the destroy operation fails. <p>
+     *
+     * @exception SecurityException if the caller does not have permission
+     *          to destroy this {@code Object}.
+     */
+    public default void destroy() throws DestroyFailedException {
+        throw new DestroyFailedException();
+    }
+
+    /**
+     * Determine if this {@code Object} has been destroyed.
+     *
+     * <p>
+     * The default implementation returns false.
+     *
+     * <p>
+     * Android note: Up to and including API 25 this method did not have a
+     * default implementation. Implementations of this interface must provide
+     * a concrete implementation of this method in order to work on older
+     * versions of Android.
+     *
+     * @return true if this {@code Object} has been destroyed,
+     *          false otherwise.
+     */
+    public default boolean isDestroyed() {
+        return false;
+    }
+}
diff --git a/javax/security/auth/PrivateCredentialPermission.java b/javax/security/auth/PrivateCredentialPermission.java
new file mode 100644
index 0000000..9733932
--- /dev/null
+++ b/javax/security/auth/PrivateCredentialPermission.java
@@ -0,0 +1,51 @@
+/*
+ * 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 javax.security.auth;
+
+import java.util.*;
+import java.security.Permission;
+import java.security.Principal;
+
+// 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 PrivateCredentialPermission extends Permission {
+
+    PrivateCredentialPermission(String credentialClass,
+                                Set<Principal> principals) { super(""); }
+
+    public PrivateCredentialPermission(String name, String actions) { super(""); }
+
+    public String getCredentialClass() { return null; }
+
+    public String[][] getPrincipals() { return null; }
+
+    public boolean implies(Permission p) { return true; }
+
+    public String getActions() { return null; }
+}
diff --git a/javax/security/auth/Subject.java b/javax/security/auth/Subject.java
new file mode 100644
index 0000000..2c9e8b8
--- /dev/null
+++ b/javax/security/auth/Subject.java
@@ -0,0 +1,1467 @@
+/*
+ * 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 javax.security.auth;
+
+import java.util.*;
+import java.io.*;
+import java.lang.reflect.*;
+import java.text.MessageFormat;
+import java.security.AccessController;
+import java.security.AccessControlContext;
+import java.security.DomainCombiner;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.Principal;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedExceptionAction;
+import java.security.PrivilegedActionException;
+import java.security.ProtectionDomain;
+import sun.security.util.ResourcesMgr;
+
+/**
+ * <p> A {@code Subject} represents a grouping of related information
+ * for a single entity, such as a person.
+ * Such information includes the Subject's identities as well as
+ * its security-related attributes
+ * (passwords and cryptographic keys, for example).
+ *
+ * <p> Subjects may potentially have multiple identities.
+ * Each identity is represented as a {@code Principal}
+ * within the {@code Subject}.  Principals simply bind names to a
+ * {@code Subject}.  For example, a {@code Subject} that happens
+ * to be a person, Alice, might have two Principals:
+ * one which binds "Alice Bar", the name on her driver license,
+ * to the {@code Subject}, and another which binds,
+ * "999-99-9999", the number on her student identification card,
+ * to the {@code Subject}.  Both Principals refer to the same
+ * {@code Subject} even though each has a different name.
+ *
+ * <p> A {@code Subject} may also own security-related attributes,
+ * which are referred to as credentials.
+ * Sensitive credentials that require special protection, such as
+ * private cryptographic keys, are stored within a private credential
+ * {@code Set}.  Credentials intended to be shared, such as
+ * public key certificates or Kerberos server tickets are stored
+ * within a public credential {@code Set}.  Different permissions
+ * are required to access and modify the different credential Sets.
+ *
+ * <p> To retrieve all the Principals associated with a {@code Subject},
+ * invoke the {@code getPrincipals} method.  To retrieve
+ * all the public or private credentials belonging to a {@code Subject},
+ * invoke the {@code getPublicCredentials} method or
+ * {@code getPrivateCredentials} method, respectively.
+ * To modify the returned {@code Set} of Principals and credentials,
+ * use the methods defined in the {@code Set} class.
+ * For example:
+ * <pre>
+ *      Subject subject;
+ *      Principal principal;
+ *      Object credential;
+ *
+ *      // add a Principal and credential to the Subject
+ *      subject.getPrincipals().add(principal);
+ *      subject.getPublicCredentials().add(credential);
+ * </pre>
+ *
+ * <p> This {@code Subject} class implements {@code Serializable}.
+ * While the Principals associated with the {@code Subject} are serialized,
+ * the credentials associated with the {@code Subject} are not.
+ * Note that the {@code java.security.Principal} class
+ * does not implement {@code Serializable}.  Therefore all concrete
+ * {@code Principal} implementations associated with Subjects
+ * must implement {@code Serializable}.
+ *
+ * @see java.security.Principal
+ * @see java.security.DomainCombiner
+ */
+public final class Subject implements java.io.Serializable {
+
+    private static final long serialVersionUID = -8308522755600156056L;
+
+    /**
+     * A {@code Set} that provides a view of all of this
+     * Subject's Principals
+     *
+     * <p>
+     *
+     * @serial Each element in this set is a
+     *          {@code java.security.Principal}.
+     *          The set is a {@code Subject.SecureSet}.
+     */
+    Set<Principal> principals;
+
+    /**
+     * Sets that provide a view of all of this
+     * Subject's Credentials
+     */
+    transient Set<Object> pubCredentials;
+    transient Set<Object> privCredentials;
+
+    /**
+     * Whether this Subject is read-only
+     *
+     * @serial
+     */
+    private volatile boolean readOnly = false;
+
+    private static final int PRINCIPAL_SET = 1;
+    private static final int PUB_CREDENTIAL_SET = 2;
+    private static final int PRIV_CREDENTIAL_SET = 3;
+
+    private static final ProtectionDomain[] NULL_PD_ARRAY
+        = new ProtectionDomain[0];
+
+    /**
+     * Create an instance of a {@code Subject}
+     * with an empty {@code Set} of Principals and empty
+     * Sets of public and private credentials.
+     *
+     * <p> The newly constructed Sets check whether this {@code Subject}
+     * has been set read-only before permitting subsequent modifications.
+     * The newly created Sets also prevent illegal modifications
+     * by ensuring that callers have sufficient permissions.
+     *
+     * <p> To modify the Principals Set, the caller must have
+     * {@code AuthPermission("modifyPrincipals")}.
+     * To modify the public credential Set, the caller must have
+     * {@code AuthPermission("modifyPublicCredentials")}.
+     * To modify the private credential Set, the caller must have
+     * {@code AuthPermission("modifyPrivateCredentials")}.
+     */
+    public Subject() {
+
+        this.principals = Collections.synchronizedSet
+                        (new SecureSet<Principal>(this, PRINCIPAL_SET));
+        this.pubCredentials = Collections.synchronizedSet
+                        (new SecureSet<Object>(this, PUB_CREDENTIAL_SET));
+        this.privCredentials = Collections.synchronizedSet
+                        (new SecureSet<Object>(this, PRIV_CREDENTIAL_SET));
+    }
+
+    /**
+     * Create an instance of a {@code Subject} with
+     * Principals and credentials.
+     *
+     * <p> The Principals and credentials from the specified Sets
+     * are copied into newly constructed Sets.
+     * These newly created Sets check whether this {@code Subject}
+     * has been set read-only before permitting subsequent modifications.
+     * The newly created Sets also prevent illegal modifications
+     * by ensuring that callers have sufficient permissions.
+     *
+     * <p> To modify the Principals Set, the caller must have
+     * {@code AuthPermission("modifyPrincipals")}.
+     * To modify the public credential Set, the caller must have
+     * {@code AuthPermission("modifyPublicCredentials")}.
+     * To modify the private credential Set, the caller must have
+     * {@code AuthPermission("modifyPrivateCredentials")}.
+     * <p>
+     *
+     * @param readOnly true if the {@code Subject} is to be read-only,
+     *          and false otherwise. <p>
+     *
+     * @param principals the {@code Set} of Principals
+     *          to be associated with this {@code Subject}. <p>
+     *
+     * @param pubCredentials the {@code Set} of public credentials
+     *          to be associated with this {@code Subject}. <p>
+     *
+     * @param privCredentials the {@code Set} of private credentials
+     *          to be associated with this {@code Subject}.
+     *
+     * @exception NullPointerException if the specified
+     *          {@code principals}, {@code pubCredentials},
+     *          or {@code privCredentials} are {@code null}.
+     */
+    public Subject(boolean readOnly, Set<? extends Principal> principals,
+                   Set<?> pubCredentials, Set<?> privCredentials)
+    {
+
+        if (principals == null ||
+            pubCredentials == null ||
+            privCredentials == null)
+            throw new NullPointerException
+                (ResourcesMgr.getString("invalid.null.input.s."));
+
+        this.principals = Collections.synchronizedSet(new SecureSet<Principal>
+                                (this, PRINCIPAL_SET, principals));
+        this.pubCredentials = Collections.synchronizedSet(new SecureSet<Object>
+                                (this, PUB_CREDENTIAL_SET, pubCredentials));
+        this.privCredentials = Collections.synchronizedSet(new SecureSet<Object>
+                                (this, PRIV_CREDENTIAL_SET, privCredentials));
+        this.readOnly = readOnly;
+    }
+
+    /**
+     * Set this {@code Subject} to be read-only.
+     *
+     * <p> Modifications (additions and removals) to this Subject's
+     * {@code Principal} {@code Set} and
+     * credential Sets will be disallowed.
+     * The {@code destroy} operation on this Subject's credentials will
+     * still be permitted.
+     *
+     * <p> Subsequent attempts to modify the Subject's {@code Principal}
+     * and credential Sets will result in an
+     * {@code IllegalStateException} being thrown.
+     * Also, once a {@code Subject} is read-only,
+     * it can not be reset to being writable again.
+     *
+     * <p>
+     *
+     * @exception SecurityException if the caller does not have permission
+     *          to set this {@code Subject} to be read-only.
+     */
+    public void setReadOnly() {
+        java.lang.SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(AuthPermissionHolder.SET_READ_ONLY_PERMISSION);
+        }
+
+        this.readOnly = true;
+    }
+
+    /**
+     * Query whether this {@code Subject} is read-only.
+     *
+     * <p>
+     *
+     * @return true if this {@code Subject} is read-only, false otherwise.
+     */
+    public boolean isReadOnly() {
+        return this.readOnly;
+    }
+
+    /**
+     * Get the {@code Subject} associated with the provided
+     * {@code AccessControlContext}.
+     *
+     * <p> The {@code AccessControlContext} may contain many
+     * Subjects (from nested {@code doAs} calls).
+     * In this situation, the most recent {@code Subject} associated
+     * with the {@code AccessControlContext} is returned.
+     *
+     * <p>
+     *
+     * @param  acc the {@code AccessControlContext} from which to retrieve
+     *          the {@code Subject}.
+     *
+     * @return  the {@code Subject} associated with the provided
+     *          {@code AccessControlContext}, or {@code null}
+     *          if no {@code Subject} is associated
+     *          with the provided {@code AccessControlContext}.
+     *
+     * @exception SecurityException if the caller does not have permission
+     *          to get the {@code Subject}. <p>
+     *
+     * @exception NullPointerException if the provided
+     *          {@code AccessControlContext} is {@code null}.
+     */
+    public static Subject getSubject(final AccessControlContext acc) {
+
+        java.lang.SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(AuthPermissionHolder.GET_SUBJECT_PERMISSION);
+        }
+
+        if (acc == null) {
+            throw new NullPointerException(ResourcesMgr.getString
+                ("invalid.null.AccessControlContext.provided"));
+        }
+
+        // return the Subject from the DomainCombiner of the provided context
+        return AccessController.doPrivileged
+            (new java.security.PrivilegedAction<Subject>() {
+            public Subject run() {
+                DomainCombiner dc = acc.getDomainCombiner();
+                if (!(dc instanceof SubjectDomainCombiner))
+                    return null;
+                SubjectDomainCombiner sdc = (SubjectDomainCombiner)dc;
+                return sdc.getSubject();
+            }
+        });
+    }
+
+    /**
+     * Perform work as a particular {@code Subject}.
+     *
+     * <p> This method first retrieves the current Thread's
+     * {@code AccessControlContext} via
+     * {@code AccessController.getContext},
+     * and then instantiates a new {@code AccessControlContext}
+     * using the retrieved context along with a new
+     * {@code SubjectDomainCombiner} (constructed using
+     * the provided {@code Subject}).
+     * Finally, this method invokes {@code AccessController.doPrivileged},
+     * passing it the provided {@code PrivilegedAction},
+     * as well as the newly constructed {@code AccessControlContext}.
+     *
+     * <p>
+     *
+     * @param subject the {@code Subject} that the specified
+     *                  {@code action} will run as.  This parameter
+     *                  may be {@code null}. <p>
+     *
+     * @param <T> the type of the value returned by the PrivilegedAction's
+     *                  {@code run} method.
+     *
+     * @param action the code to be run as the specified
+     *                  {@code Subject}. <p>
+     *
+     * @return the value returned by the PrivilegedAction's
+     *                  {@code run} method.
+     *
+     * @exception NullPointerException if the {@code PrivilegedAction}
+     *                  is {@code null}. <p>
+     *
+     * @exception SecurityException if the caller does not have permission
+     *                  to invoke this method.
+     */
+    public static <T> T doAs(final Subject subject,
+                        final java.security.PrivilegedAction<T> action) {
+
+        java.lang.SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(AuthPermissionHolder.DO_AS_PERMISSION);
+        }
+        if (action == null)
+            throw new NullPointerException
+                (ResourcesMgr.getString("invalid.null.action.provided"));
+
+        // set up the new Subject-based AccessControlContext
+        // for doPrivileged
+        final AccessControlContext currentAcc = AccessController.getContext();
+
+        // call doPrivileged and push this new context on the stack
+        return java.security.AccessController.doPrivileged
+                                        (action,
+                                        createContext(subject, currentAcc));
+    }
+
+    /**
+     * Perform work as a particular {@code Subject}.
+     *
+     * <p> This method first retrieves the current Thread's
+     * {@code AccessControlContext} via
+     * {@code AccessController.getContext},
+     * and then instantiates a new {@code AccessControlContext}
+     * using the retrieved context along with a new
+     * {@code SubjectDomainCombiner} (constructed using
+     * the provided {@code Subject}).
+     * Finally, this method invokes {@code AccessController.doPrivileged},
+     * passing it the provided {@code PrivilegedExceptionAction},
+     * as well as the newly constructed {@code AccessControlContext}.
+     *
+     * <p>
+     *
+     * @param subject the {@code Subject} that the specified
+     *                  {@code action} will run as.  This parameter
+     *                  may be {@code null}. <p>
+     *
+     * @param <T> the type of the value returned by the
+     *                  PrivilegedExceptionAction's {@code run} method.
+     *
+     * @param action the code to be run as the specified
+     *                  {@code Subject}. <p>
+     *
+     * @return the value returned by the
+     *                  PrivilegedExceptionAction's {@code run} method.
+     *
+     * @exception PrivilegedActionException if the
+     *                  {@code PrivilegedExceptionAction.run}
+     *                  method throws a checked exception. <p>
+     *
+     * @exception NullPointerException if the specified
+     *                  {@code PrivilegedExceptionAction} is
+     *                  {@code null}. <p>
+     *
+     * @exception SecurityException if the caller does not have permission
+     *                  to invoke this method.
+     */
+    public static <T> T doAs(final Subject subject,
+                        final java.security.PrivilegedExceptionAction<T> action)
+                        throws java.security.PrivilegedActionException {
+
+        java.lang.SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(AuthPermissionHolder.DO_AS_PERMISSION);
+        }
+
+        if (action == null)
+            throw new NullPointerException
+                (ResourcesMgr.getString("invalid.null.action.provided"));
+
+        // set up the new Subject-based AccessControlContext for doPrivileged
+        final AccessControlContext currentAcc = AccessController.getContext();
+
+        // call doPrivileged and push this new context on the stack
+        return java.security.AccessController.doPrivileged
+                                        (action,
+                                        createContext(subject, currentAcc));
+    }
+
+    /**
+     * Perform privileged work as a particular {@code Subject}.
+     *
+     * <p> This method behaves exactly as {@code Subject.doAs},
+     * except that instead of retrieving the current Thread's
+     * {@code AccessControlContext}, it uses the provided
+     * {@code AccessControlContext}.  If the provided
+     * {@code AccessControlContext} is {@code null},
+     * this method instantiates a new {@code AccessControlContext}
+     * with an empty collection of ProtectionDomains.
+     *
+     * <p>
+     *
+     * @param subject the {@code Subject} that the specified
+     *                  {@code action} will run as.  This parameter
+     *                  may be {@code null}. <p>
+     *
+     * @param <T> the type of the value returned by the PrivilegedAction's
+     *                  {@code run} method.
+     *
+     * @param action the code to be run as the specified
+     *                  {@code Subject}. <p>
+     *
+     * @param acc the {@code AccessControlContext} to be tied to the
+     *                  specified <i>subject</i> and <i>action</i>. <p>
+     *
+     * @return the value returned by the PrivilegedAction's
+     *                  {@code run} method.
+     *
+     * @exception NullPointerException if the {@code PrivilegedAction}
+     *                  is {@code null}. <p>
+     *
+     * @exception SecurityException if the caller does not have permission
+     *                  to invoke this method.
+     */
+    public static <T> T doAsPrivileged(final Subject subject,
+                        final java.security.PrivilegedAction<T> action,
+                        final java.security.AccessControlContext acc) {
+
+        java.lang.SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(AuthPermissionHolder.DO_AS_PRIVILEGED_PERMISSION);
+        }
+
+        if (action == null)
+            throw new NullPointerException
+                (ResourcesMgr.getString("invalid.null.action.provided"));
+
+        // set up the new Subject-based AccessControlContext
+        // for doPrivileged
+        final AccessControlContext callerAcc =
+                (acc == null ?
+                new AccessControlContext(NULL_PD_ARRAY) :
+                acc);
+
+        // call doPrivileged and push this new context on the stack
+        return java.security.AccessController.doPrivileged
+                                        (action,
+                                        createContext(subject, callerAcc));
+    }
+
+    /**
+     * Perform privileged work as a particular {@code Subject}.
+     *
+     * <p> This method behaves exactly as {@code Subject.doAs},
+     * except that instead of retrieving the current Thread's
+     * {@code AccessControlContext}, it uses the provided
+     * {@code AccessControlContext}.  If the provided
+     * {@code AccessControlContext} is {@code null},
+     * this method instantiates a new {@code AccessControlContext}
+     * with an empty collection of ProtectionDomains.
+     *
+     * <p>
+     *
+     * @param subject the {@code Subject} that the specified
+     *                  {@code action} will run as.  This parameter
+     *                  may be {@code null}. <p>
+     *
+     * @param <T> the type of the value returned by the
+     *                  PrivilegedExceptionAction's {@code run} method.
+     *
+     * @param action the code to be run as the specified
+     *                  {@code Subject}. <p>
+     *
+     * @param acc the {@code AccessControlContext} to be tied to the
+     *                  specified <i>subject</i> and <i>action</i>. <p>
+     *
+     * @return the value returned by the
+     *                  PrivilegedExceptionAction's {@code run} method.
+     *
+     * @exception PrivilegedActionException if the
+     *                  {@code PrivilegedExceptionAction.run}
+     *                  method throws a checked exception. <p>
+     *
+     * @exception NullPointerException if the specified
+     *                  {@code PrivilegedExceptionAction} is
+     *                  {@code null}. <p>
+     *
+     * @exception SecurityException if the caller does not have permission
+     *                  to invoke this method.
+     */
+    public static <T> T doAsPrivileged(final Subject subject,
+                        final java.security.PrivilegedExceptionAction<T> action,
+                        final java.security.AccessControlContext acc)
+                        throws java.security.PrivilegedActionException {
+
+        java.lang.SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(AuthPermissionHolder.DO_AS_PRIVILEGED_PERMISSION);
+        }
+
+        if (action == null)
+            throw new NullPointerException
+                (ResourcesMgr.getString("invalid.null.action.provided"));
+
+        // set up the new Subject-based AccessControlContext for doPrivileged
+        final AccessControlContext callerAcc =
+                (acc == null ?
+                new AccessControlContext(NULL_PD_ARRAY) :
+                acc);
+
+        // call doPrivileged and push this new context on the stack
+        return java.security.AccessController.doPrivileged
+                                        (action,
+                                        createContext(subject, callerAcc));
+    }
+
+    private static AccessControlContext createContext(final Subject subject,
+                                        final AccessControlContext acc) {
+
+
+        return java.security.AccessController.doPrivileged
+            (new java.security.PrivilegedAction<AccessControlContext>() {
+            public AccessControlContext run() {
+                if (subject == null)
+                    return new AccessControlContext(acc, null);
+                else
+                    return new AccessControlContext
+                                        (acc,
+                                        new SubjectDomainCombiner(subject));
+            }
+        });
+    }
+
+    /**
+     * Return the {@code Set} of Principals associated with this
+     * {@code Subject}.  Each {@code Principal} represents
+     * an identity for this {@code Subject}.
+     *
+     * <p> The returned {@code Set} is backed by this Subject's
+     * internal {@code Principal} {@code Set}.  Any modification
+     * to the returned {@code Set} affects the internal
+     * {@code Principal} {@code Set} as well.
+     *
+     * <p>
+     *
+     * @return  The {@code Set} of Principals associated with this
+     *          {@code Subject}.
+     */
+    public Set<Principal> getPrincipals() {
+
+        // always return an empty Set instead of null
+        // so LoginModules can add to the Set if necessary
+        return principals;
+    }
+
+    /**
+     * Return a {@code Set} of Principals associated with this
+     * {@code Subject} that are instances or subclasses of the specified
+     * {@code Class}.
+     *
+     * <p> The returned {@code Set} is not backed by this Subject's
+     * internal {@code Principal} {@code Set}.  A new
+     * {@code Set} is created and returned for each method invocation.
+     * Modifications to the returned {@code Set}
+     * will not affect the internal {@code Principal} {@code Set}.
+     *
+     * <p>
+     *
+     * @param <T> the type of the class modeled by {@code c}
+     *
+     * @param c the returned {@code Set} of Principals will all be
+     *          instances of this class.
+     *
+     * @return a {@code Set} of Principals that are instances of the
+     *          specified {@code Class}.
+     *
+     * @exception NullPointerException if the specified {@code Class}
+     *                  is {@code null}.
+     */
+    public <T extends Principal> Set<T> getPrincipals(Class<T> c) {
+
+        if (c == null)
+            throw new NullPointerException
+                (ResourcesMgr.getString("invalid.null.Class.provided"));
+
+        // always return an empty Set instead of null
+        // so LoginModules can add to the Set if necessary
+        return new ClassSet<T>(PRINCIPAL_SET, c);
+    }
+
+    /**
+     * Return the {@code Set} of public credentials held by this
+     * {@code Subject}.
+     *
+     * <p> The returned {@code Set} is backed by this Subject's
+     * internal public Credential {@code Set}.  Any modification
+     * to the returned {@code Set} affects the internal public
+     * Credential {@code Set} as well.
+     *
+     * <p>
+     *
+     * @return  A {@code Set} of public credentials held by this
+     *          {@code Subject}.
+     */
+    public Set<Object> getPublicCredentials() {
+
+        // always return an empty Set instead of null
+        // so LoginModules can add to the Set if necessary
+        return pubCredentials;
+    }
+
+    /**
+     * Return the {@code Set} of private credentials held by this
+     * {@code Subject}.
+     *
+     * <p> The returned {@code Set} is backed by this Subject's
+     * internal private Credential {@code Set}.  Any modification
+     * to the returned {@code Set} affects the internal private
+     * Credential {@code Set} as well.
+     *
+     * <p> A caller requires permissions to access the Credentials
+     * in the returned {@code Set}, or to modify the
+     * {@code Set} itself.  A {@code SecurityException}
+     * is thrown if the caller does not have the proper permissions.
+     *
+     * <p> While iterating through the {@code Set},
+     * a {@code SecurityException} is thrown
+     * if the caller does not have permission to access a
+     * particular Credential.  The {@code Iterator}
+     * is nevertheless advanced to next element in the {@code Set}.
+     *
+     * <p>
+     *
+     * @return  A {@code Set} of private credentials held by this
+     *          {@code Subject}.
+     */
+    public Set<Object> getPrivateCredentials() {
+
+        // XXX
+        // we do not need a security check for
+        // AuthPermission(getPrivateCredentials)
+        // because we already restrict access to private credentials
+        // via the PrivateCredentialPermission.  all the extra AuthPermission
+        // would do is protect the set operations themselves
+        // (like size()), which don't seem security-sensitive.
+
+        // always return an empty Set instead of null
+        // so LoginModules can add to the Set if necessary
+        return privCredentials;
+    }
+
+    /**
+     * Return a {@code Set} of public credentials associated with this
+     * {@code Subject} that are instances or subclasses of the specified
+     * {@code Class}.
+     *
+     * <p> The returned {@code Set} is not backed by this Subject's
+     * internal public Credential {@code Set}.  A new
+     * {@code Set} is created and returned for each method invocation.
+     * Modifications to the returned {@code Set}
+     * will not affect the internal public Credential {@code Set}.
+     *
+     * <p>
+     *
+     * @param <T> the type of the class modeled by {@code c}
+     *
+     * @param c the returned {@code Set} of public credentials will all be
+     *          instances of this class.
+     *
+     * @return a {@code Set} of public credentials that are instances
+     *          of the  specified {@code Class}.
+     *
+     * @exception NullPointerException if the specified {@code Class}
+     *          is {@code null}.
+     */
+    public <T> Set<T> getPublicCredentials(Class<T> c) {
+
+        if (c == null)
+            throw new NullPointerException
+                (ResourcesMgr.getString("invalid.null.Class.provided"));
+
+        // always return an empty Set instead of null
+        // so LoginModules can add to the Set if necessary
+        return new ClassSet<T>(PUB_CREDENTIAL_SET, c);
+    }
+
+    /**
+     * Return a {@code Set} of private credentials associated with this
+     * {@code Subject} that are instances or subclasses of the specified
+     * {@code Class}.
+     *
+     * <p> The caller must have permission to access all of the
+     * requested Credentials, or a {@code SecurityException}
+     * will be thrown.
+     *
+     * <p> The returned {@code Set} is not backed by this Subject's
+     * internal private Credential {@code Set}.  A new
+     * {@code Set} is created and returned for each method invocation.
+     * Modifications to the returned {@code Set}
+     * will not affect the internal private Credential {@code Set}.
+     *
+     * <p>
+     *
+     * @param <T> the type of the class modeled by {@code c}
+     *
+     * @param c the returned {@code Set} of private credentials will all be
+     *          instances of this class.
+     *
+     * @return a {@code Set} of private credentials that are instances
+     *          of the  specified {@code Class}.
+     *
+     * @exception NullPointerException if the specified {@code Class}
+     *          is {@code null}.
+     */
+    public <T> Set<T> getPrivateCredentials(Class<T> c) {
+
+        // XXX
+        // we do not need a security check for
+        // AuthPermission(getPrivateCredentials)
+        // because we already restrict access to private credentials
+        // via the PrivateCredentialPermission.  all the extra AuthPermission
+        // would do is protect the set operations themselves
+        // (like size()), which don't seem security-sensitive.
+
+        if (c == null)
+            throw new NullPointerException
+                (ResourcesMgr.getString("invalid.null.Class.provided"));
+
+        // always return an empty Set instead of null
+        // so LoginModules can add to the Set if necessary
+        return new ClassSet<T>(PRIV_CREDENTIAL_SET, c);
+    }
+
+    /**
+     * Compares the specified Object with this {@code Subject}
+     * for equality.  Returns true if the given object is also a Subject
+     * and the two {@code Subject} instances are equivalent.
+     * More formally, two {@code Subject} instances are
+     * equal if their {@code Principal} and {@code Credential}
+     * Sets are equal.
+     *
+     * <p>
+     *
+     * @param o Object to be compared for equality with this
+     *          {@code Subject}.
+     *
+     * @return true if the specified Object is equal to this
+     *          {@code Subject}.
+     *
+     * @exception SecurityException if the caller does not have permission
+     *          to access the private credentials for this {@code Subject},
+     *          or if the caller does not have permission to access the
+     *          private credentials for the provided {@code Subject}.
+     */
+    public boolean equals(Object o) {
+
+        if (o == null)
+            return false;
+
+        if (this == o)
+            return true;
+
+        if (o instanceof Subject) {
+
+            final Subject that = (Subject)o;
+
+            // check the principal and credential sets
+            Set<Principal> thatPrincipals;
+            synchronized(that.principals) {
+                // avoid deadlock from dual locks
+                thatPrincipals = new HashSet<Principal>(that.principals);
+            }
+            if (!principals.equals(thatPrincipals)) {
+                return false;
+            }
+
+            Set<Object> thatPubCredentials;
+            synchronized(that.pubCredentials) {
+                // avoid deadlock from dual locks
+                thatPubCredentials = new HashSet<Object>(that.pubCredentials);
+            }
+            if (!pubCredentials.equals(thatPubCredentials)) {
+                return false;
+            }
+
+            Set<Object> thatPrivCredentials;
+            synchronized(that.privCredentials) {
+                // avoid deadlock from dual locks
+                thatPrivCredentials = new HashSet<Object>(that.privCredentials);
+            }
+            if (!privCredentials.equals(thatPrivCredentials)) {
+                return false;
+            }
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Return the String representation of this {@code Subject}.
+     *
+     * <p>
+     *
+     * @return the String representation of this {@code Subject}.
+     */
+    public String toString() {
+        return toString(true);
+    }
+
+    /**
+     * package private convenience method to print out the Subject
+     * without firing off a security check when trying to access
+     * the Private Credentials
+     */
+    String toString(boolean includePrivateCredentials) {
+
+        String s = ResourcesMgr.getString("Subject.");
+        String suffix = "";
+
+        synchronized(principals) {
+            Iterator<Principal> pI = principals.iterator();
+            while (pI.hasNext()) {
+                Principal p = pI.next();
+                suffix = suffix + ResourcesMgr.getString(".Principal.") +
+                        p.toString() + ResourcesMgr.getString("NEWLINE");
+            }
+        }
+
+        synchronized(pubCredentials) {
+            Iterator<Object> pI = pubCredentials.iterator();
+            while (pI.hasNext()) {
+                Object o = pI.next();
+                suffix = suffix +
+                        ResourcesMgr.getString(".Public.Credential.") +
+                        o.toString() + ResourcesMgr.getString("NEWLINE");
+            }
+        }
+
+        if (includePrivateCredentials) {
+            synchronized(privCredentials) {
+                Iterator<Object> pI = privCredentials.iterator();
+                while (pI.hasNext()) {
+                    try {
+                        Object o = pI.next();
+                        suffix += ResourcesMgr.getString
+                                        (".Private.Credential.") +
+                                        o.toString() +
+                                        ResourcesMgr.getString("NEWLINE");
+                    } catch (SecurityException se) {
+                        suffix += ResourcesMgr.getString
+                                (".Private.Credential.inaccessible.");
+                        break;
+                    }
+                }
+            }
+        }
+        return s + suffix;
+    }
+
+    /**
+     * Returns a hashcode for this {@code Subject}.
+     *
+     * <p>
+     *
+     * @return a hashcode for this {@code Subject}.
+     *
+     * @exception SecurityException if the caller does not have permission
+     *          to access this Subject's private credentials.
+     */
+    public int hashCode() {
+
+        /**
+         * The hashcode is derived exclusive or-ing the
+         * hashcodes of this Subject's Principals and credentials.
+         *
+         * If a particular credential was destroyed
+         * ({@code credential.hashCode()} throws an
+         * {@code IllegalStateException}),
+         * the hashcode for that credential is derived via:
+         * {@code credential.getClass().toString().hashCode()}.
+         */
+
+        int hashCode = 0;
+
+        synchronized(principals) {
+            Iterator<Principal> pIterator = principals.iterator();
+            while (pIterator.hasNext()) {
+                Principal p = pIterator.next();
+                hashCode ^= p.hashCode();
+            }
+        }
+
+        synchronized(pubCredentials) {
+            Iterator<Object> pubCIterator = pubCredentials.iterator();
+            while (pubCIterator.hasNext()) {
+                hashCode ^= getCredHashCode(pubCIterator.next());
+            }
+        }
+        return hashCode;
+    }
+
+    /**
+     * get a credential's hashcode
+     */
+    private int getCredHashCode(Object o) {
+        try {
+            return o.hashCode();
+        } catch (IllegalStateException ise) {
+            return o.getClass().toString().hashCode();
+        }
+    }
+
+    /**
+     * Writes this object out to a stream (i.e., serializes it).
+     */
+    private void writeObject(java.io.ObjectOutputStream oos)
+                throws java.io.IOException {
+        synchronized(principals) {
+            oos.defaultWriteObject();
+        }
+    }
+
+    /**
+     * Reads this object from a stream (i.e., deserializes it)
+     */
+    @SuppressWarnings("unchecked")
+    private void readObject(java.io.ObjectInputStream s)
+                throws java.io.IOException, ClassNotFoundException {
+
+        ObjectInputStream.GetField gf = s.readFields();
+
+        readOnly = gf.get("readOnly", false);
+
+        Set<Principal> inputPrincs = (Set<Principal>)gf.get("principals", null);
+
+        // Rewrap the principals into a SecureSet
+        if (inputPrincs == null) {
+            throw new NullPointerException
+                (ResourcesMgr.getString("invalid.null.input.s."));
+        }
+        try {
+            principals = Collections.synchronizedSet(new SecureSet<Principal>
+                                (this, PRINCIPAL_SET, inputPrincs));
+        } catch (NullPointerException npe) {
+            // Sometimes people deserialize the principals set only.
+            // Subject is not accessible, so just don't fail.
+            principals = Collections.synchronizedSet
+                        (new SecureSet<Principal>(this, PRINCIPAL_SET));
+        }
+
+        // The Credential {@code Set} is not serialized, but we do not
+        // want the default deserialization routine to set it to null.
+        this.pubCredentials = Collections.synchronizedSet
+                        (new SecureSet<Object>(this, PUB_CREDENTIAL_SET));
+        this.privCredentials = Collections.synchronizedSet
+                        (new SecureSet<Object>(this, PRIV_CREDENTIAL_SET));
+    }
+
+    /**
+     * Prevent modifications unless caller has permission.
+     *
+     * @serial include
+     */
+    private static class SecureSet<E>
+        extends AbstractSet<E>
+        implements java.io.Serializable {
+
+        private static final long serialVersionUID = 7911754171111800359L;
+
+        /**
+         * @serialField this$0 Subject The outer Subject instance.
+         * @serialField elements LinkedList The elements in this set.
+         */
+        private static final ObjectStreamField[] serialPersistentFields = {
+            new ObjectStreamField("this$0", Subject.class),
+            new ObjectStreamField("elements", LinkedList.class),
+            new ObjectStreamField("which", int.class)
+        };
+
+        Subject subject;
+        LinkedList<E> elements;
+
+        /**
+         * @serial An integer identifying the type of objects contained
+         *      in this set.  If {@code which == 1},
+         *      this is a Principal set and all the elements are
+         *      of type {@code java.security.Principal}.
+         *      If {@code which == 2}, this is a public credential
+         *      set and all the elements are of type {@code Object}.
+         *      If {@code which == 3}, this is a private credential
+         *      set and all the elements are of type {@code Object}.
+         */
+        private int which;
+
+        SecureSet(Subject subject, int which) {
+            this.subject = subject;
+            this.which = which;
+            this.elements = new LinkedList<E>();
+        }
+
+        SecureSet(Subject subject, int which, Set<? extends E> set) {
+            this.subject = subject;
+            this.which = which;
+            this.elements = new LinkedList<E>(set);
+        }
+
+        public int size() {
+            return elements.size();
+        }
+
+        public Iterator<E> iterator() {
+            final LinkedList<E> list = elements;
+            return new Iterator<E>() {
+                ListIterator<E> i = list.listIterator(0);
+
+                public boolean hasNext() {return i.hasNext();}
+
+                public E next() {
+                    if (which != Subject.PRIV_CREDENTIAL_SET) {
+                        return i.next();
+                    }
+
+                    SecurityManager sm = System.getSecurityManager();
+                    if (sm != null) {
+                        try {
+                            sm.checkPermission(new PrivateCredentialPermission
+                                (list.get(i.nextIndex()).getClass().getName(),
+                                subject.getPrincipals()));
+                        } catch (SecurityException se) {
+                            i.next();
+                            throw (se);
+                        }
+                    }
+                    return i.next();
+                }
+
+                public void remove() {
+
+                    if (subject.isReadOnly()) {
+                        throw new IllegalStateException(ResourcesMgr.getString
+                                ("Subject.is.read.only"));
+                    }
+
+                    java.lang.SecurityManager sm = System.getSecurityManager();
+                    if (sm != null) {
+                        switch (which) {
+                        case Subject.PRINCIPAL_SET:
+                            sm.checkPermission(AuthPermissionHolder.MODIFY_PRINCIPALS_PERMISSION);
+                            break;
+                        case Subject.PUB_CREDENTIAL_SET:
+                            sm.checkPermission(AuthPermissionHolder.MODIFY_PUBLIC_CREDENTIALS_PERMISSION);
+                            break;
+                        default:
+                            sm.checkPermission(AuthPermissionHolder.MODIFY_PRIVATE_CREDENTIALS_PERMISSION);
+                            break;
+                        }
+                    }
+                    i.remove();
+                }
+            };
+        }
+
+        public boolean add(E o) {
+
+            if (subject.isReadOnly()) {
+                throw new IllegalStateException
+                        (ResourcesMgr.getString("Subject.is.read.only"));
+            }
+
+            java.lang.SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                switch (which) {
+                case Subject.PRINCIPAL_SET:
+                    sm.checkPermission(AuthPermissionHolder.MODIFY_PRINCIPALS_PERMISSION);
+                    break;
+                case Subject.PUB_CREDENTIAL_SET:
+                    sm.checkPermission(AuthPermissionHolder.MODIFY_PUBLIC_CREDENTIALS_PERMISSION);
+                    break;
+                default:
+                    sm.checkPermission(AuthPermissionHolder.MODIFY_PRIVATE_CREDENTIALS_PERMISSION);
+                    break;
+                }
+            }
+
+            switch (which) {
+            case Subject.PRINCIPAL_SET:
+                if (!(o instanceof Principal)) {
+                    throw new SecurityException(ResourcesMgr.getString
+                        ("attempting.to.add.an.object.which.is.not.an.instance.of.java.security.Principal.to.a.Subject.s.Principal.Set"));
+                }
+                break;
+            default:
+                // ok to add Objects of any kind to credential sets
+                break;
+            }
+
+            // check for duplicates
+            if (!elements.contains(o))
+                return elements.add(o);
+            else
+                return false;
+        }
+
+        public boolean remove(Object o) {
+
+            final Iterator<E> e = iterator();
+            while (e.hasNext()) {
+                E next;
+                if (which != Subject.PRIV_CREDENTIAL_SET) {
+                    next = e.next();
+                } else {
+                    next = java.security.AccessController.doPrivileged
+                        (new java.security.PrivilegedAction<E>() {
+                        public E run() {
+                            return e.next();
+                        }
+                    });
+                }
+
+                if (next == null) {
+                    if (o == null) {
+                        e.remove();
+                        return true;
+                    }
+                } else if (next.equals(o)) {
+                    e.remove();
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public boolean contains(Object o) {
+            final Iterator<E> e = iterator();
+            while (e.hasNext()) {
+                E next;
+                if (which != Subject.PRIV_CREDENTIAL_SET) {
+                    next = e.next();
+                } else {
+
+                    // For private credentials:
+                    // If the caller does not have read permission for
+                    // for o.getClass(), we throw a SecurityException.
+                    // Otherwise we check the private cred set to see whether
+                    // it contains the Object
+
+                    SecurityManager sm = System.getSecurityManager();
+                    if (sm != null) {
+                        sm.checkPermission(new PrivateCredentialPermission
+                                                (o.getClass().getName(),
+                                                subject.getPrincipals()));
+                    }
+                    next = java.security.AccessController.doPrivileged
+                        (new java.security.PrivilegedAction<E>() {
+                        public E run() {
+                            return e.next();
+                        }
+                    });
+                }
+
+                if (next == null) {
+                    if (o == null) {
+                        return true;
+                    }
+                } else if (next.equals(o)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public boolean removeAll(Collection<?> c) {
+            Objects.requireNonNull(c);
+            boolean modified = false;
+            final Iterator<E> e = iterator();
+            while (e.hasNext()) {
+                E next;
+                if (which != Subject.PRIV_CREDENTIAL_SET) {
+                    next = e.next();
+                } else {
+                    next = java.security.AccessController.doPrivileged
+                        (new java.security.PrivilegedAction<E>() {
+                        public E run() {
+                            return e.next();
+                        }
+                    });
+                }
+
+                Iterator<?> ce = c.iterator();
+                while (ce.hasNext()) {
+                    Object o = ce.next();
+                    if (next == null) {
+                        if (o == null) {
+                            e.remove();
+                            modified = true;
+                            break;
+                        }
+                    } else if (next.equals(o)) {
+                        e.remove();
+                        modified = true;
+                        break;
+                    }
+                }
+            }
+            return modified;
+        }
+
+        public boolean retainAll(Collection<?> c) {
+            Objects.requireNonNull(c);
+            boolean modified = false;
+            boolean retain = false;
+            final Iterator<E> e = iterator();
+            while (e.hasNext()) {
+                retain = false;
+                E next;
+                if (which != Subject.PRIV_CREDENTIAL_SET) {
+                    next = e.next();
+                } else {
+                    next = java.security.AccessController.doPrivileged
+                        (new java.security.PrivilegedAction<E>() {
+                        public E run() {
+                            return e.next();
+                        }
+                    });
+                }
+
+                Iterator<?> ce = c.iterator();
+                while (ce.hasNext()) {
+                    Object o = ce.next();
+                    if (next == null) {
+                        if (o == null) {
+                            retain = true;
+                            break;
+                        }
+                    } else if (next.equals(o)) {
+                        retain = true;
+                        break;
+                    }
+                }
+
+                if (!retain) {
+                    e.remove();
+                    retain = false;
+                    modified = true;
+                }
+            }
+            return modified;
+        }
+
+        public void clear() {
+            final Iterator<E> e = iterator();
+            while (e.hasNext()) {
+                E next;
+                if (which != Subject.PRIV_CREDENTIAL_SET) {
+                    next = e.next();
+                } else {
+                    next = java.security.AccessController.doPrivileged
+                        (new java.security.PrivilegedAction<E>() {
+                        public E run() {
+                            return e.next();
+                        }
+                    });
+                }
+                e.remove();
+            }
+        }
+
+        /**
+         * Writes this object out to a stream (i.e., serializes it).
+         *
+         * <p>
+         *
+         * @serialData If this is a private credential set,
+         *      a security check is performed to ensure that
+         *      the caller has permission to access each credential
+         *      in the set.  If the security check passes,
+         *      the set is serialized.
+         */
+        private void writeObject(java.io.ObjectOutputStream oos)
+                throws java.io.IOException {
+
+            if (which == Subject.PRIV_CREDENTIAL_SET) {
+                // check permissions before serializing
+                Iterator<E> i = iterator();
+                while (i.hasNext()) {
+                    i.next();
+                }
+            }
+            ObjectOutputStream.PutField fields = oos.putFields();
+            fields.put("this$0", subject);
+            fields.put("elements", elements);
+            fields.put("which", which);
+            oos.writeFields();
+        }
+
+        @SuppressWarnings("unchecked")
+        private void readObject(ObjectInputStream ois)
+            throws IOException, ClassNotFoundException
+        {
+            ObjectInputStream.GetField fields = ois.readFields();
+            subject = (Subject) fields.get("this$0", null);
+            which = fields.get("which", 0);
+
+            LinkedList<E> tmp = (LinkedList<E>) fields.get("elements", null);
+            if (tmp.getClass() != LinkedList.class) {
+                elements = new LinkedList<E>(tmp);
+            } else {
+                elements = tmp;
+            }
+        }
+    }
+
+    /**
+     * This class implements a {@code Set} which returns only
+     * members that are an instance of a specified Class.
+     */
+    private class ClassSet<T> extends AbstractSet<T> {
+
+        private int which;
+        private Class<T> c;
+        private Set<T> set;
+
+        ClassSet(int which, Class<T> c) {
+            this.which = which;
+            this.c = c;
+            set = new HashSet<T>();
+
+            switch (which) {
+            case Subject.PRINCIPAL_SET:
+                synchronized(principals) { populateSet(); }
+                break;
+            case Subject.PUB_CREDENTIAL_SET:
+                synchronized(pubCredentials) { populateSet(); }
+                break;
+            default:
+                synchronized(privCredentials) { populateSet(); }
+                break;
+            }
+        }
+
+        @SuppressWarnings("unchecked")     /*To suppress warning from line 1374*/
+        private void populateSet() {
+            final Iterator<?> iterator;
+            switch(which) {
+            case Subject.PRINCIPAL_SET:
+                iterator = Subject.this.principals.iterator();
+                break;
+            case Subject.PUB_CREDENTIAL_SET:
+                iterator = Subject.this.pubCredentials.iterator();
+                break;
+            default:
+                iterator = Subject.this.privCredentials.iterator();
+                break;
+            }
+
+            // Check whether the caller has permisson to get
+            // credentials of Class c
+
+            while (iterator.hasNext()) {
+                Object next;
+                if (which == Subject.PRIV_CREDENTIAL_SET) {
+                    next = java.security.AccessController.doPrivileged
+                        (new java.security.PrivilegedAction<Object>() {
+                        public Object run() {
+                            return iterator.next();
+                        }
+                    });
+                } else {
+                    next = iterator.next();
+                }
+                if (c.isAssignableFrom(next.getClass())) {
+                    if (which != Subject.PRIV_CREDENTIAL_SET) {
+                        set.add((T)next);
+                    } else {
+                        // Check permission for private creds
+                        SecurityManager sm = System.getSecurityManager();
+                        if (sm != null) {
+                            sm.checkPermission(new PrivateCredentialPermission
+                                                (next.getClass().getName(),
+                                                Subject.this.getPrincipals()));
+                        }
+                        set.add((T)next);
+                    }
+                }
+            }
+        }
+
+        public int size() {
+            return set.size();
+        }
+
+        public Iterator<T> iterator() {
+            return set.iterator();
+        }
+
+        public boolean add(T o) {
+
+            if (!o.getClass().isAssignableFrom(c)) {
+                MessageFormat form = new MessageFormat(ResourcesMgr.getString
+                        ("attempting.to.add.an.object.which.is.not.an.instance.of.class"));
+                Object[] source = {c.toString()};
+                throw new SecurityException(form.format(source));
+            }
+
+            return set.add(o);
+        }
+    }
+
+    static class AuthPermissionHolder {
+        static final AuthPermission DO_AS_PERMISSION =
+            new AuthPermission("doAs");
+
+        static final AuthPermission DO_AS_PRIVILEGED_PERMISSION =
+            new AuthPermission("doAsPrivileged");
+
+        static final AuthPermission SET_READ_ONLY_PERMISSION =
+            new AuthPermission("setReadOnly");
+
+        static final AuthPermission GET_SUBJECT_PERMISSION =
+            new AuthPermission("getSubject");
+
+        static final AuthPermission MODIFY_PRINCIPALS_PERMISSION =
+            new AuthPermission("modifyPrincipals");
+
+        static final AuthPermission MODIFY_PUBLIC_CREDENTIALS_PERMISSION =
+            new AuthPermission("modifyPublicCredentials");
+
+        static final AuthPermission MODIFY_PRIVATE_CREDENTIALS_PERMISSION =
+            new AuthPermission("modifyPrivateCredentials");
+    }
+}
diff --git a/javax/security/auth/SubjectDomainCombiner.java b/javax/security/auth/SubjectDomainCombiner.java
new file mode 100644
index 0000000..868ed5f
--- /dev/null
+++ b/javax/security/auth/SubjectDomainCombiner.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 1999, 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 javax.security.auth;
+
+import java.security.ProtectionDomain;
+
+// 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 SubjectDomainCombiner implements java.security.DomainCombiner {
+
+    public SubjectDomainCombiner(Subject subject) { }
+
+    public Subject getSubject() { return null; }
+
+    public ProtectionDomain[] combine(ProtectionDomain[] currentDomains,
+                                ProtectionDomain[] assignedDomains) { return null; }
+}
diff --git a/javax/security/auth/callback/Callback.java b/javax/security/auth/callback/Callback.java
new file mode 100644
index 0000000..d95c87f
--- /dev/null
+++ b/javax/security/auth/callback/Callback.java
@@ -0,0 +1,53 @@
+/*
+ * 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 javax.security.auth.callback;
+
+// Android-changed: Removed @see tags (targets do not exist on Android):
+// @see javax.security.auth.callback.ChoiceCallback
+// @see javax.security.auth.callback.ConfirmationCallback
+// @see javax.security.auth.callback.LanguageCallback
+// @see javax.security.auth.callback.NameCallback
+// @see javax.security.auth.callback.TextInputCallback
+// @see javax.security.auth.callback.TextOutputCallback
+/**
+ * <p> Implementations of this interface are passed to a
+ * {@code CallbackHandler}, allowing underlying security services
+ * the ability to interact with a calling application to retrieve specific
+ * authentication data such as usernames and passwords, or to display
+ * certain information, such as error and warning messages.
+ *
+ * <p> {@code Callback} implementations do not retrieve or
+ * display the information requested by underlying security services.
+ * {@code Callback} implementations simply provide the means
+ * to pass such requests to applications, and for applications,
+ * if appropriate, to return requested information back to the
+ * underlying security services.
+ *
+ * @see javax.security.auth.callback.CallbackHandler
+ * @see javax.security.auth.callback.PasswordCallback
+ */
+public interface Callback { }
diff --git a/javax/security/auth/callback/CallbackHandler.java b/javax/security/auth/callback/CallbackHandler.java
new file mode 100644
index 0000000..af02496
--- /dev/null
+++ b/javax/security/auth/callback/CallbackHandler.java
@@ -0,0 +1,150 @@
+/*
+ * 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 javax.security.auth.callback;
+
+/**
+ * <p> An application implements a {@code CallbackHandler} and passes
+ * it to underlying security services so that they may interact with
+ * the application to retrieve specific authentication data,
+ * such as usernames and passwords, or to display certain information,
+ * such as error and warning messages.
+ *
+ * <p> CallbackHandlers are implemented in an application-dependent fashion.
+ * For example, implementations for an application with a graphical user
+ * interface (GUI) may pop up windows to prompt for requested information
+ * or to display error messages.  An implementation may also choose to obtain
+ * requested information from an alternate source without asking the end user.
+ *
+ * <p> Underlying security services make requests for different types
+ * of information by passing individual Callbacks to the
+ * {@code CallbackHandler}.  The {@code CallbackHandler}
+ * implementation decides how to retrieve and display information
+ * depending on the Callbacks passed to it.  For example,
+ * if the underlying service needs a username and password to
+ * authenticate a user, it uses a {@code NameCallback} and
+ * {@code PasswordCallback}.  The {@code CallbackHandler}
+ * can then choose to prompt for a username and password serially,
+ * or to prompt for both in a single window.
+ *
+ * <p> A default {@code CallbackHandler} class implementation
+ * may be specified by setting the value of the
+ * {@code auth.login.defaultCallbackHandler} security property.
+ *
+ * <p> If the security property is set to the fully qualified name of a
+ * {@code CallbackHandler} implementation class,
+ * then a {@code LoginContext} will load the specified
+ * {@code CallbackHandler} and pass it to the underlying LoginModules.
+ * The {@code LoginContext} only loads the default handler
+ * if it was not provided one.
+ *
+ * <p> All default handler implementations must provide a public
+ * zero-argument constructor.
+ *
+ * @see java.security.Security security properties
+ */
+public interface CallbackHandler {
+
+    /**
+     * <p> Retrieve or display the information requested in the
+     * provided Callbacks.
+     *
+     * <p> The {@code handle} method implementation checks the
+     * instance(s) of the {@code Callback} object(s) passed in
+     * to retrieve or display the requested information.
+     * The following example is provided to help demonstrate what an
+     * {@code handle} method implementation might look like.
+     * This example code is for guidance only.  Many details,
+     * including proper error handling, are left out for simplicity.
+     *
+     * <pre>{@code
+     * public void handle(Callback[] callbacks)
+     * throws IOException, UnsupportedCallbackException {
+     *
+     *   for (int i = 0; i < callbacks.length; i++) {
+     *      if (callbacks[i] instanceof TextOutputCallback) {
+     *
+     *          // display the message according to the specified type
+     *          TextOutputCallback toc = (TextOutputCallback)callbacks[i];
+     *          switch (toc.getMessageType()) {
+     *          case TextOutputCallback.INFORMATION:
+     *              System.out.println(toc.getMessage());
+     *              break;
+     *          case TextOutputCallback.ERROR:
+     *              System.out.println("ERROR: " + toc.getMessage());
+     *              break;
+     *          case TextOutputCallback.WARNING:
+     *              System.out.println("WARNING: " + toc.getMessage());
+     *              break;
+     *          default:
+     *              throw new IOException("Unsupported message type: " +
+     *                                  toc.getMessageType());
+     *          }
+     *
+     *      } else if (callbacks[i] instanceof NameCallback) {
+     *
+     *          // prompt the user for a username
+     *          NameCallback nc = (NameCallback)callbacks[i];
+     *
+     *          // ignore the provided defaultName
+     *          System.err.print(nc.getPrompt());
+     *          System.err.flush();
+     *          nc.setName((new BufferedReader
+     *                  (new InputStreamReader(System.in))).readLine());
+     *
+     *      } else if (callbacks[i] instanceof PasswordCallback) {
+     *
+     *          // prompt the user for sensitive information
+     *          PasswordCallback pc = (PasswordCallback)callbacks[i];
+     *          System.err.print(pc.getPrompt());
+     *          System.err.flush();
+     *          pc.setPassword(readPassword(System.in));
+     *
+     *      } else {
+     *          throw new UnsupportedCallbackException
+     *                  (callbacks[i], "Unrecognized Callback");
+     *      }
+     *   }
+     * }
+     *
+     * // Reads user password from given input stream.
+     * private char[] readPassword(InputStream in) throws IOException {
+     *    // insert code to read a user password from the input stream
+     * }
+     * }</pre>
+     *
+     * @param callbacks an array of {@code Callback} objects provided
+     *          by an underlying security service which contains
+     *          the information requested to be retrieved or displayed.
+     *
+     * @exception java.io.IOException if an input or output error occurs. <p>
+     *
+     * @exception UnsupportedCallbackException if the implementation of this
+     *          method does not support one or more of the Callbacks
+     *          specified in the {@code callbacks} parameter.
+     */
+    void handle(Callback[] callbacks)
+    throws java.io.IOException, UnsupportedCallbackException;
+}
diff --git a/javax/security/auth/callback/PasswordCallback.java b/javax/security/auth/callback/PasswordCallback.java
new file mode 100644
index 0000000..0e8fb7b
--- /dev/null
+++ b/javax/security/auth/callback/PasswordCallback.java
@@ -0,0 +1,142 @@
+/*
+ * 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 javax.security.auth.callback;
+
+/**
+ * <p> Underlying security services instantiate and pass a
+ * {@code PasswordCallback} to the {@code handle}
+ * method of a {@code CallbackHandler} to retrieve password information.
+ *
+ * @see javax.security.auth.callback.CallbackHandler
+ */
+public class PasswordCallback implements Callback, java.io.Serializable {
+
+    private static final long serialVersionUID = 2267422647454909926L;
+
+    /**
+     * @serial
+     * @since 1.4
+     */
+    private String prompt;
+    /**
+     * @serial
+     * @since 1.4
+     */
+    private boolean echoOn;
+    /**
+     * @serial
+     * @since 1.4
+     */
+    private char[] inputPassword;
+
+    /**
+     * Construct a {@code PasswordCallback} with a prompt
+     * and a boolean specifying whether the password should be displayed
+     * as it is being typed.
+     *
+     * <p>
+     *
+     * @param prompt the prompt used to request the password. <p>
+     *
+     * @param echoOn true if the password should be displayed
+     *                  as it is being typed.
+     *
+     * @exception IllegalArgumentException if {@code prompt} is null or
+     *                  if {@code prompt} has a length of 0.
+     */
+    public PasswordCallback(String prompt, boolean echoOn) {
+        if (prompt == null || prompt.length() == 0)
+            throw new IllegalArgumentException();
+
+        this.prompt = prompt;
+        this.echoOn = echoOn;
+    }
+
+    /**
+     * Get the prompt.
+     *
+     * <p>
+     *
+     * @return the prompt.
+     */
+    public String getPrompt() {
+        return prompt;
+    }
+
+    /**
+     * Return whether the password
+     * should be displayed as it is being typed.
+     *
+     * <p>
+     *
+     * @return the whether the password
+     *          should be displayed as it is being typed.
+     */
+    public boolean isEchoOn() {
+        return echoOn;
+    }
+
+    /**
+     * Set the retrieved password.
+     *
+     * <p> This method makes a copy of the input <i>password</i>
+     * before storing it.
+     *
+     * <p>
+     *
+     * @param password the retrieved password, which may be null.
+     *
+     * @see #getPassword
+     */
+    public void setPassword(char[] password) {
+        this.inputPassword = (password == null ? null : password.clone());
+    }
+
+    /**
+     * Get the retrieved password.
+     *
+     * <p> This method returns a copy of the retrieved password.
+     *
+     * <p>
+     *
+     * @return the retrieved password, which may be null.
+     *
+     * @see #setPassword
+     */
+    public char[] getPassword() {
+        return (inputPassword == null ? null : inputPassword.clone());
+    }
+
+    /**
+     * Clear the retrieved password.
+     */
+    public void clearPassword() {
+        if (inputPassword != null) {
+            for (int i = 0; i < inputPassword.length; i++)
+                inputPassword[i] = ' ';
+        }
+    }
+}
diff --git a/javax/security/auth/callback/UnsupportedCallbackException.java b/javax/security/auth/callback/UnsupportedCallbackException.java
new file mode 100644
index 0000000..0a9fa51
--- /dev/null
+++ b/javax/security/auth/callback/UnsupportedCallbackException.java
@@ -0,0 +1,81 @@
+/*
+ * 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 javax.security.auth.callback;
+
+/**
+ * Signals that a {@code CallbackHandler} does not
+ * recognize a particular {@code Callback}.
+ *
+ */
+public class UnsupportedCallbackException extends Exception {
+
+    private static final long serialVersionUID = -6873556327655666839L;
+
+    /**
+     * @serial
+     */
+    private Callback callback;
+
+    /**
+     * Constructs a {@code UnsupportedCallbackException}
+     * with no detail message.
+     *
+     * <p>
+     *
+     * @param callback the unrecognized {@code Callback}.
+     */
+    public UnsupportedCallbackException(Callback callback) {
+        super();
+        this.callback = callback;
+    }
+
+    /**
+     * Constructs a UnsupportedCallbackException with the specified detail
+     * message.  A detail message is a String that describes this particular
+     * exception.
+     *
+     * <p>
+     *
+     * @param callback the unrecognized {@code Callback}. <p>
+     *
+     * @param msg the detail message.
+     */
+    public UnsupportedCallbackException(Callback callback, String msg) {
+        super(msg);
+        this.callback = callback;
+    }
+
+    /**
+     * Get the unrecognized {@code Callback}.
+     *
+     * <p>
+     *
+     * @return the unrecognized {@code Callback}.
+     */
+    public Callback getCallback() {
+        return callback;
+    }
+}
diff --git a/javax/security/auth/callback/package-info.java b/javax/security/auth/callback/package-info.java
new file mode 100644
index 0000000..4cd5daf
--- /dev/null
+++ b/javax/security/auth/callback/package-info.java
@@ -0,0 +1,35 @@
+/*
+ * 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 package provides the classes necessary for services
+ * to interact with applications in order to retrieve
+ * information (authentication data including usernames
+ * or passwords, for example) or to display information
+ * (error and warning messages, for example).
+ *
+ * @since JDK1.4
+ */
+package javax.security.auth.callback;
diff --git a/javax/security/auth/login/LoginException.java b/javax/security/auth/login/LoginException.java
new file mode 100644
index 0000000..c8fa8cb
--- /dev/null
+++ b/javax/security/auth/login/LoginException.java
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+package javax.security.auth.login;
+
+// Android-changed: Removed @see tag (target does not exist on Android):
+// @see javax.security.auth.login.LoginContext
+/**
+ * This is the basic login exception.
+ */
+
+public class LoginException extends java.security.GeneralSecurityException {
+
+    private static final long serialVersionUID = -4679091624035232488L;
+
+    /**
+     * Constructs a LoginException with no detail message. A detail
+     * message is a String that describes this particular exception.
+     */
+    public LoginException() {
+        super();
+    }
+
+    /**
+     * Constructs a LoginException with the specified detail message.
+     * A detail message is a String that describes this particular
+     * exception.
+     *
+     * <p>
+     *
+     * @param msg the detail message.
+     */
+    public LoginException(String msg) {
+        super(msg);
+    }
+}
diff --git a/javax/security/auth/login/package-info.java b/javax/security/auth/login/package-info.java
new file mode 100644
index 0000000..5b43480
--- /dev/null
+++ b/javax/security/auth/login/package-info.java
@@ -0,0 +1,39 @@
+/*
+ * 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 package provides a pluggable authentication framework.
+ * <h2>Package Specification</h2>
+ *
+ * <ul>
+ *   <li><a href="{@docRoot}/../technotes/guides/security/StandardNames.html">
+ *     <b>Java&trade;
+ *     Cryptography Architecture Standard Algorithm Name
+ *     Documentation</b></a></li>
+ * </ul>
+ *
+ * @since 1.4
+ */
+package javax.security.auth.login;
diff --git a/javax/security/auth/package-info.java b/javax/security/auth/package-info.java
new file mode 100644
index 0000000..b4ac082
--- /dev/null
+++ b/javax/security/auth/package-info.java
@@ -0,0 +1,38 @@
+/*
+ * 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 package provides a framework for authentication and
+ * authorization. The framework allows
+ * authentication to be performed in pluggable fashion. Different
+ * authentication modules can be plugged under an application without
+ * requiring modifications to the application itself. The
+ * authorization component allows specification of access controls
+ * based on code location, code signers and code executors
+ * (Subjects).
+ *
+ * @since JDK1.4
+ */
+package javax.security.auth;
diff --git a/javax/security/auth/x500/X500Principal.java b/javax/security/auth/x500/X500Principal.java
new file mode 100644
index 0000000..77292b0
--- /dev/null
+++ b/javax/security/auth/x500/X500Principal.java
@@ -0,0 +1,513 @@
+/*
+ * 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 javax.security.auth.x500;
+
+import java.io.*;
+import java.security.Principal;
+import java.util.Collections;
+import java.util.Map;
+import sun.security.x509.X500Name;
+import sun.security.util.*;
+
+/**
+ * <p> This class represents an X.500 {@code Principal}.
+ * {@code X500Principal}s are represented by distinguished names such as
+ * "CN=Duke, OU=JavaSoft, O=Sun Microsystems, C=US".
+ *
+ * <p> This class can be instantiated by using a string representation
+ * of the distinguished name, or by using the ASN.1 DER encoded byte
+ * representation of the distinguished name.  The current specification
+ * for the string representation of a distinguished name is defined in
+ * <a href="http://www.ietf.org/rfc/rfc2253.txt">RFC 2253: Lightweight
+ * Directory Access Protocol (v3): UTF-8 String Representation of
+ * Distinguished Names</a>. This class, however, accepts string formats from
+ * both RFC 2253 and <a href="http://www.ietf.org/rfc/rfc1779.txt">RFC 1779:
+ * A String Representation of Distinguished Names</a>, and also recognizes
+ * attribute type keywords whose OIDs (Object Identifiers) are defined 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 string representation for this {@code X500Principal}
+ * can be obtained by calling the {@code getName} methods.
+ *
+ * <p> Note that the {@code getSubjectX500Principal} and
+ * {@code getIssuerX500Principal} methods of
+ * {@code X509Certificate} return X500Principals representing the
+ * issuer and subject fields of the certificate.
+ *
+ * @see java.security.cert.X509Certificate
+ * @since 1.4
+ */
+public final class X500Principal implements Principal, java.io.Serializable {
+
+    private static final long serialVersionUID = -500463348111345721L;
+
+    /**
+     * RFC 1779 String format of Distinguished Names.
+     */
+    public static final String RFC1779 = "RFC1779";
+    /**
+     * RFC 2253 String format of Distinguished Names.
+     */
+    public static final String RFC2253 = "RFC2253";
+    /**
+     * Canonical String format of Distinguished Names.
+     */
+    public static final String CANONICAL = "CANONICAL";
+
+    /**
+     * The X500Name representing this principal.
+     *
+     * NOTE: this field is reflectively accessed from within X500Name.
+     */
+    private transient X500Name thisX500Name;
+
+    /**
+     * Creates an X500Principal by wrapping an X500Name.
+     *
+     * NOTE: The constructor is package private. It is intended to be accessed
+     * using privileged reflection from classes in sun.security.*.
+     * Currently referenced from sun.security.x509.X500Name.asX500Principal().
+     */
+    X500Principal(X500Name x500Name) {
+        thisX500Name = x500Name;
+    }
+
+    /**
+     * Creates an {@code X500Principal} from a string representation of
+     * an X.500 distinguished name (ex:
+     * "CN=Duke, OU=JavaSoft, O=Sun Microsystems, C=US").
+     * The distinguished name must be specified using the grammar defined in
+     * RFC 1779 or RFC 2253 (either format is acceptable).
+     *
+     * <p>This constructor recognizes the attribute type keywords
+     * defined in RFC 1779 and RFC 2253
+     * (and listed in {@link #getName(String format) getName(String format)}),
+     * as well as the T, DNQ or DNQUALIFIER, SURNAME, GIVENNAME, INITIALS,
+     * GENERATION, EMAILADDRESS, and SERIALNUMBER keywords whose Object
+     * Identifiers (OIDs) are defined in RFC 3280 and its successor.
+     * Any other attribute type must be specified as an OID.
+     *
+     * <p>This implementation enforces a more restrictive OID syntax than
+     * defined in RFC 1779 and 2253. It uses the more correct syntax defined in
+     * <a href="http://www.ietf.org/rfc/rfc4512.txt">RFC 4512</a>, which
+     * specifies that OIDs contain at least 2 digits:
+     *
+     * <p>{@code numericoid = number 1*( DOT number ) }
+     *
+     * @param name an X.500 distinguished name in RFC 1779 or RFC 2253 format
+     * @exception NullPointerException if the {@code name}
+     *                  is {@code null}
+     * @exception IllegalArgumentException if the {@code name}
+     *                  is improperly specified
+     */
+    public X500Principal(String name) {
+        this(name, Collections.<String, String>emptyMap());
+    }
+
+    /**
+     * Creates an {@code X500Principal} from a string representation of
+     * an X.500 distinguished name (ex:
+     * "CN=Duke, OU=JavaSoft, O=Sun Microsystems, C=US").
+     * The distinguished name must be specified using the grammar defined in
+     * RFC 1779 or RFC 2253 (either format is acceptable).
+     *
+     * <p> This constructor recognizes the attribute type keywords specified
+     * in {@link #X500Principal(String)} and also recognizes additional
+     * keywords that have entries in the {@code keywordMap} parameter.
+     * Keyword entries in the keywordMap take precedence over the default
+     * keywords recognized by {@code X500Principal(String)}. Keywords
+     * MUST be specified in all upper-case, otherwise they will be ignored.
+     * Improperly specified keywords are ignored; however if a keyword in the
+     * name maps to an improperly specified Object Identifier (OID), an
+     * {@code IllegalArgumentException} is thrown. It is permissible to
+     * have 2 different keywords that map to the same OID.
+     *
+     * <p>This implementation enforces a more restrictive OID syntax than
+     * defined in RFC 1779 and 2253. It uses the more correct syntax defined in
+     * <a href="http://www.ietf.org/rfc/rfc4512.txt">RFC 4512</a>, which
+     * specifies that OIDs contain at least 2 digits:
+     *
+     * <p>{@code numericoid = number 1*( DOT number ) }
+     *
+     * @param name an X.500 distinguished name in RFC 1779 or RFC 2253 format
+     * @param keywordMap an attribute type keyword map, where each key is a
+     *   keyword String that maps to a corresponding object identifier in String
+     *   form (a sequence of nonnegative integers separated by periods). The map
+     *   may be empty but never {@code null}.
+     * @exception NullPointerException if {@code name} or
+     *   {@code keywordMap} is {@code null}
+     * @exception IllegalArgumentException if the {@code name} is
+     *   improperly specified or a keyword in the {@code name} maps to an
+     *   OID that is not in the correct form
+     * @since 1.6
+     */
+    public X500Principal(String name, Map<String, String> keywordMap) {
+        if (name == null) {
+            throw new NullPointerException
+                (sun.security.util.ResourcesMgr.getString
+                ("provided.null.name"));
+        }
+        if (keywordMap == null) {
+            throw new NullPointerException
+                (sun.security.util.ResourcesMgr.getString
+                ("provided.null.keyword.map"));
+        }
+
+        try {
+            thisX500Name = new X500Name(name, keywordMap);
+        } catch (Exception e) {
+            IllegalArgumentException iae = new IllegalArgumentException
+                        ("improperly specified input name: " + name);
+            iae.initCause(e);
+            throw iae;
+        }
+    }
+
+    /**
+     * Creates an {@code X500Principal} from a distinguished name in
+     * ASN.1 DER encoded form. 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>
+     *
+     * @param name a byte array containing the distinguished name in ASN.1
+     * DER encoded form
+     * @throws IllegalArgumentException if an encoding error occurs
+     *          (incorrect form for DN)
+     */
+    public X500Principal(byte[] name) {
+        try {
+            thisX500Name = new X500Name(name);
+        } catch (Exception e) {
+            IllegalArgumentException iae = new IllegalArgumentException
+                        ("improperly specified input name");
+            iae.initCause(e);
+            throw iae;
+        }
+    }
+
+    /**
+     * Creates an {@code X500Principal} from an {@code InputStream}
+     * containing the distinguished name in ASN.1 DER encoded form.
+     * The ASN.1 notation for this structure is supplied in the
+     * documentation for
+     * {@link #X500Principal(byte[] name) X500Principal(byte[] name)}.
+     *
+     * <p> The read position of the input stream is positioned
+     * to the next available byte after the encoded distinguished name.
+     *
+     * @param is an {@code InputStream} containing the distinguished
+     *          name in ASN.1 DER encoded form
+     *
+     * @exception NullPointerException if the {@code InputStream}
+     *          is {@code null}
+     * @exception IllegalArgumentException if an encoding error occurs
+     *          (incorrect form for DN)
+     */
+    public X500Principal(InputStream is) {
+        if (is == null) {
+            throw new NullPointerException("provided null input stream");
+        }
+
+        try {
+            if (is.markSupported())
+                is.mark(is.available() + 1);
+            DerValue der = new DerValue(is);
+            thisX500Name = new X500Name(der.data);
+        } catch (Exception e) {
+            if (is.markSupported()) {
+                try {
+                    is.reset();
+                } catch (IOException ioe) {
+                    IllegalArgumentException iae = new IllegalArgumentException
+                        ("improperly specified input stream " +
+                        ("and unable to reset input stream"));
+                    iae.initCause(e);
+                    throw iae;
+                }
+            }
+            IllegalArgumentException iae = new IllegalArgumentException
+                        ("improperly specified input stream");
+            iae.initCause(e);
+            throw iae;
+        }
+    }
+
+    /**
+     * Returns a string representation of the X.500 distinguished name using
+     * the format defined in RFC 2253.
+     *
+     * <p>This method is equivalent to calling
+     * {@code getName(X500Principal.RFC2253)}.
+     *
+     * @return the distinguished name of this {@code X500Principal}
+     */
+    public String getName() {
+        return getName(X500Principal.RFC2253);
+    }
+
+    /**
+     * Returns a string representation of the X.500 distinguished name
+     * using the specified format. Valid values for the format are
+     * "RFC1779", "RFC2253", and "CANONICAL" (case insensitive).
+     *
+     * <p> If "RFC1779" is specified as the format,
+     * this method emits the attribute type keywords defined in
+     * RFC 1779 (CN, L, ST, O, OU, C, STREET).
+     * Any other attribute type is emitted as an OID.
+     *
+     * <p> If "RFC2253" is specified as the format,
+     * this method emits the attribute type keywords defined in
+     * RFC 2253 (CN, L, ST, O, OU, C, STREET, DC, UID).
+     * Any other attribute type is emitted as an OID.
+     * Under a strict reading, RFC 2253 only specifies a UTF-8 string
+     * representation. The String returned by this method is the
+     * Unicode string achieved by decoding this UTF-8 representation.
+     *
+     * <p> If "CANONICAL" is specified as the format,
+     * this method returns an RFC 2253 conformant string representation
+     * with the following additional canonicalizations:
+     *
+     * <ol>
+     * <li> Leading zeros are removed from attribute types
+     *          that are encoded as dotted decimal OIDs
+     * <li> DirectoryString attribute values of type
+     *          PrintableString and UTF8String are not
+     *          output in hexadecimal format
+     * <li> DirectoryString attribute values of types
+     *          other than PrintableString and UTF8String
+     *          are output in hexadecimal format
+     * <li> Leading and trailing white space characters
+     *          are removed from non-hexadecimal attribute values
+     *          (unless the value consists entirely of white space characters)
+     * <li> Internal substrings of one or more white space characters are
+     *          converted to a single space in non-hexadecimal
+     *          attribute values
+     * <li> Relative Distinguished Names containing more than one
+     *          Attribute Value Assertion (AVA) are output in the
+     *          following order: an alphabetical ordering of AVAs
+     *          containing standard keywords, followed by a numeric
+     *          ordering of AVAs containing OID keywords.
+     * <li> The only characters in attribute values that are escaped are
+     *          those which section 2.4 of RFC 2253 states must be escaped
+     *          (they are escaped using a preceding backslash character)
+     * <li> The entire name is converted to upper case
+     *          using {@code String.toUpperCase(Locale.US)}
+     * <li> The entire name is converted to lower case
+     *          using {@code String.toLowerCase(Locale.US)}
+     * <li> The name is finally normalized using normalization form KD,
+     *          as described in the Unicode Standard and UAX #15
+     * </ol>
+     *
+     * <p> Additional standard formats may be introduced in the future.
+     *
+     * @param format the format to use
+     *
+     * @return a string representation of this {@code X500Principal}
+     *          using the specified format
+     * @throws IllegalArgumentException if the specified format is invalid
+     *          or null
+     */
+    public String getName(String format) {
+        if (format != null) {
+            if (format.equalsIgnoreCase(RFC1779)) {
+                return thisX500Name.getRFC1779Name();
+            } else if (format.equalsIgnoreCase(RFC2253)) {
+                return thisX500Name.getRFC2253Name();
+            } else if (format.equalsIgnoreCase(CANONICAL)) {
+                return thisX500Name.getRFC2253CanonicalName();
+            }
+        }
+        throw new IllegalArgumentException("invalid format specified");
+    }
+
+    /**
+     * Returns a string representation of the X.500 distinguished name
+     * using the specified format. Valid values for the format are
+     * "RFC1779" and "RFC2253" (case insensitive). "CANONICAL" is not
+     * permitted and an {@code IllegalArgumentException} will be thrown.
+     *
+     * <p>This method returns Strings in the format as specified in
+     * {@link #getName(String)} and also emits additional attribute type
+     * keywords for OIDs that have entries in the {@code oidMap}
+     * parameter. OID entries in the oidMap take precedence over the default
+     * OIDs recognized by {@code getName(String)}.
+     * Improperly specified OIDs are ignored; however if an OID
+     * in the name maps to an improperly specified keyword, an
+     * {@code IllegalArgumentException} is thrown.
+     *
+     * <p> Additional standard formats may be introduced in the future.
+     *
+     * <p> Warning: additional attribute type keywords may not be recognized
+     * by other implementations; therefore do not use this method if
+     * you are unsure if these keywords will be recognized by other
+     * implementations.
+     *
+     * @param format the format to use
+     * @param oidMap an OID map, where each key is an object identifier in
+     *  String form (a sequence of nonnegative integers separated by periods)
+     *  that maps to a corresponding attribute type keyword String.
+     *  The map may be empty but never {@code null}.
+     * @return a string representation of this {@code X500Principal}
+     *          using the specified format
+     * @throws IllegalArgumentException if the specified format is invalid,
+     *  null, or an OID in the name maps to an improperly specified keyword
+     * @throws NullPointerException if {@code oidMap} is {@code null}
+     * @since 1.6
+     */
+    public String getName(String format, Map<String, String> oidMap) {
+        if (oidMap == null) {
+            throw new NullPointerException
+                (sun.security.util.ResourcesMgr.getString
+                ("provided.null.OID.map"));
+        }
+        if (format != null) {
+            if (format.equalsIgnoreCase(RFC1779)) {
+                return thisX500Name.getRFC1779Name(oidMap);
+            } else if (format.equalsIgnoreCase(RFC2253)) {
+                return thisX500Name.getRFC2253Name(oidMap);
+            }
+        }
+        throw new IllegalArgumentException("invalid format specified");
+    }
+
+    /**
+     * Returns the distinguished name in ASN.1 DER encoded form. The ASN.1
+     * notation for this structure is supplied in the documentation for
+     * {@link #X500Principal(byte[] name) X500Principal(byte[] name)}.
+     *
+     * <p>Note that the byte array returned is cloned to protect against
+     * subsequent modifications.
+     *
+     * @return a byte array containing the distinguished name in ASN.1 DER
+     * encoded form
+     */
+    public byte[] getEncoded() {
+        try {
+            return thisX500Name.getEncoded();
+        } catch (IOException e) {
+            throw new RuntimeException("unable to get encoding", e);
+        }
+    }
+
+    /**
+     * Return a user-friendly string representation of this
+     * {@code X500Principal}.
+     *
+     * @return a string representation of this {@code X500Principal}
+     */
+    public String toString() {
+        return thisX500Name.toString();
+    }
+
+    /**
+     * Compares the specified {@code Object} with this
+     * {@code X500Principal} for equality.
+     *
+     * <p> Specifically, this method returns {@code true} if
+     * the {@code Object} <i>o</i> is an {@code X500Principal}
+     * and if the respective canonical string representations
+     * (obtained via the {@code getName(X500Principal.CANONICAL)} method)
+     * of this object and <i>o</i> are equal.
+     *
+     * <p> This implementation is compliant with the requirements of RFC 3280.
+     *
+     * @param o Object to be compared for equality with this
+     *          {@code X500Principal}
+     *
+     * @return {@code true} if the specified {@code Object} is equal
+     *          to this {@code X500Principal}, {@code false} otherwise
+     */
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o instanceof X500Principal == false) {
+            return false;
+        }
+        X500Principal other = (X500Principal)o;
+        return this.thisX500Name.equals(other.thisX500Name);
+    }
+
+    /**
+     * Return a hash code for this {@code X500Principal}.
+     *
+     * <p> The hash code is calculated via:
+     * {@code getName(X500Principal.CANONICAL).hashCode()}
+     *
+     * @return a hash code for this {@code X500Principal}
+     */
+    public int hashCode() {
+        return thisX500Name.hashCode();
+    }
+
+    /**
+     * Save the X500Principal object to a stream.
+     *
+     * @serialData this {@code X500Principal} is serialized
+     *          by writing out its DER-encoded form
+     *          (the value of {@code getEncoded} is serialized).
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws IOException {
+        s.writeObject(thisX500Name.getEncodedInternal());
+    }
+
+    /**
+     * Reads this object from a stream (i.e., deserializes it).
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException,
+               java.io.NotActiveException,
+               ClassNotFoundException {
+
+        // re-create thisX500Name
+        thisX500Name = new X500Name((byte[])s.readObject());
+    }
+}
diff --git a/javax/security/auth/x500/package-info.java b/javax/security/auth/x500/package-info.java
new file mode 100644
index 0000000..12f8a53
--- /dev/null
+++ b/javax/security/auth/x500/package-info.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.
+ */
+
+/**
+ * This package contains the classes that should be used to store
+ * X500 Principal and X500 Private Credentials in a
+ * <i>Subject</i>.
+ *
+ * <h2>Package Specification</h2>
+ *
+ * <ul>
+ *   <li><a href="http://www.ietf.org/rfc/rfc1779.txt">
+ *     RFC 1779: A String Representation of Distinguished Names</a></li>
+ *   <li><a href="http://www.ietf.org/rfc/rfc2253.txt">
+ *     RFC 2253: Lightweight Directory Access Protocol (v3):
+ *     UTF-8 String Representation of Distinguished Names</a></li>
+ *   <li><a href="http://www.ietf.org/rfc/rfc3280.txt">
+ *     RFC 3280: Internet X.509 Public Key Infrastructure
+ *     Certificate and Certificate Revocation List (CRL) Profile</a></li>
+ *   <li><a href="http://www.ietf.org/rfc/rfc4512.txt">
+ *     RFC 4512: Lightweight Directory Access Protocol (LDAP):
+ *     Directory Information Models</a></li>
+ * </ul>
+ *
+ * @since JDK1.4
+ */
+package javax.security.auth.x500;
diff --git a/javax/security/cert/Certificate.java b/javax/security/cert/Certificate.java
new file mode 100644
index 0000000..10fd767
--- /dev/null
+++ b/javax/security/cert/Certificate.java
@@ -0,0 +1,177 @@
+/*
+ * 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 javax.security.cert;
+
+import java.security.PublicKey;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.InvalidKeyException;
+import java.security.SignatureException;
+
+/**
+ * <p>Abstract class 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>
+ * 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.
+ *
+ * <p><em>Note: The classes in the package {@code javax.security.cert}
+ * exist for compatibility with earlier versions of the
+ * Java Secure Sockets Extension (JSSE). New applications should instead
+ * use the standard Java SE certificate classes located in
+ * {@code java.security.cert}.</em></p>
+ *
+ * @since 1.4
+ * @see X509Certificate
+ *
+ * @author Hemma Prafullchandra
+ */
+public abstract class Certificate {
+
+    /**
+     * 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 if 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 = this.getEncoded();
+            byte[] otherCert = ((Certificate)other).getEncoded();
+
+            if (thisCert.length != otherCert.length)
+                return false;
+            for (int i = 0; i < thisCert.length; i++)
+                 if (thisCert[i] != otherCert[i])
+                     return false;
+            return true;
+        } catch (CertificateException e) {
+            return false;
+        }
+    }
+
+    /**
+     * Returns a hashcode value for this certificate from its
+     * encoded form.
+     *
+     * @return the hashcode value.
+     */
+    public int hashCode() {
+        int     retval = 0;
+        try {
+            byte[] certData = this.getEncoded();
+            for (int i = 1; i < certData.length; i++) {
+                 retval += certData[i] * i;
+            }
+            return (retval);
+        } catch (CertificateException e) {
+            return (retval);
+        }
+    }
+
+    /**
+     * 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 encoded form of this certificate
+     * @exception CertificateEncodingException on internal certificate
+     *            encoding failure
+     */
+    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;
+
+    /**
+     * 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();
+}
diff --git a/javax/security/cert/CertificateEncodingException.java b/javax/security/cert/CertificateEncodingException.java
new file mode 100644
index 0000000..1496c75
--- /dev/null
+++ b/javax/security/cert/CertificateEncodingException.java
@@ -0,0 +1,64 @@
+/*
+ * 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 javax.security.cert;
+
+/**
+ * Certificate Encoding Exception. This is thrown whenever an error
+ * occurs whilst attempting to encode a certificate.
+ *
+ * <p><em>Note: The classes in the package {@code javax.security.cert}
+ * exist for compatibility with earlier versions of the
+ * Java Secure Sockets Extension (JSSE). New applications should instead
+ * use the standard Java SE certificate classes located in
+ * {@code java.security.cert}.</em></p>
+ *
+ * @since 1.4
+ * @author Hemma Prafullchandra
+ */
+public class CertificateEncodingException extends CertificateException {
+
+    private static final long serialVersionUID = -8187642723048403470L;
+    /**
+     * 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);
+    }
+}
diff --git a/javax/security/cert/CertificateException.java b/javax/security/cert/CertificateException.java
new file mode 100644
index 0000000..68ee679
--- /dev/null
+++ b/javax/security/cert/CertificateException.java
@@ -0,0 +1,63 @@
+/*
+ * 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 javax.security.cert;
+
+/**
+ * This exception indicates one of a variety of certificate problems.
+ *
+ * <p><em>Note: The classes in the package {@code javax.security.cert}
+ * exist for compatibility with earlier versions of the
+ * Java Secure Sockets Extension (JSSE). New applications should instead
+ * use the standard Java SE certificate classes located in
+ * {@code java.security.cert}.</em></p>
+ *
+ * @author Hemma Prafullchandra
+ * @since 1.4
+ * @see Certificate
+ */
+public class CertificateException extends Exception {
+
+    private static final long serialVersionUID = -5757213374030785290L;
+    /**
+     * 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);
+    }
+}
diff --git a/javax/security/cert/CertificateExpiredException.java b/javax/security/cert/CertificateExpiredException.java
new file mode 100644
index 0000000..7e4579f
--- /dev/null
+++ b/javax/security/cert/CertificateExpiredException.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 javax.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.
+ *
+ * <p><em>Note: The classes in the package {@code javax.security.cert}
+ * exist for compatibility with earlier versions of the
+ * Java Secure Sockets Extension (JSSE). New applications should instead
+ * use the standard Java SE certificate classes located in
+ * {@code java.security.cert}.</em></p>
+ *
+ * @since 1.4
+ * @author Hemma Prafullchandra
+ */
+public class CertificateExpiredException extends CertificateException {
+
+    private static final long serialVersionUID = 5091601212177261883L;
+    /**
+     * 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/javax/security/cert/CertificateNotYetValidException.java b/javax/security/cert/CertificateNotYetValidException.java
new file mode 100644
index 0000000..9a53daa
--- /dev/null
+++ b/javax/security/cert/CertificateNotYetValidException.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 javax.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.
+ *
+ * <p><em>Note: The classes in the package {@code javax.security.cert}
+ * exist for compatibility with earlier versions of the
+ * Java Secure Sockets Extension (JSSE). New applications should instead
+ * use the standard Java SE certificate classes located in
+ * {@code java.security.cert}.</em></p>
+ *
+ * @since 1.4
+ * @author Hemma Prafullchandra
+ */
+public class CertificateNotYetValidException extends CertificateException {
+
+    private static final long serialVersionUID = -8976172474266822818L;
+    /**
+     * 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/javax/security/cert/CertificateParsingException.java b/javax/security/cert/CertificateParsingException.java
new file mode 100644
index 0000000..4378587
--- /dev/null
+++ b/javax/security/cert/CertificateParsingException.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 javax.security.cert;
+
+/**
+ * Certificate Parsing Exception. This is thrown whenever
+ * invalid DER encoded certificate is parsed or unsupported DER features
+ * are found in the Certificate.
+ *
+ * <p><em>Note: The classes in the package {@code javax.security.cert}
+ * exist for compatibility with earlier versions of the
+ * Java Secure Sockets Extension (JSSE). New applications should instead
+ * use the standard Java SE certificate classes located in
+ * {@code java.security.cert}.</em></p>
+ *
+ * @since 1.4
+ * @author Hemma Prafullchandra
+ */
+public class CertificateParsingException extends CertificateException {
+
+    private static final long serialVersionUID = -8449352422951136229L;
+
+    /**
+     * 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);
+    }
+}
diff --git a/javax/security/cert/X509Certificate.java b/javax/security/cert/X509Certificate.java
new file mode 100644
index 0000000..eedd78f
--- /dev/null
+++ b/javax/security/cert/X509Certificate.java
@@ -0,0 +1,460 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * 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 javax.security.cert;
+
+import com.sun.security.cert.internal.x509.X509V1CertImpl;
+
+import java.io.InputStream;
+import java.lang.Class;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.security.Security;
+
+import java.math.BigInteger;
+import java.security.AccessController;
+import java.security.Principal;
+import java.security.PrivilegedAction;
+import java.security.PublicKey;
+import java.util.BitSet;
+import java.util.Date;
+
+/**
+ * Abstract class for X.509 v1 certificates. This provides a standard
+ * way to access all the version 1 attributes of an X.509 certificate.
+ * Attributes that are specific to X.509 v2 or v3 are not available
+ * through this interface. Future API evolution will provide full access to
+ * complete X.509 v3 attributes.
+ * <p>
+ * The basic X.509 format was defined by
+ * ISO/IEC and ANSI X9 and 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>
+ * 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,
+ *     }
+ * </pre>
+ * <p>
+ * Here is sample code to instantiate an X.509 certificate:
+ * <pre>
+ * InputStream inStream = new FileInputStream("fileName-of-cert");
+ * X509Certificate cert = X509Certificate.getInstance(inStream);
+ * inStream.close();
+ * </pre>
+ * OR
+ * <pre>
+ * byte[] certData = &lt;certificate read from a file, say&gt;
+ * X509Certificate cert = X509Certificate.getInstance(certData);
+ * </pre>
+ * <p>
+ * In either case, the code that instantiates an X.509 certificate
+ * consults the value of the {@code cert.provider.x509v1} security property
+ * to locate the actual implementation or instantiates a default implementation.
+ * <p>
+ * The {@code cert.provider.x509v1} property is set to a default
+ * implementation for X.509 such as:
+ * <pre>
+ * cert.provider.x509v1=com.sun.security.cert.internal.x509.X509V1CertImpl
+ * </pre>
+ * <p>
+ * The value of this {@code cert.provider.x509v1} property has to be
+ * changed to instantiate another implementation. If this security
+ * property is not set, a default implementation will be used.
+ * Currently, due to possible security restrictions on access to
+ * Security properties, this value is looked up and cached at class
+ * initialization time and will fallback on a default implementation if
+ * the Security property is not accessible.
+ *
+ * <p><em>Note: The classes in the package {@code javax.security.cert}
+ * exist for compatibility with earlier versions of the
+ * Java Secure Sockets Extension (JSSE). New applications should instead
+ * use the standard Java SE certificate classes located in
+ * {@code java.security.cert}.</em></p>
+ *
+ * @author Hemma Prafullchandra
+ * @since 1.4
+ * @see Certificate
+ * @see java.security.cert.X509Extension
+ * @see java.security.Security security properties
+ */
+public abstract class X509Certificate extends Certificate {
+
+    /*
+     * Constant to lookup in the Security properties file.
+     * In the Security properties file the default implementation
+     * for X.509 v3 is given as:
+     * <pre>
+     * cert.provider.x509v1=com.sun.security.cert.internal.x509.X509V1CertImpl
+     * </pre>
+     */
+    private static final String X509_PROVIDER = "cert.provider.x509v1";
+    private static String X509Provider;
+
+    // Android-added.
+    private static final String DEFAULT_X509_CERT_CLASS = X509V1CertImpl.class.getName();
+
+    static {
+        X509Provider = AccessController.doPrivileged(
+            new PrivilegedAction<String>() {
+                public String run() {
+                    return Security.getProperty(X509_PROVIDER);
+                }
+            }
+        );
+    }
+
+    /**
+     * Instantiates an X509Certificate object, and initializes it with
+     * the data read from the input stream {@code inStream}.
+     * The implementation (X509Certificate is an abstract class) is
+     * provided by the class specified as the value of the
+     * {@code cert.provider.x509v1} security property.
+     *
+     * <p>Note: Only one DER-encoded
+     * certificate is expected to be in the input stream.
+     * Also, all X509Certificate
+     * subclasses must provide a constructor of the form:
+     * <pre>{@code
+     * public <subClass>(InputStream inStream) ...
+     * }</pre>
+     *
+     * @param inStream an input stream with the data to be read to
+     *        initialize the certificate.
+     * @return an X509Certificate object initialized with the data
+     *         from the input stream.
+     * @exception CertificateException if a class initialization
+     *            or certificate parsing error occurs.
+     */
+    public static final X509Certificate getInstance(InputStream inStream)
+    throws CertificateException {
+        return getInst((Object)inStream);
+    }
+
+    /**
+     * Instantiates an X509Certificate object, and initializes it with
+     * the specified byte array.
+     * The implementation (X509Certificate is an abstract class) is
+     * provided by the class specified as the value of the
+     * {@code cert.provider.x509v1} security property.
+     *
+     * <p>Note: All X509Certificate
+     * subclasses must provide a constructor of the form:
+     * <pre>{@code
+     * public <subClass>(InputStream inStream) ...
+     * }</pre>
+     *
+     * @param certData a byte array containing the DER-encoded
+     *        certificate.
+     * @return an X509Certificate object initialized with the data
+     *         from {@code certData}.
+     * @exception CertificateException if a class initialization
+     *            or certificate parsing error occurs.
+     */
+    public static final X509Certificate getInstance(byte[] certData)
+    throws CertificateException {
+        return getInst((Object)certData);
+    }
+
+    private static final X509Certificate getInst(Object value)
+    throws CertificateException {
+        /*
+         * This turns out not to work for now. To run under JDK1.2 we would
+         * need to call beginPrivileged() but we can't do that and run
+         * under JDK1.1.
+         */
+        String className = X509Provider;
+        if (className == null || className.length() == 0) {
+            // shouldn't happen, but assume corrupted properties file
+            // provide access to sun implementation
+            //
+            // Android-changed.
+            className = DEFAULT_X509_CERT_CLASS;
+        }
+        try {
+            Class<?>[] params = null;
+            if (value instanceof InputStream) {
+                params = new Class<?>[] { InputStream.class };
+            } else if (value instanceof byte[]) {
+                params = new Class<?>[] { value.getClass() };
+            } else
+                throw new CertificateException("Unsupported argument type");
+            Class<?> certClass = Class.forName(className);
+
+            // get the appropriate constructor and instantiate it
+            Constructor<?> cons = certClass.getConstructor(params);
+
+            // get a new instance
+            Object obj = cons.newInstance(new Object[] {value});
+            return (X509Certificate)obj;
+
+        } catch (ClassNotFoundException e) {
+          throw new CertificateException("Could not find class: " + e);
+        } catch (IllegalAccessException e) {
+          throw new CertificateException("Could not access class: " + e);
+        } catch (InstantiationException e) {
+          throw new CertificateException("Problems instantiating: " + e);
+        } catch (InvocationTargetException e) {
+          throw new CertificateException("InvocationTargetException: "
+                                         + e.getTargetException());
+        } catch (NoSuchMethodException e) {
+          throw new CertificateException("Could not find class method: "
+                                          + e.getMessage());
+        }
+    }
+
+    /**
+     * 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 specified date is within the certificate's
+     * validity period. In other words, this determines whether the
+     * certificate would be valid at the specified 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 from the ASN.1 encoding, i.e. 0, 1 or 2.
+     */
+    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();
+
+    /**
+     * 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();
+
+    /**
+     * Gets the {@code subject} (subject distinguished name) value
+     * from the certificate.
+     * 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.
+     * @see #getIssuerDN()
+     */
+    public abstract Principal getSubjectDN();
+
+    /**
+     * 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 signature algorithm name for the certificate
+     * signature algorithm. An example is the string "SHA-1/DSA".
+     * 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 positive whole numbers separated
+     * by periods.
+     * For example, the string "1.2.840.10040.4.3" identifies the SHA-1
+     * with DSA signature algorithm, as per the PKIX part I.
+     *
+     * <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.
+     *
+     * <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/javax/security/cert/package-info.java b/javax/security/cert/package-info.java
new file mode 100644
index 0000000..c09a0ea
--- /dev/null
+++ b/javax/security/cert/package-info.java
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+/**
+ * Provides classes for public key certificates.
+ *
+ * These classes include a simplified version of the
+ * java.security.cert package.  These classes were developed
+ * as part of the Java Secure Socket
+ * Extension (JSSE).  When JSSE was added to the J2SE version 1.4, this
+ * package was added for backward-compatibility reasons only.
+ *
+ * New applications should not use this package, but rather
+ * java.security.cert.
+ *
+ * @since 1.4
+ */
+package javax.security.cert;
diff --git a/javax/sql/CommonDataSource.java b/javax/sql/CommonDataSource.java
new file mode 100644
index 0000000..25b4068
--- /dev/null
+++ b/javax/sql/CommonDataSource.java
@@ -0,0 +1,129 @@
+/*
+ * 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 javax.sql;
+
+import java.sql.SQLException;
+import java.io.PrintWriter;
+import java.sql.SQLFeatureNotSupportedException;
+import java.util.logging.Logger;
+
+/**
+ * Interface that defines the methods which are common between <code>DataSource</code>,
+ * <code>XADataSource</code> and <code>ConnectionPoolDataSource</code>.
+ *<p>
+ */
+public interface CommonDataSource {
+
+    /**
+     * <p>Retrieves the log writer for this <code>DataSource</code>
+     * object.
+     *
+     * <p>The log writer is a character output stream to which all logging
+     * and tracing messages for this data source will be
+     * printed.  This includes messages printed by the methods of this
+     * object, messages printed by methods of other objects manufactured
+     * by this object, and so on.  Messages printed to a data source
+     * specific log writer are not printed to the log writer associated
+     * with the <code>java.sql.DriverManager</code> class.  When a
+     * <code>DataSource</code> object is
+     * created, the log writer is initially null; in other words, the
+     * default is for logging to be disabled.
+     *
+     * @return the log writer for this data source or null if
+     *        logging is disabled
+     * @exception java.sql.SQLException if a database access error occurs
+     * @see #setLogWriter
+     * @since 1.4
+     */
+    java.io.PrintWriter getLogWriter() throws SQLException;
+
+    /**
+     * <p>Sets the log writer for this <code>DataSource</code>
+     * object to the given <code>java.io.PrintWriter</code> object.
+     *
+     * <p>The log writer is a character output stream to which all logging
+     * and tracing messages for this data source will be
+     * printed.  This includes messages printed by the methods of this
+     * object, messages printed by methods of other objects manufactured
+     * by this object, and so on.  Messages printed to a data source-
+     * specific log writer are not printed to the log writer associated
+     * with the <code>java.sql.DriverManager</code> class. When a
+     * <code>DataSource</code> object is created the log writer is
+     * initially null; in other words, the default is for logging to be
+     * disabled.
+     *
+     * @param out the new log writer; to disable logging, set to null
+     * @exception SQLException if a database access error occurs
+     * @see #getLogWriter
+     * @since 1.4
+     */
+    void setLogWriter(java.io.PrintWriter out) throws SQLException;
+
+    /**
+     * <p>Sets the maximum time in seconds that this data source will wait
+     * while attempting to connect to a database.  A value of zero
+     * specifies that the timeout is the default system timeout
+     * if there is one; otherwise, it specifies that there is no timeout.
+     * When a <code>DataSource</code> object is created, the login timeout is
+     * initially zero.
+     *
+     * @param seconds the data source login time limit
+     * @exception SQLException if a database access error occurs.
+     * @see #getLoginTimeout
+     * @since 1.4
+     */
+    void setLoginTimeout(int seconds) throws SQLException;
+
+    /**
+     * Gets the maximum time in seconds that this data source can wait
+     * while attempting to connect to a database.  A value of zero
+     * means that the timeout is the default system timeout
+     * if there is one; otherwise, it means that there is no timeout.
+     * When a <code>DataSource</code> object is created, the login timeout is
+     * initially zero.
+     *
+     * @return the data source login time limit
+     * @exception SQLException if a database access error occurs.
+     * @see #setLoginTimeout
+     * @since 1.4
+     */
+    int getLoginTimeout() throws SQLException;
+
+    //------------------------- JDBC 4.1 -----------------------------------
+
+    /**
+     * Return the parent Logger of all the Loggers used by this data source. This
+     * should be the Logger farthest from the root Logger that is
+     * still an ancestor of all of the Loggers used by this data source. Configuring
+     * this Logger will affect all of the log messages generated by the data source.
+     * In the worst case, this may be the root Logger.
+     *
+     * @return the parent Logger for this data source
+     * @throws SQLFeatureNotSupportedException if the data source does not use <code>java.util.logging<code>.
+     * @since 1.7
+     */
+    public Logger getParentLogger() throws SQLFeatureNotSupportedException;
+}
diff --git a/javax/sql/ConnectionEvent.java b/javax/sql/ConnectionEvent.java
new file mode 100644
index 0000000..4f7c01a
--- /dev/null
+++ b/javax/sql/ConnectionEvent.java
@@ -0,0 +1,95 @@
+/*
+ * 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 javax.sql;
+
+import java.sql.SQLException;
+
+/**
+ * <P>An <code>Event</code> object that provides information about the
+ * source of a connection-related event.  <code>ConnectionEvent</code>
+ * objects are generated when an application closes a pooled connection
+ * and when an error occurs.  The <code>ConnectionEvent</code> object
+ * contains two kinds of information:
+ * <UL>
+ *   <LI>The pooled connection closed by the application
+ *   <LI>In the case of an error event, the <code>SQLException</code>
+ *       about to be thrown to the application
+ * </UL>
+ *
+ * @since 1.4
+ */
+
+public class ConnectionEvent extends java.util.EventObject {
+
+  /**
+   * <P>Constructs a <code>ConnectionEvent</code> object initialized with
+   * the given <code>PooledConnection</code> object. <code>SQLException</code>
+   * defaults to <code>null</code>.
+   *
+   * @param con the pooled connection that is the source of the event
+   * @throws IllegalArgumentException if <code>con</code> is null.
+   */
+  public ConnectionEvent(PooledConnection con) {
+    super(con);
+  }
+
+  /**
+   * <P>Constructs a <code>ConnectionEvent</code> object initialized with
+   * the given <code>PooledConnection</code> object and
+   * <code>SQLException</code> object.
+   *
+   * @param con the pooled connection that is the source of the event
+   * @param ex the SQLException about to be thrown to the application
+   * @throws IllegalArgumentException if <code>con</code> is null.
+   */
+  public ConnectionEvent(PooledConnection con, SQLException ex) {
+    super(con);
+    this.ex = ex;
+  }
+
+  /**
+   * <P>Retrieves the <code>SQLException</code> for this
+   * <code>ConnectionEvent</code> object. May be <code>null</code>.
+   *
+   * @return the SQLException about to be thrown or <code>null</code>
+   */
+  public SQLException getSQLException() { return ex; }
+
+  /**
+   * The <code>SQLException</code> that the driver will throw to the
+   * application when an error occurs and the pooled connection is no
+   * longer usable.
+   * @serial
+   */
+  private SQLException ex = null;
+
+  /**
+   * Private serial version unique ID to ensure serialization
+   * compatibility.
+   */
+  static final long serialVersionUID = -4843217645290030002L;
+
+ }
diff --git a/javax/sql/ConnectionEventListener.java b/javax/sql/ConnectionEventListener.java
new file mode 100644
index 0000000..8cb871f
--- /dev/null
+++ b/javax/sql/ConnectionEventListener.java
@@ -0,0 +1,76 @@
+/*
+ * 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 javax.sql;
+
+/**
+ * <P>
+ * An object that registers to be notified of events generated by a
+ * <code>PooledConnection</code> object.
+ * <P>
+ * The <code>ConnectionEventListener</code> interface is implemented by a
+ * connection pooling component.  A connection pooling component will
+ * usually be provided by a JDBC driver vendor or another system software
+ * vendor.  A JDBC driver notifies a <code>ConnectionEventListener</code>
+ * object when an application is finished using a pooled connection with
+ * which the listener has registered.  The notification
+ * occurs after the application calls the method <code>close</code> on
+ * its representation of a <code>PooledConnection</code> object.  A
+ * <code>ConnectionEventListener</code> is also notified when a
+ * connection error occurs due to the fact that the <code>PooledConnection</code>
+ * is unfit for future use---the server has crashed, for example.
+ * The listener is notified by the JDBC driver just before the driver throws an
+ * <code>SQLException</code> to the application using the
+ * <code>PooledConnection</code> object.
+ *
+ * @since 1.4
+ */
+
+public interface ConnectionEventListener extends java.util.EventListener {
+
+  /**
+   * Notifies this <code>ConnectionEventListener</code> that
+   * the application has called the method <code>close</code> on its
+   * representation of a pooled connection.
+   *
+   * @param event an event object describing the source of
+   * the event
+   */
+  void connectionClosed(ConnectionEvent event);
+
+  /**
+   * Notifies this <code>ConnectionEventListener</code> that
+   * a fatal error has occurred and the pooled connection can
+   * no longer be used.  The driver makes this notification just
+   * before it throws the application the <code>SQLException</code>
+   * contained in the given <code>ConnectionEvent</code> object.
+   *
+   * @param event an event object describing the source of
+   * the event and containing the <code>SQLException</code> that the
+   * driver is about to throw
+   */
+  void connectionErrorOccurred(ConnectionEvent event);
+
+ }
diff --git a/javax/sql/ConnectionPoolDataSource.java b/javax/sql/ConnectionPoolDataSource.java
new file mode 100644
index 0000000..cdaa329
--- /dev/null
+++ b/javax/sql/ConnectionPoolDataSource.java
@@ -0,0 +1,73 @@
+/*
+ * 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 javax.sql;
+
+import java.sql.SQLException;
+
+
+/**
+ * A factory for <code>PooledConnection</code>
+ * objects.  An object that implements this interface will typically be
+ * registered with a naming service that is based on the
+ * Java<sup><font size=-2>TM</font></sup> Naming and Directory Interface
+ * (JNDI).
+ *
+ * @since 1.4
+ */
+
+public interface ConnectionPoolDataSource  extends CommonDataSource {
+
+  /**
+   * Attempts to establish a physical database connection that can
+   * be used as a pooled connection.
+   *
+   * @return  a <code>PooledConnection</code> object that is a physical
+   *         connection to the database that this
+   *         <code>ConnectionPoolDataSource</code> object represents
+   * @exception SQLException if a database access error occurs
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.4
+   */
+  PooledConnection getPooledConnection() throws SQLException;
+
+  /**
+   * Attempts to establish a physical database connection that can
+   * be used as a pooled connection.
+   *
+   * @param user the database user on whose behalf the connection is being made
+   * @param password the user's password
+   * @return  a <code>PooledConnection</code> object that is a physical
+   *         connection to the database that this
+   *         <code>ConnectionPoolDataSource</code> object represents
+   * @exception SQLException if a database access error occurs
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.4
+   */
+  PooledConnection getPooledConnection(String user, String password)
+    throws SQLException;
+ }
diff --git a/javax/sql/DataSource.java b/javax/sql/DataSource.java
new file mode 100644
index 0000000..81e5d98
--- /dev/null
+++ b/javax/sql/DataSource.java
@@ -0,0 +1,99 @@
+/*
+ * 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 javax.sql;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Wrapper;
+
+/**
+ * <p>A factory for connections to the physical data source that this
+ * <code>DataSource</code> object represents.  An alternative to the
+ * <code>DriverManager</code> facility, a <code>DataSource</code> object
+ * is the preferred means of getting a connection. An object that implements
+ * the <code>DataSource</code> interface will typically be
+ * registered with a naming service based on the
+ * Java<sup><font size=-2>TM</font></sup> Naming and Directory (JNDI) API.
+ * <P>
+ * The <code>DataSource</code> interface is implemented by a driver vendor.
+ * There are three types of implementations:
+ * <OL>
+ *   <LI>Basic implementation -- produces a standard <code>Connection</code>
+ *       object
+ *   <LI>Connection pooling implementation -- produces a <code>Connection</code>
+ *       object that will automatically participate in connection pooling.  This
+ *       implementation works with a middle-tier connection pooling manager.
+ *   <LI>Distributed transaction implementation -- produces a
+ *       <code>Connection</code> object that may be used for distributed
+ *       transactions and almost always participates in connection pooling.
+ *       This implementation works with a middle-tier
+ *       transaction manager and almost always with a connection
+ *       pooling manager.
+ * </OL>
+ * <P>
+ * A <code>DataSource</code> object has properties that can be modified
+ * when necessary.  For example, if the data source is moved to a different
+ * server, the property for the server can be changed.  The benefit is that
+ * because the data source's properties can be changed, any code accessing
+ * that data source does not need to be changed.
+ * <P>
+ * A driver that is accessed via a <code>DataSource</code> object does not
+ * register itself with the <code>DriverManager</code>.  Rather, a
+ * <code>DataSource</code> object is retrieved though a lookup operation
+ * and then used to create a <code>Connection</code> object.  With a basic
+ * implementation, the connection obtained through a <code>DataSource</code>
+ * object is identical to a connection obtained through the
+ * <code>DriverManager</code> facility.
+ *
+ * @since 1.4
+ */
+
+public interface DataSource  extends CommonDataSource,Wrapper {
+
+  /**
+   * <p>Attempts to establish a connection with the data source that
+   * this <code>DataSource</code> object represents.
+   *
+   * @return  a connection to the data source
+   * @exception SQLException if a database access error occurs
+   */
+  Connection getConnection() throws SQLException;
+
+  /**
+   * <p>Attempts to establish a connection with the data source that
+   * this <code>DataSource</code> object represents.
+   *
+   * @param username the database user on whose behalf the connection is
+   *  being made
+   * @param password the user's password
+   * @return  a connection to the data source
+   * @exception SQLException if a database access error occurs
+   * @since 1.4
+   */
+  Connection getConnection(String username, String password)
+    throws SQLException;
+
+}
diff --git a/javax/sql/PooledConnection.java b/javax/sql/PooledConnection.java
new file mode 100644
index 0000000..e5d9ec4
--- /dev/null
+++ b/javax/sql/PooledConnection.java
@@ -0,0 +1,178 @@
+/*
+ * 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 javax.sql;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+
+/**
+ * An object that provides hooks for connection pool management.
+ * A <code>PooledConnection</code> object
+ * represents a physical connection to a data source.  The connection
+ * can be recycled rather than being closed when an application is
+ * finished with it, thus reducing the number of connections that
+ * need to be made.
+ * <P>
+ * An application programmer does not use the <code>PooledConnection</code>
+ * interface directly; rather, it is used by a middle tier infrastructure
+ * that manages the pooling of connections.
+ * <P>
+ * When an application calls the method <code>DataSource.getConnection</code>,
+ * it gets back a <code>Connection</code> object.  If connection pooling is
+ * being done, that <code>Connection</code> object is actually a handle to
+ * a <code>PooledConnection</code> object, which is a physical connection.
+ * <P>
+ * The connection pool manager, typically the application server, maintains
+ * a pool of <code>PooledConnection</code> objects.  If there is a
+ * <code>PooledConnection</code> object available in the pool, the
+ * connection pool manager returns a <code>Connection</code> object that
+ * is a handle to that physical connection.
+ * If no <code>PooledConnection</code> object is available, the
+ * connection pool manager calls the <code>ConnectionPoolDataSource</code>
+ * method <code>getPoolConnection</code> to create a new physical connection.  The
+ *  JDBC driver implementing <code>ConnectionPoolDataSource</code> creates a
+ *  new <code>PooledConnection</code> object and returns a handle to it.
+ * <P>
+ * When an application closes a connection, it calls the <code>Connection</code>
+ * method <code>close</code>. When connection pooling is being done,
+ * the connection pool manager is notified because it has registered itself as
+ * a <code>ConnectionEventListener</code> object using the
+ * <code>ConnectionPool</code> method <code>addConnectionEventListener</code>.
+ * The connection pool manager deactivates the handle to
+ * the <code>PooledConnection</code> object and  returns the
+ * <code>PooledConnection</code> object to the pool of connections so that
+ * it can be used again.  Thus, when an application closes its connection,
+ * the underlying physical connection is recycled rather than being closed.
+ * <P>
+ * The physical connection is not closed until the connection pool manager
+ * calls the <code>PooledConnection</code> method <code>close</code>.
+ * This method is generally called to have an orderly shutdown of the server or
+ * if a fatal error has made the connection unusable.
+ *
+ * <p>
+ * A connection pool manager is often also a statement pool manager, maintining
+ *  a pool of <code>PreparedStatement</code> objects.
+ *  When an application closes a prepared statement, it calls the
+ *  <code>PreparedStatement</code>
+ * method <code>close</code>. When <code>Statement</code> pooling is being done,
+ * the pool manager is notified because it has registered itself as
+ * a <code>StatementEventListener</code> object using the
+ * <code>ConnectionPool</code> method <code>addStatementEventListener</code>.
+ *  Thus, when an application closes its  <code>PreparedStatement</code>,
+ * the underlying prepared statement is recycled rather than being closed.
+ * <P>
+ *
+ * @since 1.4
+ */
+
+public interface PooledConnection {
+
+  /**
+   * Creates and returns a <code>Connection</code> object that is a handle
+   * for the physical connection that
+   * this <code>PooledConnection</code> object represents.
+   * The connection pool manager calls this method when an application has
+   * called the method <code>DataSource.getConnection</code> and there are
+   * no <code>PooledConnection</code> objects available. See the
+   * {@link PooledConnection interface description} for more information.
+   *
+   * @return  a <code>Connection</code> object that is a handle to
+   *          this <code>PooledConnection</code> object
+   * @exception SQLException if a database access error occurs
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.4
+   */
+  Connection getConnection() throws SQLException;
+
+  /**
+   * Closes the physical connection that this <code>PooledConnection</code>
+   * object represents.  An application never calls this method directly;
+   * it is called by the connection pool module, or manager.
+   * <P>
+   * See the {@link PooledConnection interface description} for more
+   * information.
+   *
+   * @exception SQLException if a database access error occurs
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.4
+   */
+  void close() throws SQLException;
+
+  /**
+   * Registers the given event listener so that it will be notified
+   * when an event occurs on this <code>PooledConnection</code> object.
+   *
+   * @param listener a component, usually the connection pool manager,
+   *        that has implemented the
+   *        <code>ConnectionEventListener</code> interface and wants to be
+   *        notified when the connection is closed or has an error
+   * @see #removeConnectionEventListener
+   */
+  void addConnectionEventListener(ConnectionEventListener listener);
+
+  /**
+   * Removes the given event listener from the list of components that
+   * will be notified when an event occurs on this
+   * <code>PooledConnection</code> object.
+   *
+   * @param listener a component, usually the connection pool manager,
+   *        that has implemented the
+   *        <code>ConnectionEventListener</code> interface and
+   *        been registered with this <code>PooledConnection</code> object as
+   *        a listener
+   * @see #addConnectionEventListener
+   */
+  void removeConnectionEventListener(ConnectionEventListener listener);
+
+        /**
+         * Registers a <code>StatementEventListener</code> with this <code>PooledConnection</code> object.  Components that
+         * wish to be notified when  <code>PreparedStatement</code>s created by the
+         * connection are closed or are detected to be invalid may use this method
+         * to register a <code>StatementEventListener</code> with this <code>PooledConnection</code> object.
+         * <p>
+         * @param listener      an component which implements the <code>StatementEventListener</code>
+         *                                      interface that is to be registered with this <code>PooledConnection</code> object
+         * <p>
+         * @since 1.6
+         */
+        public void addStatementEventListener(StatementEventListener listener);
+
+        /**
+         * Removes the specified <code>StatementEventListener</code> from the list of
+         * components that will be notified when the driver detects that a
+         * <code>PreparedStatement</code> has been closed or is invalid.
+         * <p>
+         * @param listener      the component which implements the
+         *                                      <code>StatementEventListener</code> interface that was previously
+         *                                      registered with this <code>PooledConnection</code> object
+         * <p>
+         * @since 1.6
+         */
+        public void removeStatementEventListener(StatementEventListener listener);
+
+ }
diff --git a/javax/sql/RowSet.java b/javax/sql/RowSet.java
new file mode 100644
index 0000000..fd33529
--- /dev/null
+++ b/javax/sql/RowSet.java
@@ -0,0 +1,2186 @@
+/*
+ * 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 javax.sql;
+
+import java.sql.*;
+import java.io.*;
+import java.math.*;
+import java.util.*;
+
+/**
+ * The interface that adds support to the JDBC API for the
+ * JavaBeans<sup><font size=-2>TM</font></sup> component model.
+ * A rowset, which can be used as a JavaBeans component in
+ * a visual Bean development environment, can be created and
+ * configured at design time and executed at run time.
+ * <P>
+ * The <code>RowSet</code>
+ * interface provides a set of JavaBeans properties that allow a <code>RowSet</code>
+ * instance to be configured to connect to a JDBC data source and read
+ * some data from the data source.  A group of setter methods (<code>setInt</code>,
+ * <code>setBytes</code>, <code>setString</code>, and so on)
+ * provide a way to pass input parameters to a rowset's command property.
+ * This command is the SQL query the rowset uses when it gets its data from
+ * a relational database, which is generally the case.
+ * <P>
+ * The <code>RowSet</code>
+ * interface supports JavaBeans events, allowing other components in an
+ * application to be notified when an event occurs on a rowset,
+ * such as a change in its value.
+ *
+ * <P>The <code>RowSet</code> interface is unique in that it is intended to be
+ * implemented using the rest of the JDBC API.  In other words, a
+ * <code>RowSet</code> implementation is a layer of software that executes "on top"
+ * of a JDBC driver.  Implementations of the <code>RowSet</code> interface can
+ * be provided by anyone, including JDBC driver vendors who want to
+ * provide a <code>RowSet</code> implementation as part of their JDBC products.
+ * <P>
+ * A <code>RowSet</code> object may make a connection with a data source and
+ * maintain that connection throughout its life cycle, in which case it is
+ * called a <i>connected</i> rowset.  A rowset may also make a connection with
+ * a data source, get data from it, and then close the connection. Such a rowset
+ * is called a <i>disconnected</i> rowset.  A disconnected rowset may make
+ * changes to its data while it is disconnected and then send the changes back
+ * to the original source of the data, but it must reestablish a connection to do so.
+ * <P>
+ * A disconnected rowset may have a reader (a <code>RowSetReader</code> object)
+ * and a writer (a <code>RowSetWriter</code> object) associated with it.
+ * The reader may be implemented in many different ways to populate a rowset
+ * with data, including getting data from a non-relational data source. The
+ * writer can also be implemented in many different ways to propagate changes
+ * made to the rowset's data back to the underlying data source.
+ * <P>
+ * Rowsets are easy to use.  The <code>RowSet</code> interface extends the standard
+ * <code>java.sql.ResultSet</code> interface.  The <code>RowSetMetaData</code>
+ * interface extends the <code>java.sql.ResultSetMetaData</code> interface.
+ * Thus, developers familiar
+ * with the JDBC API will have to learn a minimal number of new APIs to
+ * use rowsets.  In addition, third-party software tools that work with
+ * JDBC <code>ResultSet</code> objects will also easily be made to work with rowsets.
+ *
+ * @since 1.4
+ */
+
+public interface RowSet extends ResultSet {
+
+  //-----------------------------------------------------------------------
+  // Properties
+  //-----------------------------------------------------------------------
+
+  //-----------------------------------------------------------------------
+  // The following properties may be used to create a Connection.
+  //-----------------------------------------------------------------------
+
+  /**
+   * Retrieves the url property this <code>RowSet</code> object will use to
+   * create a connection if it uses the <code>DriverManager</code>
+   * instead of a <code>DataSource</code> object to establish the connection.
+   * The default value is <code>null</code>.
+   *
+   * @return a string url
+   * @exception SQLException if a database access error occurs
+   * @see #setUrl
+   */
+  String getUrl() throws SQLException;
+
+  /**
+   * Sets the URL this <code>RowSet</code> object will use when it uses the
+   * <code>DriverManager</code> to create a connection.
+   *
+   * Setting this property is optional.  If a URL is used, a JDBC driver
+   * that accepts the URL must be loaded before the
+   * rowset is used to connect to a database.  The rowset will use the URL
+   * internally to create a database connection when reading or writing
+   * data.  Either a URL or a data source name is used to create a
+   * connection, whichever was set to non null value most recently.
+   *
+   * @param url a string value; may be <code>null</code>
+   * @exception SQLException if a database access error occurs
+   * @see #getUrl
+   */
+  void setUrl(String url) throws SQLException;
+
+  /**
+   * Retrieves the logical name that identifies the data source for this
+   * <code>RowSet</code> object.
+   *
+   * @return a data source name
+   * @see #setDataSourceName
+   * @see #setUrl
+   */
+  String getDataSourceName();
+
+  /**
+   * Sets the data source name property for this <code>RowSet</code> object to the
+   * given <code>String</code>.
+   * <P>
+   * The value of the data source name property can be used to do a lookup of
+   * a <code>DataSource</code> object that has been registered with a naming
+   * service.  After being retrieved, the <code>DataSource</code> object can be
+   * used to create a connection to the data source that it represents.
+   *
+   * @param name the logical name of the data source for this <code>RowSet</code>
+   *        object; may be <code>null</code>
+   * @exception SQLException if a database access error occurs
+   * @see #getDataSourceName
+   */
+  void setDataSourceName(String name) throws SQLException;
+
+  /**
+   * Retrieves the username used to create a database connection for this
+   * <code>RowSet</code> object.
+   * The username property is set at run time before calling the method
+   * <code>execute</code>.  It is
+   * not usually part of the serialized state of a <code>RowSet</code> object.
+   *
+   * @return the username property
+   * @see #setUsername
+   */
+  String getUsername();
+
+  /**
+   * Sets the username property for this <code>RowSet</code> object to the
+   * given <code>String</code>.
+   *
+   * @param name a user name
+   * @exception SQLException if a database access error occurs
+   * @see #getUsername
+   */
+  void setUsername(String name) throws SQLException;
+
+  /**
+   * Retrieves the password used to create a database connection.
+   * The password property is set at run time before calling the method
+   * <code>execute</code>.  It is not usually part of the serialized state
+   * of a <code>RowSet</code> object.
+   *
+   * @return the password for making a database connection
+   * @see #setPassword
+   */
+  String getPassword();
+
+  /**
+   * Sets the database password for this <code>RowSet</code> object to
+   * the given <code>String</code>.
+   *
+   * @param password the password string
+   * @exception SQLException if a database access error occurs
+   * @see #getPassword
+   */
+  void setPassword(String password) throws SQLException;
+
+  /**
+   * Retrieves the transaction isolation level set for this
+   * <code>RowSet</code> object.
+   *
+   * @return the transaction isolation level; one of
+   *      <code>Connection.TRANSACTION_READ_UNCOMMITTED</code>,
+   *      <code>Connection.TRANSACTION_READ_COMMITTED</code>,
+   *      <code>Connection.TRANSACTION_REPEATABLE_READ</code>, or
+   *      <code>Connection.TRANSACTION_SERIALIZABLE</code>
+   * @see #setTransactionIsolation
+   */
+  int getTransactionIsolation();
+
+  /**
+   * Sets the transaction isolation level for this <code>RowSet</code> obejct.
+   *
+   * @param level the transaction isolation level; one of
+   *      <code>Connection.TRANSACTION_READ_UNCOMMITTED</code>,
+   *      <code>Connection.TRANSACTION_READ_COMMITTED</code>,
+   *      <code>Connection.TRANSACTION_REPEATABLE_READ</code>, or
+   *      <code>Connection.TRANSACTION_SERIALIZABLE</code>
+   * @exception SQLException if a database access error occurs
+   * @see #getTransactionIsolation
+   */
+  void setTransactionIsolation(int level) throws SQLException;
+
+  /**
+   * Retrieves the <code>Map</code> object associated with this
+   * <code>RowSet</code> object, which specifies the custom mapping
+   * of SQL user-defined types, if any.  The default is for the
+   * type map to be empty.
+   *
+   * @return a <code>java.util.Map</code> object containing the names of
+   *         SQL user-defined types and the Java classes to which they are
+   *         to be mapped
+   *
+   * @exception SQLException if a database access error occurs
+   * @see #setTypeMap
+   */
+   java.util.Map<String,Class<?>> getTypeMap() throws SQLException;
+
+  /**
+   * Installs the given <code>java.util.Map</code> object as the default
+   * type map for this <code>RowSet</code> object. This type map will be
+   * used unless another type map is supplied as a method parameter.
+   *
+   * @param map  a <code>java.util.Map</code> object containing the names of
+   *         SQL user-defined types and the Java classes to which they are
+   *         to be mapped
+   * @exception SQLException if a database access error occurs
+   * @see #getTypeMap
+   */
+   void setTypeMap(java.util.Map<String,Class<?>> map) throws SQLException;
+
+  //-----------------------------------------------------------------------
+  // The following properties may be used to create a Statement.
+  //-----------------------------------------------------------------------
+
+  /**
+   * Retrieves this <code>RowSet</code> object's command property.
+   *
+   * The command property contains a command string, which must be an SQL
+   * query, that can be executed to fill the rowset with data.
+   * The default value is <code>null</code>.
+   *
+   * @return the command string; may be <code>null</code>
+   * @see #setCommand
+   */
+  String getCommand();
+
+  /**
+   * Sets this <code>RowSet</code> object's command property to the given
+   * SQL query.
+   *
+   * This property is optional
+   * when a rowset gets its data from a data source that does not support
+   * commands, such as a spreadsheet.
+   *
+   * @param cmd the SQL query that will be used to get the data for this
+   *        <code>RowSet</code> object; may be <code>null</code>
+   * @exception SQLException if a database access error occurs
+   * @see #getCommand
+   */
+  void setCommand(String cmd) throws SQLException;
+
+  /**
+   * Retrieves whether this <code>RowSet</code> object is read-only.
+   * If updates are possible, the default is for a rowset to be
+   * updatable.
+   * <P>
+   * Attempts to update a read-only rowset will result in an
+   * <code>SQLException</code> being thrown.
+   *
+   * @return <code>true</code> if this <code>RowSet</code> object is
+   *         read-only; <code>false</code> if it is updatable
+   * @see #setReadOnly
+   */
+  boolean isReadOnly();
+
+  /**
+   * Sets whether this <code>RowSet</code> object is read-only to the
+   * given <code>boolean</code>.
+   *
+   * @param value <code>true</code> if read-only; <code>false</code> if
+   *        updatable
+   * @exception SQLException if a database access error occurs
+   * @see #isReadOnly
+   */
+  void setReadOnly(boolean value) throws SQLException;
+
+  /**
+   * Retrieves the maximum number of bytes that may be returned
+   * for certain column values.
+   * This limit applies only to <code>BINARY</code>,
+   * <code>VARBINARY</code>, <code>LONGVARBINARYBINARY</code>, <code>CHAR</code>,
+   * <code>VARCHAR</code>, <code>LONGVARCHAR</code>, <code>NCHAR</code>
+   * and <code>NVARCHAR</code> columns.
+   * If the limit is exceeded, the excess data is silently discarded.
+   *
+   * @return the current maximum column size limit; zero means that there
+   *          is no limit
+   * @exception SQLException if a database access error occurs
+   * @see #setMaxFieldSize
+   */
+  int getMaxFieldSize() throws SQLException;
+
+  /**
+   * Sets the maximum number of bytes that can be returned for a column
+   * value to the given number of bytes.
+   * This limit applies only to <code>BINARY</code>,
+   * <code>VARBINARY</code>, <code>LONGVARBINARYBINARY</code>, <code>CHAR</code>,
+   * <code>VARCHAR</code>, <code>LONGVARCHAR</code>, <code>NCHAR</code>
+   * and <code>NVARCHAR</code> columns.
+   * If the limit is exceeded, the excess data is silently discarded.
+   * For maximum portability, use values greater than 256.
+   *
+   * @param max the new max column size limit in bytes; zero means unlimited
+   * @exception SQLException if a database access error occurs
+   * @see #getMaxFieldSize
+   */
+  void setMaxFieldSize(int max) throws SQLException;
+
+  /**
+   * Retrieves the maximum number of rows that this <code>RowSet</code>
+   * object can contain.
+   * If the limit is exceeded, the excess rows are silently dropped.
+   *
+   * @return the current maximum number of rows that this <code>RowSet</code>
+   *         object can contain; zero means unlimited
+   * @exception SQLException if a database access error occurs
+   * @see #setMaxRows
+   */
+  int getMaxRows() throws SQLException;
+
+  /**
+   * Sets the maximum number of rows that this <code>RowSet</code>
+   * object can contain to the specified number.
+   * If the limit is exceeded, the excess rows are silently dropped.
+   *
+   * @param max the new maximum number of rows; zero means unlimited
+   * @exception SQLException if a database access error occurs
+   * @see #getMaxRows
+   */
+  void setMaxRows(int max) throws SQLException;
+
+  /**
+   * Retrieves whether escape processing is enabled for this
+   * <code>RowSet</code> object.
+   * If escape scanning is enabled, which is the default, the driver will do
+   * escape substitution before sending an SQL statement to the database.
+   *
+   * @return <code>true</code> if escape processing is enabled;
+   *         <code>false</code> if it is disabled
+   * @exception SQLException if a database access error occurs
+   * @see #setEscapeProcessing
+   */
+  boolean getEscapeProcessing() throws SQLException;
+
+  /**
+   * Sets escape processing for this <code>RowSet</code> object on or
+   * off. If escape scanning is on (the default), the driver will do
+   * escape substitution before sending an SQL statement to the database.
+   *
+   * @param enable <code>true</code> to enable escape processing;
+   *        <code>false</code> to disable it
+   * @exception SQLException if a database access error occurs
+   * @see #getEscapeProcessing
+   */
+  void setEscapeProcessing(boolean enable) throws SQLException;
+
+  /**
+   * Retrieves the maximum number of seconds the driver will wait for
+   * a statement to execute.
+   * If this limit is exceeded, an <code>SQLException</code> is thrown.
+   *
+   * @return the current query timeout limit in seconds; zero means
+   *          unlimited
+   * @exception SQLException if a database access error occurs
+   * @see #setQueryTimeout
+   */
+  int getQueryTimeout() throws SQLException;
+
+  /**
+   * Sets the maximum time the driver will wait for
+   * a statement to execute to the given number of seconds.
+   * If this limit is exceeded, an <code>SQLException</code> is thrown.
+   *
+   * @param seconds the new query timeout limit in seconds; zero means
+   *        that there is no limit
+   * @exception SQLException if a database access error occurs
+   * @see #getQueryTimeout
+   */
+  void setQueryTimeout(int seconds) throws SQLException;
+
+  /**
+   * Sets the type of this <code>RowSet</code> object to the given type.
+   * This method is used to change the type of a rowset, which is by
+   * default read-only and non-scrollable.
+   *
+   * @param type one of the <code>ResultSet</code> constants specifying a type:
+   *        <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
+   * @see java.sql.ResultSet#getType
+   */
+  void setType(int type) throws SQLException;
+
+  /**
+   * Sets the concurrency of this <code>RowSet</code> object to the given
+   * concurrency level. This method is used to change the concurrency level
+   * of a rowset, which is by default <code>ResultSet.CONCUR_READ_ONLY</code>
+   *
+   * @param concurrency one of the <code>ResultSet</code> constants specifying a
+   *        concurrency level:  <code>ResultSet.CONCUR_READ_ONLY</code> or
+   *        <code>ResultSet.CONCUR_UPDATABLE</code>
+   * @exception SQLException if a database access error occurs
+   * @see ResultSet#getConcurrency
+   */
+  void setConcurrency(int concurrency) throws SQLException;
+
+  //-----------------------------------------------------------------------
+  // Parameters
+  //-----------------------------------------------------------------------
+
+  /**
+   * The <code>RowSet</code> setter methods are used to set any input parameters
+   * needed by the <code>RowSet</code> object's command.
+   * Parameters are set at run time, as opposed to design time.
+   */
+
+  /**
+   * Sets the designated parameter in this <code>RowSet</code> object's SQL
+   * command 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 a SQL type code defined by <code>java.sql.Types</code>
+   * @exception SQLException if a database access error occurs
+   */
+  void setNull(int parameterIndex, int sqlType) 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 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 in this <code>RowSet</code> object's SQL
+   * command to SQL <code>NULL</code>. This version of the method <code>setNull</code>
+   * should  be used for SQL user-defined types (UDTs) and <code>REF</code> type
+   * parameters.  Examples of UDTs include: <code>STRUCT</code>, <code>DISTINCT</code>,
+   * <code>JAVA_OBJECT</code>, 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 UDT or <code>REF</code> parameter.  In the case of a UDT,
+   * the name is the type name of the parameter itself.  For a <code>REF</code>
+   * 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 UDT and <code>REF</code> 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 <code>REF</code> type,
+   * the typeName parameter is ignored.
+   *
+   *
+   * @param paramIndex 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 UDT or the type
+   *        name of the SQL structured type being referenced by a <code>REF</code>
+   *        type; ignored if the parameter is not a UDT or <code>REF</code> type
+   * @exception SQLException if a database access error occurs
+   */
+  void setNull (int paramIndex, int sqlType, String typeName)
+    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 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 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;
+
+  /**
+   * Sets the designated parameter in this <code>RowSet</code> object's command
+   * to the given Java <code>boolean</code> value. The driver converts this to
+   * an SQL <code>BIT</code> value before sending it to the database.
+   *
+   * @param parameterIndex the first parameter is 1, the second is 2, ...
+   * @param x the parameter value
+   * @exception SQLException if a database access error occurs
+   */
+  void setBoolean(int parameterIndex, boolean x) 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 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 in this <code>RowSet</code> object's command
+   * to the given Java <code>byte</code> value. The driver converts this to
+   * an SQL <code>TINYINT</code> value before sending it to the database.
+   *
+   * @param parameterIndex the first parameter is 1, the second is 2, ...
+   * @param x the parameter value
+   * @exception SQLException if a database access error occurs
+   */
+  void setByte(int parameterIndex, byte 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 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 in this <code>RowSet</code> object's command
+   * to the given Java <code>short</code> value. The driver converts this to
+   * an SQL <code>SMALLINT</code> value before sending it to the database.
+   *
+   * @param parameterIndex the first parameter is 1, the second is 2, ...
+   * @param x the parameter value
+   * @exception SQLException if a database access error occurs
+   */
+  void setShort(int parameterIndex, short 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 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 in this <code>RowSet</code> object's command
+   * to the given Java <code>int</code> value. The driver converts this to
+   * an SQL <code>INTEGER</code> value before sending it to the database.
+   *
+   * @param parameterIndex the first parameter is 1, the second is 2, ...
+   * @param x the parameter value
+   * @exception SQLException if a database access error occurs
+   */
+  void setInt(int parameterIndex, int 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 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 in this <code>RowSet</code> object's command
+   * to the given Java <code>long</code> value. The driver converts this to
+   * an SQL <code>BIGINT</code> value before sending it to the database.
+   *
+   * @param parameterIndex the first parameter is 1, the second is 2, ...
+   * @param x the parameter value
+   * @exception SQLException if a database access error occurs
+   */
+  void setLong(int parameterIndex, long 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 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 in this <code>RowSet</code> object's command
+   * to the given Java <code>float</code> value. The driver converts this to
+   * an SQL <code>REAL</code> value before sending it to the database.
+   *
+   * @param parameterIndex the first parameter is 1, the second is 2, ...
+   * @param x the parameter value
+   * @exception SQLException if a database access error occurs
+   */
+  void setFloat(int parameterIndex, float 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 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 in this <code>RowSet</code> object's command
+   * to the given Java <code>double</code> value. The driver converts this to
+   * an SQL <code>DOUBLE</code> value before sending it to the database.
+   *
+   * @param parameterIndex the first parameter is 1, the second is 2, ...
+   * @param x the parameter value
+   * @exception SQLException if a database access error occurs
+   */
+  void setDouble(int parameterIndex, double 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 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 in this <code>RowSet</code> object's command
+   * to the given <code>java.math.BigDeciaml</code> value.
+   * The driver converts this to
+   * an SQL <code>NUMERIC</code> value before sending it to the database.
+   *
+   * @param parameterIndex the first parameter is 1, the second is 2, ...
+   * @param x the parameter value
+   * @exception SQLException if a database access error occurs
+   */
+  void setBigDecimal(int parameterIndex, BigDecimal 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 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 in this <code>RowSet</code> object's command
+   * to the given Java <code>String</code> value. Before sending it to the
+   * database, 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.
+   *
+   * @param parameterIndex the first parameter is 1, the second is 2, ...
+   * @param x the parameter value
+   * @exception SQLException if a database access error occurs
+   */
+  void setString(int parameterIndex, String 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 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 in this <code>RowSet</code> object's command
+   * to the given Java array of <code>byte</code> values. Before sending it to the
+   * database, the driver converts this to an SQL <code>VARBINARY</code> or
+   * <code>LONGVARBINARY</code> value, depending on the argument's size relative
+   * to the driver's limits on <code>VARBINARY</code> values.
+   *
+   * @param parameterIndex the first parameter is 1, the second is 2, ...
+   * @param x the parameter value
+   * @exception SQLException if a database access error occurs
+   */
+  void setBytes(int parameterIndex, byte 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 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 in this <code>RowSet</code> object's command
+   * to the given <code>java.sql.Date</code> value. The driver converts this to
+   * an SQL <code>DATE</code> value before sending it to the database, using the
+   * default <code>java.util.Calendar</code> to calculate the date.
+   *
+   * @param parameterIndex the first parameter is 1, the second is 2, ...
+   * @param x the parameter value
+   * @exception SQLException if a database access error occurs
+   */
+  void setDate(int parameterIndex, java.sql.Date x) throws SQLException;
+
+  /**
+   * Sets the designated parameter in this <code>RowSet</code> object's command
+   * to the given <code>java.sql.Time</code> value. The driver converts this to
+   * an SQL <code>TIME</code> value before sending it to the database, using the
+   * default <code>java.util.Calendar</code> to calculate it.
+   *
+   * @param parameterIndex the first parameter is 1, the second is 2, ...
+   * @param x the parameter value
+   * @exception SQLException if a database access error occurs
+   */
+  void setTime(int parameterIndex, java.sql.Time x) throws SQLException;
+
+  /**
+   * Sets the designated parameter in this <code>RowSet</code> object's command
+   * to the given <code>java.sql.Timestamp</code> value. The driver converts this to
+   * an SQL <code>TIMESTAMP</code> value before sending it to the database, using the
+   * default <code>java.util.Calendar</code> to calculate it.
+   *
+   * @param parameterIndex the first parameter is 1, the second is 2, ...
+   * @param x the parameter value
+   * @exception SQLException if a database access error occurs
+   */
+  void setTimestamp(int parameterIndex, java.sql.Timestamp 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 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 in this <code>RowSet</code> object's command
+   * to the given <code>java.io.InputStream</code> value.
+   * It may be more practical to send a very large ASCII value via a
+   * <code>java.io.InputStream</code> rather than as a <code>LONGVARCHAR</code>
+   * parameter. The driver will read the data from the stream
+   * as needed until it reaches end-of-file.
+   *
+   * <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 a database access error occurs
+   */
+  void setAsciiStream(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 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 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 in this <code>RowSet</code> object's command
+   * to the given <code>java.io.InputStream</code> value.
+   * It may be more practical to send a very large binary value via a
+   * <code>java.io.InputStream</code> rather than as a <code>LONGVARBINARY</code>
+   * parameter. The driver will read the data from the stream
+   * as needed until it reaches end-of-file.
+   *
+   * <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 a database access error occurs
+   */
+  void setBinaryStream(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 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 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 designated parameter in this <code>RowSet</code> object's command
+   * to the given <code>java.io.Reader</code> value.
+   * It may be more practical to send a very large UNICODE value via a
+   * <code>java.io.Reader</code> rather than as a <code>LONGVARCHAR</code>
+   * parameter. The driver will read the data from the stream
+   * as needed until it reaches end-of-file.
+   *
+   * <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>Reader</code> object that contains the UNICODE data
+   *        to be set
+   * @param length the number of characters in the stream
+   * @exception SQLException if a database access error occurs
+   */
+  void setCharacterStream(int parameterIndex,
+                          Reader reader,
+                          int 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 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 in this <code>RowSet</code> object's command
+   * 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 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 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 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 in this <code>RowSet</code> object's command
+   * 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 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 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 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 in this <code>RowSet</code> object's command
+   * 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 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 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 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 in this <code>RowSet</code> object's command
+   * 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 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 in this <code>RowSet</code> object's command
+   * with the given Java <code>Object</code>.  For integral values, the
+   * <code>java.lang</code> equivalent objects should be used (for example,
+   * an instance of the class <code>Integer</code> for an <code>int</code>).
+   *
+   * 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 targetSqlType
+   * before being sent to the database.
+   * <P>
+   * If the object is of a class implementing <code>SQLData</code>,
+   * the rowset should call the method <code>SQLData.writeSQL</code>
+   * to write the object to an <code>SQLOutput</code> 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>
+   *
+   * <p>Note that this method may be used to pass datatabase-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 <code>java.sql.Types</code>)
+   *        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 a database access error occurs
+   * @see java.sql.Types
+   */
+  void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength)
+            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 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 designated parameter in this <code>RowSet</code> object's command
+   * with a Java <code>Object</code>.  For integral values, the
+   * <code>java.lang</code> equivalent objects should be used.
+   * This method is like <code>setObject</code> above, but the scale used is the scale
+   * of the second parameter.  Scalar values have a scale of zero.  Literal
+   * values have the scale present in the literal.
+   * <P>
+   * Even though it is supported, it is not recommended that this method
+   * be called with floating point input values.
+   *
+   * @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 <code>java.sql.Types</code>)
+   *        to be sent to the database
+   * @exception SQLException if a database access error occurs
+   */
+  void setObject(int parameterIndex, Object x,
+                 int targetSqlType) 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 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.
+     *
+     * @param parameterName the name of the parameter
+     * @param x the object containing the input parameter value
+     * @exception SQLException 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 in this <code>RowSet</code> object's command
+   * with a Java <code>Object</code>.  For integral values, the
+   * <code>java.lang</code> equivalent objects should be used.
+   *
+   * <p>The JDBC specification provides a standard mapping from
+   * Java Object types to SQL types.  The driver will convert the
+   * given Java object to its standard SQL mapping before sending it
+   * 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 <code>SQLData</code>,
+   * the rowset should call the method <code>SQLData.writeSQL</code>
+   * to write the object to an <code>SQLOutput</code> 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>
+   * <P>
+   * An exception is thrown if there is an ambiguity, for example, if the
+   * object is of a class implementing more than one of these interfaces.
+   *
+   * @param parameterIndex The first parameter is 1, the second is 2, ...
+   * @param x The object containing the input parameter value
+   * @exception SQLException if a database access error occurs
+   */
+  void setObject(int parameterIndex, Object x) throws SQLException;
+
+
+  /**
+   * Sets the designated parameter in this <code>RowSet</code> object's command
+   * with the given  <code>Ref</code> value.  The driver will convert this
+   * to the appropriate <code>REF(&lt;structured-type&gt;)</code> value.
+   *
+   * @param i the first parameter is 1, the second is 2, ...
+   * @param x an object representing data of an SQL <code>REF</code> type
+   * @exception SQLException if a database access error occurs
+   */
+  void setRef (int i, Ref x) throws SQLException;
+
+  /**
+   * Sets the designated parameter in this <code>RowSet</code> object's command
+   * with the given  <code>Blob</code> value.  The driver will convert this
+   * to the <code>BLOB</code> value that the <code>Blob</code> object
+   * represents before sending it to the database.
+   *
+   * @param i the first parameter is 1, the second is 2, ...
+   * @param x an object representing a BLOB
+   * @exception SQLException if a database access error occurs
+   */
+  void setBlob (int i, Blob x) 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 a database access error occurs,
+     * this method is called on a closed <code>PreparedStatement</code>,
+     * if parameterIndex does not correspond
+     * to a parameter marker in the SQL statement,  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>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 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>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 parameterIndex does not correspond
+     * to a parameter marker in the SQL statement,  or 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 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 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 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 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 in this <code>RowSet</code> object's command
+   * with the given  <code>Clob</code> value.  The driver will convert this
+   * to the <code>CLOB</code> value that the <code>Clob</code> object
+   * represents before sending it to the database.
+   *
+   * @param i the first parameter is 1, the second is 2, ...
+   * @param x an object representing a CLOB
+   * @exception SQLException if a database access error occurs
+   */
+  void setClob (int i, Clob x) 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 a database access error occurs, this method is called on
+     * a closed <code>PreparedStatement</code>, if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement, 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>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 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>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 parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; 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 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 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 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 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 in this <code>RowSet</code> object's command
+   * with the given  <code>Array</code> value.  The driver will convert this
+   * to the <code>ARRAY</code> value that the <code>Array</code> object
+   * represents before sending it to the database.
+   *
+   * @param i the first parameter is 1, the second is 2, ...
+   * @param x an object representing an SQL array
+   * @exception SQLException if a database access error occurs
+   */
+  void setArray (int i, Array x) throws SQLException;
+
+  /**
+   * Sets the designated parameter in this <code>RowSet</code> object's command
+   * with the given  <code>java.sql.Date</code> value.  The driver will convert this
+   * to an SQL <code>DATE</code> value, using the given <code>java.util.Calendar</code>
+   * object to calculate the date.
+   *
+   * @param parameterIndex the first parameter is 1, the second is 2, ...
+   * @param x the parameter value
+   * @param cal the <code>java.util.Calendar</code> object to use for calculating the date
+   * @exception SQLException if a database access error occurs
+   */
+  void setDate(int parameterIndex, java.sql.Date x, Calendar cal)
+    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 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.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 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 in this <code>RowSet</code> object's command
+   * with the given  <code>java.sql.Time</code> value.  The driver will convert this
+   * to an SQL <code>TIME</code> value, using the given <code>java.util.Calendar</code>
+   * object to calculate it, before sending it to the database.
+   *
+   * @param parameterIndex the first parameter is 1, the second is 2, ...
+   * @param x the parameter value
+   * @param cal the <code>java.util.Calendar</code> object to use for calculating the time
+   * @exception SQLException if a database access error occurs
+   */
+  void setTime(int parameterIndex, java.sql.Time x, Calendar cal)
+    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 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.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 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 in this <code>RowSet</code> object's command
+   * with the given  <code>java.sql.Timestamp</code> value.  The driver will
+   * convert this to an SQL <code>TIMESTAMP</code> value, using the given
+   * <code>java.util.Calendar</code> object to calculate it, before sending it to the
+   * database.
+   *
+   * @param parameterIndex the first parameter is 1, the second is 2, ...
+   * @param x the parameter value
+   * @param cal the <code>java.util.Calendar</code> object to use for calculating the
+   *        timestamp
+   * @exception SQLException if a database access error occurs
+   */
+  void setTimestamp(int parameterIndex, java.sql.Timestamp 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 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;
+
+  /**
+   * Clears the parameters set for this <code>RowSet</code> object's command.
+   * <P>In general, parameter values remain in force for repeated use of a
+   * <code>RowSet</code> object. 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, which can
+   * be done by calling the method <code>clearParameters</code>.
+   *
+   * @exception SQLException if a database access error occurs
+   */
+  void clearParameters() throws SQLException;
+
+  //---------------------------------------------------------------------
+  // Reading and writing data
+  //---------------------------------------------------------------------
+
+  /**
+   * Fills this <code>RowSet</code> object with data.
+   * <P>
+   * The <code>execute</code> method may use the following properties
+   * to create a connection for reading data: url, data source name,
+   * user name, password, transaction isolation, and type map.
+   *
+   * The <code>execute</code> method  may use the following properties
+   * to create a statement to execute a command:
+   * command, read only, maximum field size,
+   * maximum rows, escape processing, and query timeout.
+   * <P>
+   * If the required properties have not been set, an exception is
+   * thrown.  If this method is successful, the current contents of the rowset are
+   * discarded and the rowset's metadata is also (re)set.  If there are
+   * outstanding updates, they are ignored.
+   * <P>
+   * If this <code>RowSet</code> object does not maintain a continuous connection
+   * with its source of data, it may use a reader (a <code>RowSetReader</code>
+   * object) to fill itself with data.  In this case, a reader will have been
+   * registered with this <code>RowSet</code> object, and the method
+   * <code>execute</code> will call on the reader's <code>readData</code>
+   * method as part of its implementation.
+   *
+   * @exception SQLException if a database access error occurs or any of the
+   *            properties necessary for making a connection and creating
+   *            a statement have not been set
+   */
+  void execute() throws SQLException;
+
+  //--------------------------------------------------------------------
+  // Events
+  //--------------------------------------------------------------------
+
+  /**
+   * Registers the given listener so that it will be notified of events
+   * that occur on this <code>RowSet</code> object.
+   *
+   * @param listener a component that has implemented the <code>RowSetListener</code>
+   *        interface and wants to be notified when events occur on this
+   *        <code>RowSet</code> object
+   * @see #removeRowSetListener
+   */
+  void addRowSetListener(RowSetListener listener);
+
+  /**
+   * Removes the specified listener from the list of components that will be
+   * notified when an event occurs on this <code>RowSet</code> object.
+   *
+   * @param listener a component that has been registered as a listener for this
+   *        <code>RowSet</code> object
+   * @see #addRowSetListener
+   */
+  void removeRowSetListener(RowSetListener listener);
+
+    /**
+      * 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.
+      * @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 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  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.
+      * @since 1.6
+      */
+     void setSQLXML(int parameterIndex, SQLXML xmlObject) 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 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  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.
+     * @since 1.6
+     */
+    void setSQLXML(String parameterName, SQLXML xmlObject) 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> 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 a database access error occurs
+     *
+     * @since 1.6
+     */
+    void setRowId(int parameterIndex, RowId x) 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 a database access error occurs
+    * @since 1.6
+    */
+   void setRowId(String parameterName, 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 the driver does not support national
+     *         character sets;  if the driver can detect that a data conversion
+     *  error could occur ; or if a database access error occurs
+     * @since 1.6
+     */
+     void setNString(int parameterIndex, String value) 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>
+     * @param parameterName the name of the column to be set
+     * @param value the parameter value
+     * @throws SQLException if the driver does not support national
+     *         character sets;  if the driver can detect that a data conversion
+     *  error could occur; or if a database access error occurs
+     * @since 1.6
+     */
+    public 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 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 the driver does not support national
+     *         character sets;  if the driver can detect that a data conversion
+     *  error could occur ; or if a database access error occurs
+     * @since 1.6
+     */
+     void setNCharacterStream(int parameterIndex, Reader value, long length) 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 column to be set
+     * @param value the parameter value
+     * @param length the number of characters in the parameter data.
+     * @throws SQLException if the driver does not support national
+     *         character sets;  if the driver can detect that a data conversion
+     *  error could occur; or if a database access error occurs
+     * @since 1.6
+     */
+    public void setNCharacterStream(String parameterName, Reader value, long length)
+            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 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>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 column to be set
+    * @param value the parameter value
+    * @throws SQLException if the driver does not support national
+    *         character sets;  if the driver can detect that a data conversion
+    *  error could occur; or if a database access error occurs
+    * @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>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 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>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;
+
+    /**
+     * 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 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;
+
+    /**
+     * 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 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 the driver does not support national
+     *         character sets;  if the driver can detect that a data conversion
+     *  error could occur ; or if a database access error occurs
+     * @since 1.6
+     */
+     void setNClob(int parameterIndex, NClob 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>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;
+
+    /**
+     * 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 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;
+
+
+
+}
diff --git a/javax/sql/RowSetEvent.java b/javax/sql/RowSetEvent.java
new file mode 100644
index 0000000..ab811ca
--- /dev/null
+++ b/javax/sql/RowSetEvent.java
@@ -0,0 +1,62 @@
+/*
+ * 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 javax.sql;
+
+/**
+ * An <code>Event</code> object generated when an event occurs to a
+ * <code>RowSet</code> object.  A <code>RowSetEvent</code> object is
+ * generated when a single row in a rowset is changed, the whole rowset
+ * is changed, or the rowset cursor moves.
+ * <P>
+ * When an event occurs on a <code>RowSet</code> object, one of the
+ * <code>RowSetListener</code> methods will be sent to all registered
+ * listeners to notify them of the event.  An <code>Event</code> object
+ * is supplied to the <code>RowSetListener</code> method so that the
+ * listener can use it to find out which <code>RowSet</code> object is
+ * the source of the event.
+ *
+ * @since 1.4
+ */
+
+public class RowSetEvent extends java.util.EventObject {
+
+  /**
+   * Constructs a <code>RowSetEvent</code> object initialized with the
+   * given <code>RowSet</code> object.
+   *
+   * @param source the <code>RowSet</code> object whose data has changed or
+   *        whose cursor has moved
+   * @throws IllegalArgumentException if <code>source</code> is null.
+   */
+  public RowSetEvent(RowSet source)
+    { super(source); }
+
+  /**
+   * Private serial version unique ID to ensure serialization
+   * compatibility.
+   */
+  static final long serialVersionUID = -1875450876546332005L;
+}
diff --git a/javax/sql/RowSetInternal.java b/javax/sql/RowSetInternal.java
new file mode 100644
index 0000000..a58d862
--- /dev/null
+++ b/javax/sql/RowSetInternal.java
@@ -0,0 +1,103 @@
+/*
+ * 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 javax.sql;
+
+import java.sql.*;
+
+/**
+ * The interface that a <code>RowSet</code> object implements in order to
+ * present itself to a <code>RowSetReader</code> or <code>RowSetWriter</code>
+ * object. The <code>RowSetInternal</code> interface contains
+ * methods that let the reader or writer access and modify the internal
+ * state of the rowset.
+ *
+ * @since 1.4
+ */
+
+public interface RowSetInternal {
+
+  /**
+   * Retrieves the parameters that have been set for this
+   * <code>RowSet</code> object's command.
+   *
+   * @return an array of the current parameter values for this <code>RowSet</code>
+   *         object's command
+   * @exception SQLException if a database access error occurs
+   */
+  Object[] getParams() throws SQLException;
+
+  /**
+   * Retrieves the <code>Connection</code> object that was passed to this
+   * <code>RowSet</code> object.
+   *
+   * @return the <code>Connection</code> object passed to the rowset
+   *      or <code>null</code> if none was passed
+   * @exception SQLException if a database access error occurs
+   */
+  Connection getConnection() throws SQLException;
+
+  /**
+   * Sets the given <code>RowSetMetaData</code> object as the
+   * <code>RowSetMetaData</code> object for this <code>RowSet</code>
+   * object. The <code>RowSetReader</code> object associated with the rowset
+   * will use <code>RowSetMetaData</code> methods to set the values giving
+   * information about the rowset's columns.
+   *
+   * @param md the <code>RowSetMetaData</code> object that will be set with
+   *        information about the rowset's columns
+   *
+   * @exception SQLException if a database access error occurs
+   */
+  void setMetaData(RowSetMetaData md) throws SQLException;
+
+  /**
+   * Retrieves a <code>ResultSet</code> object containing the original
+   * value of this <code>RowSet</code> object.
+   * <P>
+   * The cursor is positioned before the first row in the result set.
+   * Only rows contained in the result set returned by the method
+   * <code>getOriginal</code> are said to have an original value.
+   *
+   * @return the original value of the rowset
+   * @exception SQLException if a database access error occurs
+   */
+  public ResultSet getOriginal() throws SQLException;
+
+  /**
+   * Retrieves a <code>ResultSet</code> object containing the original value
+   * of the current row only.  If the current row has no original value,
+   * an empty result set is returned. If there is no current row,
+   * an exception is thrown.
+   *
+   * @return the original value of the current row as a <code>ResultSet</code>
+   *          object
+   * @exception SQLException if a database access error occurs or this method
+   *           is called while the cursor is on the insert row, before the
+   *           first row, or after the last row
+   */
+  public ResultSet getOriginalRow() throws SQLException;
+
+}
diff --git a/javax/sql/RowSetListener.java b/javax/sql/RowSetListener.java
new file mode 100644
index 0000000..688d289
--- /dev/null
+++ b/javax/sql/RowSetListener.java
@@ -0,0 +1,77 @@
+/*
+ * 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 javax.sql;
+
+/**
+ * An interface that must be implemented by a
+ * component that wants to be notified when a significant
+ * event happens in the life of a <code>RowSet</code> object.
+ * A component becomes a listener by being registered with a
+ * <code>RowSet</code> object via the method <code>RowSet.addRowSetListener</code>.
+ * How a registered component implements this interface determines what it does
+ * when it is notified of an event.
+ *
+ * @since 1.4
+ */
+
+public interface RowSetListener extends java.util.EventListener {
+
+  /**
+   * Notifies registered listeners that a <code>RowSet</code> object
+   * in the given <code>RowSetEvent</code> object has changed its entire contents.
+   * <P>
+   * The source of the event can be retrieved with the method
+   * <code>event.getSource</code>.
+   *
+   * @param event a <code>RowSetEvent</code> object that contains
+   *         the <code>RowSet</code> object that is the source of the event
+   */
+  void rowSetChanged(RowSetEvent event);
+
+  /**
+   * Notifies registered listeners that a <code>RowSet</code> object
+   * has had a change in one of its rows.
+   * <P>
+   * The source of the event can be retrieved with the method
+   * <code>event.getSource</code>.
+   *
+   * @param event a <code>RowSetEvent</code> object that contains
+   *         the <code>RowSet</code> object that is the source of the event
+   */
+  void rowChanged(RowSetEvent event);
+
+  /**
+   * Notifies registered listeners that a <code>RowSet</code> object's
+   * cursor has moved.
+   * <P>
+   * The source of the event can be retrieved with the method
+   * <code>event.getSource</code>.
+   *
+   * @param event a <code>RowSetEvent</code> object that contains
+   *         the <code>RowSet</code> object that is the source of the event
+   */
+  void cursorMoved(RowSetEvent event);
+}
diff --git a/javax/sql/RowSetMetaData.java b/javax/sql/RowSetMetaData.java
new file mode 100644
index 0000000..76bc4f7
--- /dev/null
+++ b/javax/sql/RowSetMetaData.java
@@ -0,0 +1,235 @@
+/*
+ * 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 javax.sql;
+
+import java.sql.*;
+
+/**
+ * An object that contains information about the columns in a
+ * <code>RowSet</code> object.  This interface is
+ * an extension of the <code>ResultSetMetaData</code> interface with
+ * methods for setting the values in a <code>RowSetMetaData</code> object.
+ * When a <code>RowSetReader</code> object reads data into a <code>RowSet</code>
+ * object, it creates a <code>RowSetMetaData</code> object and initializes it
+ * using the methods in the <code>RowSetMetaData</code> interface.  Then the
+ * reader passes the <code>RowSetMetaData</code> object to the rowset.
+ * <P>
+ * The methods in this interface are invoked internally when an application
+ * calls the method <code>RowSet.execute</code>; an application
+ * programmer would not use them directly.
+ *
+ * @since 1.4
+ */
+
+public interface RowSetMetaData extends ResultSetMetaData {
+
+  /**
+   * Sets the number of columns in the <code>RowSet</code> object to
+   * the given number.
+   *
+   * @param columnCount the number of columns in the <code>RowSet</code> object
+   * @exception SQLException if a database access error occurs
+   */
+  void setColumnCount(int columnCount) throws SQLException;
+
+  /**
+   * Sets whether the designated column is automatically numbered,
+   * The default is for a <code>RowSet</code> object's
+   * columns not to be automatically numbered.
+   *
+   * @param columnIndex the first column is 1, the second is 2, ...
+   * @param property <code>true</code> if the column is automatically
+   *                 numbered; <code>false</code> if it is not
+   *
+   * @exception SQLException if a database access error occurs
+   */
+  void setAutoIncrement(int columnIndex, boolean property) throws SQLException;
+
+  /**
+   * Sets whether the designated column is case sensitive.
+   * The default is <code>false</code>.
+   *
+   * @param columnIndex the first column is 1, the second is 2, ...
+   * @param property <code>true</code> if the column is case sensitive;
+   *                 <code>false</code> if it is not
+   *
+   * @exception SQLException if a database access error occurs
+   */
+  void setCaseSensitive(int columnIndex, boolean property) throws SQLException;
+
+  /**
+   * Sets whether the designated column can be used in a where clause.
+   * The default is <code>false</code>.
+   *
+   * @param columnIndex the first column is 1, the second is 2, ...
+   * @param property <code>true</code> if the column can be used in a
+   *                 <code>WHERE</code> clause; <code>false</code> if it cannot
+   *
+   * @exception SQLException if a database access error occurs
+   */
+  void setSearchable(int columnIndex, boolean property) throws SQLException;
+
+  /**
+   * Sets whether the designated column is a cash value.
+   * The default is <code>false</code>.
+   *
+   * @param columnIndex the first column is 1, the second is 2, ...
+   * @param property <code>true</code> if the column is a cash value;
+   *                 <code>false</code> if it is not
+   *
+   * @exception SQLException if a database access error occurs
+   */
+  void setCurrency(int columnIndex, boolean property) throws SQLException;
+
+  /**
+   * Sets whether the designated column's value can be set to
+   * <code>NULL</code>.
+   * The default is <code>ResultSetMetaData.columnNullableUnknown</code>
+   *
+   * @param columnIndex the first column is 1, the second is 2, ...
+   * @param property one of the following constants:
+   *                 <code>ResultSetMetaData.columnNoNulls</code>,
+   *                 <code>ResultSetMetaData.columnNullable</code>, or
+   *                 <code>ResultSetMetaData.columnNullableUnknown</code>
+   *
+   * @exception SQLException if a database access error occurs
+   */
+  void setNullable(int columnIndex, int property) throws SQLException;
+
+  /**
+   * Sets whether the designated column is a signed number.
+   * The default is <code>false</code>.
+   *
+   * @param columnIndex the first column is 1, the second is 2, ...
+   * @param property <code>true</code> if the column is a signed number;
+   *                 <code>false</code> if it is not
+   *
+   * @exception SQLException if a database access error occurs
+   */
+  void setSigned(int columnIndex, boolean property) throws SQLException;
+
+  /**
+   * Sets the designated column's normal maximum width in chars to the
+   * given <code>int</code>.
+   *
+   * @param columnIndex the first column is 1, the second is 2, ...
+   * @param size the normal maximum number of characters for
+   *           the designated column
+   *
+   * @exception SQLException if a database access error occurs
+   */
+  void setColumnDisplaySize(int columnIndex, int size) throws SQLException;
+
+  /**
+   * Sets the suggested column title for use in printouts and
+   * displays, if any, to the given <code>String</code>.
+   *
+   * @param columnIndex the first column is 1, the second is 2, ...
+   * @param label the column title
+   * @exception SQLException if a database access error occurs
+   */
+  void setColumnLabel(int columnIndex, String label) throws SQLException;
+
+  /**
+   * Sets the name of the designated column to the given <code>String</code>.
+   *
+   * @param columnIndex the first column is 1, the second is 2, ...
+   * @param columnName the designated column's name
+   * @exception SQLException if a database access error occurs
+   */
+  void setColumnName(int columnIndex, String columnName) throws SQLException;
+
+  /**
+   * Sets the name of the designated column's table's schema, if any, to
+   * the given <code>String</code>.
+   *
+   * @param columnIndex the first column is 1, the second is 2, ...
+   * @param schemaName the schema name
+   * @exception SQLException if a database access error occurs
+   */
+  void setSchemaName(int columnIndex, String schemaName) throws SQLException;
+
+  /**
+   * Sets the designated column's number of decimal digits to the
+   * given <code>int</code>.
+   *
+   * @param columnIndex the first column is 1, the second is 2, ...
+   * @param precision the total number of decimal digits
+   * @exception SQLException if a database access error occurs
+   */
+  void setPrecision(int columnIndex, int precision) throws SQLException;
+
+  /**
+   * Sets the designated column's number of digits to the
+   * right of the decimal point to the given <code>int</code>.
+   *
+   * @param columnIndex the first column is 1, the second is 2, ...
+   * @param scale the number of digits to right of decimal point
+   * @exception SQLException if a database access error occurs
+   */
+  void setScale(int columnIndex, int scale) throws SQLException;
+
+  /**
+   * Sets the designated column's table name, if any, to the given
+   * <code>String</code>.
+   *
+   * @param columnIndex the first column is 1, the second is 2, ...
+   * @param tableName the column's table name
+   * @exception SQLException if a database access error occurs
+   */
+  void setTableName(int columnIndex, String tableName) throws SQLException;
+
+  /**
+   * Sets the designated column's table's catalog name, if any, to the given
+   * <code>String</code>.
+   *
+   * @param columnIndex the first column is 1, the second is 2, ...
+   * @param catalogName the column's catalog name
+   * @exception SQLException if a database access error occurs
+   */
+  void setCatalogName(int columnIndex, String catalogName) throws SQLException;
+
+  /**
+   * Sets the designated column's SQL type to the one given.
+   *
+   * @param columnIndex the first column is 1, the second is 2, ...
+   * @param SQLType the column's SQL type
+   * @exception SQLException if a database access error occurs
+   * @see Types
+   */
+  void setColumnType(int columnIndex, int SQLType) throws SQLException;
+
+  /**
+   * Sets the designated column's type name that is specific to the
+   * data source, if any, to the given <code>String</code>.
+   *
+   * @param columnIndex the first column is 1, the second is 2, ...
+   * @param typeName data source specific type name.
+   * @exception SQLException if a database access error occurs
+   */
+  void setColumnTypeName(int columnIndex, String typeName) throws SQLException;
+
+}
diff --git a/javax/sql/RowSetReader.java b/javax/sql/RowSetReader.java
new file mode 100644
index 0000000..c699db2
--- /dev/null
+++ b/javax/sql/RowSetReader.java
@@ -0,0 +1,73 @@
+/*
+ * 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 javax.sql;
+
+import java.sql.*;
+
+/**
+ * The facility that a disconnected <code>RowSet</code> object calls on
+ * to populate itself with rows of data. A reader (an object implementing the
+ * <code>RowSetReader</code> interface) may be registered with
+ * a <code>RowSet</code> object that supports the reader/writer paradigm.
+ * When the <code>RowSet</code> object's <code>execute</code> method is
+ * called, it in turn calls the reader's <code>readData</code> method.
+ *
+ * @since 1.4
+ */
+
+public interface RowSetReader {
+
+  /**
+   * Reads the new contents of the calling <code>RowSet</code> object.
+   * In order to call this method, a <code>RowSet</code>
+   * object must have implemented the <code>RowSetInternal</code> interface
+   * and registered this <code>RowSetReader</code> object as its reader.
+   * The <code>readData</code>  method is invoked internally
+   * by the <code>RowSet.execute</code> method for rowsets that support the
+   * reader/writer paradigm.
+   *
+   * <P>The <code>readData</code> method adds rows to the caller.
+   * It can be implemented in a wide variety of ways and can even
+   * populate the caller with rows from a nonrelational data source.
+   * In general, a reader may invoke any of the rowset's methods,
+   * with one exception. Calling the method <code>execute</code> will
+   * cause an <code>SQLException</code> to be thrown
+   * because <code>execute</code> may not be called recursively.  Also,
+   * when a reader invokes <code>RowSet</code> methods, no listeners
+   * are notified; that is, no <code>RowSetEvent</code> objects are
+   * generated and no <code>RowSetListener</code> methods are invoked.
+   * This is true because listeners are already being notified by the method
+   * <code>execute</code>.
+   *
+   * @param caller the <code>RowSet</code> object (1) that has implemented the
+   *         <code>RowSetInternal</code> interface, (2) with which this reader is
+   *        registered, and (3) whose <code>execute</code> method called this reader
+   * @exception SQLException if a database access error occurs or this method
+   *            invokes the <code>RowSet.execute</code> method
+   */
+  void readData(RowSetInternal caller) throws SQLException;
+
+}
diff --git a/javax/sql/RowSetWriter.java b/javax/sql/RowSetWriter.java
new file mode 100644
index 0000000..1865ba2
--- /dev/null
+++ b/javax/sql/RowSetWriter.java
@@ -0,0 +1,64 @@
+/*
+ * 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 javax.sql;
+
+import java.sql.*;
+
+/**
+ * An object that implements the <code>RowSetWriter</code> interface,
+ * called a <i>writer</i>. A writer may be registered with a <code>RowSet</code>
+ * object that supports the reader/writer paradigm.
+ * <P>
+ * If a disconnected <code>RowSet</code> object modifies some of its data,
+ * and it has a writer associated with it, it may be implemented so that it
+ * calls on the writer's <code>writeData</code> method internally
+ * to write the updates back to the data source. In order to do this, the writer
+ * must first establish a connection with the rowset's data source.
+ * <P>
+ * If the data to be updated has already been changed in the data source, there
+ * is a conflict, in which case the writer will not write
+ * the changes to the data source.  The algorithm the writer uses for preventing
+ * or limiting conflicts depends entirely on its implementation.
+ *
+ * @since 1.4
+ */
+
+public interface RowSetWriter {
+
+  /**
+   * Writes the changes in this <code>RowSetWriter</code> object's
+   * rowset back to the data source from which it got its data.
+   *
+   * @param caller the <code>RowSet</code> object (1) that has implemented the
+   *         <code>RowSetInternal</code> interface, (2) with which this writer is
+   *        registered, and (3) that called this method internally
+   * @return <code>true</code> if the modified data was written; <code>false</code>
+   *          if not, which will be the case if there is a conflict
+   * @exception SQLException if a database access error occurs
+   */
+  boolean writeData(RowSetInternal caller) throws SQLException;
+
+}
diff --git a/javax/sql/StatementEvent.java b/javax/sql/StatementEvent.java
new file mode 100644
index 0000000..bb41be7
--- /dev/null
+++ b/javax/sql/StatementEvent.java
@@ -0,0 +1,117 @@
+/*
+ * 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.
+ */
+
+/*
+ * Created on Apr 28, 2005
+ */
+package javax.sql;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.EventObject;
+
+/**
+ * A <code>StatementEvent</code> is sent to all <code>StatementEventListener</code>s which were
+ * registered with a <code>PooledConnection</code>. This occurs when the driver determines that a
+ * <code>PreparedStatement</code> that is associated with the <code>PooledConnection</code> has been closed or the driver determines
+ * is invalid.
+ * <p>
+ * @since 1.6
+ */
+public class StatementEvent extends EventObject {
+
+        private SQLException            exception;
+        private PreparedStatement       statement;
+
+        /**
+         * Constructs a <code>StatementEvent</code> with the specified <code>PooledConnection</code> and
+         * <code>PreparedStatement</code>.  The <code>SQLException</code> contained in the event defaults to
+         * null.
+         * <p>
+         * @param con                   The <code>PooledConnection</code> that the closed or invalid
+         * <code>PreparedStatement</code>is associated with.
+         * @param statement             The <code>PreparedStatement</code> that is bieng closed or is invalid
+         * <p>
+         * @throws IllegalArgumentException if <code>con</code> is null.
+         *
+         * @since 1.6
+         */
+        public StatementEvent(PooledConnection con,
+                                                  PreparedStatement statement) {
+
+                super(con);
+
+                this.statement = statement;
+                this.exception = null;
+        }
+
+        /**
+         * Constructs a <code>StatementEvent</code> with the specified <code>PooledConnection</code>,
+         * <code>PreparedStatement</code> and <code>SQLException</code>
+         * <p>
+         * @param con                   The <code>PooledConnection</code> that the closed or invalid <code>PreparedStatement</code>
+         * is associated with.
+         * @param statement             The <code>PreparedStatement</code> that is being closed or is invalid
+         * @param exception             The <code>SQLException </code>the driver is about to throw to
+         *                                              the application
+         *
+         * @throws IllegalArgumentException if <code>con</code> is null.
+         * <p>
+         * @since 1.6
+         */
+        public StatementEvent(PooledConnection con,
+                                                  PreparedStatement statement,
+                                                  SQLException exception) {
+
+                super(con);
+
+                this.statement = statement;
+                this.exception = exception;
+        }
+
+        /**
+         * Returns the <code>PreparedStatement</code> that is being closed or is invalid
+         * <p>
+         * @return      The <code>PreparedStatement</code> that is being closed or is invalid
+         * <p>
+         * @since 1.6
+         */
+        public PreparedStatement getStatement() {
+
+                return this.statement;
+        }
+
+        /**
+         * Returns the <code>SQLException</code> the driver is about to throw
+         * <p>
+         * @return      The <code>SQLException</code> the driver is about to throw
+         * <p>
+         * @since 1.6
+         */
+        public SQLException getSQLException() {
+
+                return this.exception;
+        }
+}
diff --git a/javax/sql/StatementEventListener.java b/javax/sql/StatementEventListener.java
new file mode 100644
index 0000000..fb3a52f
--- /dev/null
+++ b/javax/sql/StatementEventListener.java
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+
+/*
+ * Created on Apr 28, 2005
+ */
+package javax.sql;
+
+/**
+ * An object that registers to be notified of events that occur on PreparedStatements
+ * that are in the Statement pool.
+ * <p>
+ * The JDBC 3.0 specification added the maxStatements
+ * <code>ConnectionPooledDataSource</code> property to provide a standard mechanism for
+ * enabling the pooling of <code>PreparedStatements</code>
+ * and to specify the size of the statement
+ * pool.  However, there was no way for a driver to notify an external
+ * statement pool when a <code>PreparedStatement</code> becomes invalid.  For some databases, a
+ * statement becomes invalid if a DDL operation is performed that affects the
+ * table.  For example an application may create a temporary table to do some work
+ * on the table and then destroy it.  It may later recreate the same table when
+ * it is needed again.  Some databases will invalidate any prepared statements
+ * that reference the temporary table when the table is dropped.
+ * <p>
+ * Similar to the methods defined in the <code>ConnectionEventListener</code> interface,
+ * the driver will call the <code>StatementEventListener.statementErrorOccurred</code>
+ * method prior to throwing any exceptions when it detects a statement is invalid.
+ * The driver will also call the <code>StatementEventListener.statementClosed</code>
+ * method when a <code>PreparedStatement</code> is closed.
+ * <p>
+ * Methods which allow a component to register a StatementEventListener with a
+ * <code>PooledConnection</code> have been added to the <code>PooledConnection</code> interface.
+ * <p>
+ * @since 1.6
+ */
+public interface StatementEventListener  extends java.util.EventListener{
+  /**
+   * The driver calls this method on all <code>StatementEventListener</code>s registered on the connection when it detects that a
+   * <code>PreparedStatement</code> is closed.
+   *
+   * @param event an event object describing the source of
+   * the event and that the <code>PreparedStatement</code> was closed.
+   * @since 1.6
+   */
+  void statementClosed(StatementEvent event);
+
+        /**
+         * The driver calls this method on all <code>StatementEventListener</code>s
+         * registered on the connection when it detects that a
+         * <code>PreparedStatement</code> is invalid. The driver calls this method
+         * just before it throws the <code>SQLException</code>,
+         * contained in the given event, to the application.
+         * <p>
+         * @param event         an event object describing the source of the event,
+         *                                      the statement that is invalid and the exception the
+         *                                      driver is about to throw.  The source of the event is
+         *                                      the <code>PooledConnection</code> which the invalid <code>PreparedStatement</code>
+         * is associated with.
+         * <p>
+         * @since 1.6
+         */
+        void statementErrorOccurred(StatementEvent event);
+
+}
diff --git a/javax/xml/XMLConstants.java b/javax/xml/XMLConstants.java
new file mode 100644
index 0000000..dd3c515
--- /dev/null
+++ b/javax/xml/XMLConstants.java
@@ -0,0 +1,179 @@
+/*
+ * 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.
+ */
+
+// $Id: XMLConstants.java 584477 2007-10-14 02:44:03Z mrglavas $
+
+package javax.xml;
+
+/**
+ * <p>Utility class to contain basic XML values as constants.</p>
+ *
+ * @author <a href="mailto:[email protected]">Jeff Suttor</a>
+ * @version $Revision: 584477 $, $Date: 2007-10-13 19:44:03 -0700 (Sat, 13 Oct 2007) $
+ * @see <a href="http://www.w3.org/TR/xml11/">Extensible Markup Language (XML) 1.1</a>
+ * @see <a href="http://www.w3.org/TR/REC-xml">Extensible Markup Language (XML) 1.0 (Second Edition)</a>
+ * @see <a href="http://www.w3.org/XML/xml-V10-2e-errata">XML 1.0 Second Edition Specification Errata</a>
+ * @see <a href="http://www.w3.org/TR/xml-names11/">Namespaces in XML 1.1</a>
+ * @see <a href="http://www.w3.org/TR/REC-xml-names">Namespaces in XML</a>
+ * @see <a href="http://www.w3.org/XML/xml-names-19990114-errata">Namespaces in XML Errata</a>
+ * @see <a href="http://www.w3.org/TR/xmlschema-1/">XML Schema Part 1: Structures</a>
+ * @since 1.5
+ **/
+public final class XMLConstants {
+
+    /**
+     * <p>Private constructor to prevent instantiation.</p>
+     */
+    private XMLConstants() {
+    }
+
+    /**
+     * <p>Namespace URI to use to represent that there is no Namespace.</p>
+     *
+     * <p>Defined by the Namespace specification to be "".</p>
+     *
+     * @see <a href="http://www.w3.org/TR/REC-xml-names/#defaulting">
+     * Namespaces in XML, 5.2 Namespace Defaulting</a>
+     */
+    public static final String NULL_NS_URI = "";
+
+    /**
+     * <p>Prefix to use to represent the default XML Namespace.</p>
+     *
+     * <p>Defined by the XML specification to be "".</p>
+     *
+     * @see <a href="http://www.w3.org/TR/REC-xml-names/#ns-qualnames">
+     * Namespaces in XML, 3. Qualified Names</a>
+     */
+    public static final String DEFAULT_NS_PREFIX = "";
+
+    /**
+     * <p>The official XML Namespace name URI.</p>
+     *
+     * <p>Defined by the XML specification to be
+     * "<code>http://www.w3.org/XML/1998/namespace</code>".</p>
+     *
+     * @see <a href="http://www.w3.org/TR/REC-xml-names/#ns-qualnames">
+     * Namespaces in XML, 3. Qualified Names</a>
+     */
+    public static final String XML_NS_URI =
+        "http://www.w3.org/XML/1998/namespace";
+
+    /**
+     * <p>The official XML Namespace prefix.</p>
+     *
+     * <p>Defined by the XML specification to be "<code>xml</code>".</p>
+     *
+     * @see <a href="http://www.w3.org/TR/REC-xml-names/#ns-qualnames">
+     * Namespaces in XML, 3. Qualified Names</a>
+     */
+    public static final String XML_NS_PREFIX = "xml";
+
+    /**
+     * <p>The official XML attribute used for specifying XML Namespace
+     * declarations, {@link #XMLNS_ATTRIBUTE
+     * XMLConstants.XMLNS_ATTRIBUTE}, Namespace name URI.</p>
+     *
+     * <p>Defined by the XML specification to be
+     * "<code>http://www.w3.org/2000/xmlns/</code>".</p>
+     *
+     * @see <a href="http://www.w3.org/TR/REC-xml-names/#ns-qualnames">
+     * Namespaces in XML, 3. Qualified Names</a>
+     * @see <a href="http://www.w3.org/XML/xml-names-19990114-errata/">
+     * Namespaces in XML Errata</a>
+     */
+    public static final String XMLNS_ATTRIBUTE_NS_URI =
+        "http://www.w3.org/2000/xmlns/";
+
+    /**
+     * <p>The official XML attribute used for specifying XML Namespace
+     * declarations.</p>
+     *
+     * <p>It is <strong><em>NOT</em></strong> valid to use as a
+     * prefix.  Defined by the XML specification to be
+     * "<code>xmlns</code>".</p>
+     *
+     * @see <a href="http://www.w3.org/TR/REC-xml-names/#ns-qualnames">
+     * Namespaces in XML, 3. Qualified Names</a>
+     */
+    public static final String XMLNS_ATTRIBUTE = "xmlns";
+
+    /**
+     * <p>W3C XML Schema Namespace URI.</p>
+     *
+     * <p>Defined to be "<code>http://www.w3.org/2001/XMLSchema</code>".
+     *
+     * @see <a href="http://www.w3.org/TR/xmlschema-1/#Instance_Document_Constructions">
+     *  XML Schema Part 1:
+     *  Structures, 2.6 Schema-Related Markup in Documents Being Validated</a>
+     */
+    public static final String W3C_XML_SCHEMA_NS_URI =
+        "http://www.w3.org/2001/XMLSchema";
+
+    /**
+     * <p>W3C XML Schema Instance Namespace URI.</p>
+     *
+     * <p>Defined to be "<code>http://www.w3.org/2001/XMLSchema-instance</code>".</p>
+     *
+     * @see <a href="http://www.w3.org/TR/xmlschema-1/#Instance_Document_Constructions">
+     *  XML Schema Part 1:
+     *  Structures, 2.6 Schema-Related Markup in Documents Being Validated</a>
+     */
+    public static final String W3C_XML_SCHEMA_INSTANCE_NS_URI =
+        "http://www.w3.org/2001/XMLSchema-instance";
+
+    /**
+     * <p>W3C XPath Datatype Namespace URI.</p>
+     *
+     * <p>Defined to be "<code>http://www.w3.org/2003/11/xpath-datatypes</code>".</p>
+     *
+     * @see <a href="http://www.w3.org/TR/xpath-datamodel">XQuery 1.0 and XPath 2.0 Data Model</a>
+     */
+    public static final String W3C_XPATH_DATATYPE_NS_URI = "http://www.w3.org/2003/11/xpath-datatypes";
+
+    /**
+     * <p>XML Document Type Declaration Namespace URI as an arbitrary value.</p>
+     *
+     * <p>Since not formally defined by any existing standard, arbitrarily define to be "<code>http://www.w3.org/TR/REC-xml</code>".
+     */
+    public static final String XML_DTD_NS_URI = "http://www.w3.org/TR/REC-xml";
+
+    /**
+     * <p>RELAX NG Namespace URI.</p>
+     *
+     * <p>Defined to be "<code>http://relaxng.org/ns/structure/1.0</code>".</p>
+     *
+     * @see <a href="http://relaxng.org/spec-20011203.html">RELAX NG Specification</a>
+     */
+    public static final String RELAXNG_NS_URI = "http://relaxng.org/ns/structure/1.0";
+
+    /**
+     * <p>Feature for secure processing.</p>
+     *
+     * <ul>
+     *   <li>
+     *     <code>true</code> instructs the implementation to process XML securely.
+     *     This may set limits on XML constructs to avoid conditions such as denial of service attacks.
+     *   </li>
+     *   <li>
+     *     <code>false</code> instructs the implementation to process XML according to the letter of the XML specifications
+     *     ignoring security issues such as limits on XML constructs to avoid conditions such as denial of service attacks.
+     *   </li>
+     * </ul>
+     */
+    public static final String FEATURE_SECURE_PROCESSING = "http://javax.xml.XMLConstants/feature/secure-processing";
+}
diff --git a/javax/xml/datatype/DatatypeConfigurationException.java b/javax/xml/datatype/DatatypeConfigurationException.java
new file mode 100644
index 0000000..f0d3fe5
--- /dev/null
+++ b/javax/xml/datatype/DatatypeConfigurationException.java
@@ -0,0 +1,170 @@
+/*
+ * 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.
+ */
+
+// $Id: DatatypeConfigurationException.java 569987 2007-08-27 04:08:46Z mrglavas $
+
+package javax.xml.datatype;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.lang.reflect.Method;
+
+/**
+ * <p>Indicates a serious configuration error.</p>
+ *
+ * @author <a href="mailto:[email protected]">Jeff Suttor</a>
+ * @version $Revision: 569987 $, $Date: 2007-08-26 21:08:46 -0700 (Sun, 26 Aug 2007) $
+ * @since 1.5
+ */
+
+public class DatatypeConfigurationException extends Exception {
+
+    /** Stream Unique Identifier. */
+    private static final long serialVersionUID = -1699373159027047238L;
+
+    /** This field is required to store the cause on JDK 1.3 and below. */
+    private Throwable causeOnJDK13OrBelow;
+
+    /** Indicates whether this class is being used in a JDK 1.4 context. */
+    private transient boolean isJDK14OrAbove = false;
+
+    /**
+     * <p>Create a new <code>DatatypeConfigurationException</code> with
+     * no specified detail message and cause.</p>
+     */
+
+    public DatatypeConfigurationException() {
+    }
+
+    /**
+     * <p>Create a new <code>DatatypeConfigurationException</code> with
+     * the specified detail message.</p>
+     *
+     * @param message The detail message.
+     */
+
+    public DatatypeConfigurationException(String message) {
+        super(message);
+    }
+
+    /**
+     * <p>Create a new <code>DatatypeConfigurationException</code> with
+     * the specified detail message and cause.</p>
+     *
+     * @param message The detail message.
+     * @param cause The cause.  A <code>null</code> value is permitted, and indicates that the cause is nonexistent or unknown.
+     */
+
+    public DatatypeConfigurationException(String message, Throwable cause) {
+        super(message);
+        initCauseByReflection(cause);
+    }
+
+    /**
+     * <p>Create a new <code>DatatypeConfigurationException</code> with
+     * the specified cause.</p>
+     *
+     * @param cause The cause.  A <code>null</code> value is permitted, and indicates that the cause is nonexistent or unknown.
+     */
+
+    public DatatypeConfigurationException(Throwable cause) {
+        super(cause == null ? null : cause.toString());
+        initCauseByReflection(cause);
+    }
+
+    /**
+     * Print the the trace of methods from where the error
+     * originated.  This will trace all nested exception
+     * objects, as well as this object.
+     */
+    public void printStackTrace() {
+        if (!isJDK14OrAbove && causeOnJDK13OrBelow != null) {
+            printStackTrace0(new PrintWriter(System.err, true));
+        }
+        else {
+            super.printStackTrace();
+        }
+    }
+
+    /**
+     * Print the the trace of methods from where the error
+     * originated.  This will trace all nested exception
+     * objects, as well as this object.
+     * @param s The stream where the dump will be sent to.
+     */
+    public void printStackTrace(PrintStream s) {
+        if (!isJDK14OrAbove && causeOnJDK13OrBelow != null) {
+            printStackTrace0(new PrintWriter(s));
+        }
+        else {
+            super.printStackTrace(s);
+        }
+    }
+
+    /**
+     * Print the the trace of methods from where the error
+     * originated.  This will trace all nested exception
+     * objects, as well as this object.
+     * @param s The writer where the dump will be sent to.
+     */
+    public void printStackTrace(PrintWriter s) {
+        if (!isJDK14OrAbove && causeOnJDK13OrBelow != null) {
+            printStackTrace0(s);
+        }
+        else {
+            super.printStackTrace(s);
+        }
+    }
+
+    private void printStackTrace0(PrintWriter s) {
+        causeOnJDK13OrBelow.printStackTrace(s);
+        s.println("------------------------------------------");
+        super.printStackTrace(s);
+    }
+
+    private void initCauseByReflection(Throwable cause) {
+        causeOnJDK13OrBelow = cause;
+        try {
+            Method m = this.getClass().getMethod("initCause", new Class[] {Throwable.class});
+            m.invoke(this, new Object[] {cause});
+            isJDK14OrAbove = true;
+        }
+        // Ignore exception
+        catch (Exception e) {}
+    }
+
+    private void readObject(ObjectInputStream in)
+        throws IOException, ClassNotFoundException {
+        in.defaultReadObject();
+        try {
+            Method m1 = this.getClass().getMethod("getCause", new Class[] {});
+            Throwable cause = (Throwable) m1.invoke(this, new Object[] {});
+            if (causeOnJDK13OrBelow == null) {
+                causeOnJDK13OrBelow = cause;
+            }
+            else if (cause == null) {
+                Method m2 = this.getClass().getMethod("initCause", new Class[] {Throwable.class});
+                m2.invoke(this, new Object[] {causeOnJDK13OrBelow});
+            }
+            isJDK14OrAbove = true;
+        }
+        // Ignore exception
+        catch (Exception e) {}
+    }
+}
diff --git a/javax/xml/datatype/DatatypeConstants.java b/javax/xml/datatype/DatatypeConstants.java
new file mode 100644
index 0000000..4946390
--- /dev/null
+++ b/javax/xml/datatype/DatatypeConstants.java
@@ -0,0 +1,268 @@
+/*
+ * 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.
+ */
+
+// $Id: DatatypeConstants.java 446598 2006-09-15 12:55:40Z jeremias $
+
+package javax.xml.datatype;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+
+/**
+ * <p>Utility class to contain basic Datatype values as constants.</p>
+ *
+ * @author <a href="mailto:[email protected]">Jeff Suttor</a>
+ * @version $Revision: 446598 $, $Date: 2006-09-15 05:55:40 -0700 (Fri, 15 Sep 2006) $
+ * @since 1.5
+ */
+
+public final class DatatypeConstants {
+
+    /**
+     * <p>Private constructor to prevent instantiation.</p>
+     */
+    private DatatypeConstants() {
+    }
+
+    /**
+     * Value for first month of year.
+     */
+    public static final int JANUARY  = 1;
+
+    /**
+     * Value for second month of year.
+     */
+    public static final int FEBRUARY = 2;
+
+    /**
+     * Value for third month of year.
+     */
+    public static final int MARCH    = 3;
+
+    /**
+     * Value for fourth month of year.
+     */
+    public static final int APRIL    = 4;
+
+    /**
+     * Value for fifth month of year.
+     */
+    public static final int MAY      = 5;
+
+    /**
+     * Value for sixth month of year.
+     */
+    public static final int JUNE     = 6;
+
+    /**
+     * Value for seventh month of year.
+     */
+    public static final int JULY     = 7;
+
+    /**
+     * Value for eighth month of year.
+     */
+    public static final int AUGUST   = 8;
+
+    /**
+     * Value for ninth month of year.
+     */
+    public static final int SEPTEMBER = 9;
+
+    /**
+     * Value for tenth month of year.
+     */
+    public static final int OCTOBER = 10;
+
+    /**
+     * Value for eleven month of year.
+     */
+    public static final int NOVEMBER = 11;
+
+    /**
+     * Value for twelve month of year.
+     */
+    public static final int DECEMBER = 12;
+
+    /**
+     * <p>Comparison result.</p>
+     */
+    public static final int LESSER = -1;
+
+    /**
+     * <p>Comparison result.</p>
+     */
+    public static final int EQUAL =  0;
+
+    /**
+     * <p>Comparison result.</p>
+     */
+    public static final int GREATER =  1;
+
+    /**
+     * <p>Comparison result.</p>
+     */
+    public static final int INDETERMINATE =  2;
+
+    /**
+     * Designation that an "int" field is not set.
+     */
+    public static final int FIELD_UNDEFINED = Integer.MIN_VALUE;
+
+    /**
+     * <p>A constant that represents the years field.</p>
+     */
+    public static final Field YEARS = new Field("YEARS", 0);
+
+    /**
+     * <p>A constant that represents the months field.</p>
+     */
+    public static final Field MONTHS = new Field("MONTHS", 1);
+
+    /**
+     * <p>A constant that represents the days field.</p>
+     */
+    public static final Field DAYS = new Field("DAYS", 2);
+
+    /**
+     * <p>A constant that represents the hours field.</p>
+     */
+    public static final Field HOURS = new Field("HOURS", 3);
+
+    /**
+     * <p>A constant that represents the minutes field.</p>
+     */
+    public static final Field MINUTES = new Field("MINUTES", 4);
+
+    /**
+     * <p>A constant that represents the seconds field.</p>
+     */
+    public static final Field SECONDS = new Field("SECONDS", 5);
+
+    /**
+     * Type-safe enum class that represents six fields
+     * of the {@link Duration} class.
+     */
+    public static final class Field {
+
+        /**
+         * <p><code>String</code> representation of <ode>Field</code>.</p>
+         */
+        private final String str;
+        /**
+         * <p>Unique id of the field.</p>
+         *
+         * <p>This value allows the {@link Duration} class to use switch
+         * statements to process fields.</p>
+         */
+        private final int id;
+
+        /**
+         * <p>Construct a <code>Field</code> with specified values.</p>
+         * @param str <code>String</code> representation of <code>Field</code>
+         * @param id  <code>int</code> representation of <code>Field</code>
+         */
+        private Field(final String str, final int id) {
+            this.str = str;
+            this.id = id;
+        }
+        /**
+         * Returns a field name in English. This method
+         * is intended to be used for debugging/diagnosis
+         * and not for display to end-users.
+         *
+         * @return
+         *      a non-null valid String constant.
+         */
+        public String toString() { return str; }
+
+        /**
+         * <p>Get id of this Field.</p>
+         *
+         * @return Id of field.
+         */
+        public int getId() {
+            return id;
+        }
+    }
+
+    /**
+     * <p>Fully qualified name for W3C XML Schema 1.0 datatype <code>dateTime</code>.</p>
+     */
+    public static final QName DATETIME = new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "dateTime");
+
+    /**
+     * <p>Fully qualified name for W3C XML Schema 1.0 datatype <code>time</code>.</p>
+     */
+    public static final QName TIME = new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "time");
+
+    /**
+     * <p>Fully qualified name for W3C XML Schema 1.0 datatype <code>date</code>.</p>
+     */
+    public static final QName DATE = new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "date");
+
+    /**
+     * <p>Fully qualified name for W3C XML Schema 1.0 datatype <code>gYearMonth</code>.</p>
+     */
+    public static final QName GYEARMONTH = new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "gYearMonth");
+
+    /**
+     * <p>Fully qualified name for W3C XML Schema 1.0 datatype <code>gMonthDay</code>.</p>
+     */
+    public static final QName GMONTHDAY = new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "gMonthDay");
+
+    /**
+     * <p>Fully qualified name for W3C XML Schema 1.0 datatype <code>gYear</code>.</p>
+     */
+    public static final QName GYEAR = new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "gYear");
+
+    /**
+     * <p>Fully qualified name for W3C XML Schema 1.0 datatype <code>gMonth</code>.</p>
+     */
+    public static final QName GMONTH = new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "gMonth");
+
+    /**
+     * <p>Fully qualified name for W3C XML Schema 1.0 datatype <code>gDay</code>.</p>
+     */
+    public static final QName GDAY = new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "gDay");
+
+    /**
+     * <p>Fully qualified name for W3C XML Schema datatype <code>duration</code>.</p>
+     */
+    public static final QName DURATION = new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "duration");
+
+    /**
+     * <p>Fully qualified name for XQuery 1.0 and XPath 2.0 datatype <code>dayTimeDuration</code>.</p>
+     */
+    public static final QName DURATION_DAYTIME = new QName(XMLConstants.W3C_XPATH_DATATYPE_NS_URI, "dayTimeDuration");
+
+    /**
+     * <p>Fully qualified name for XQuery 1.0 and XPath 2.0 datatype <code>yearMonthDuration</code>.</p>
+     */
+    public static final QName DURATION_YEARMONTH = new QName(XMLConstants.W3C_XPATH_DATATYPE_NS_URI, "yearMonthDuration");
+
+    /**
+     * W3C XML Schema max timezone offset is -14:00. Zone offset is in minutes.
+     */
+    public static final int MAX_TIMEZONE_OFFSET = -14 * 60;
+
+    /**
+     * W3C XML Schema min timezone offset is +14:00. Zone offset is in minutes.
+     */
+    public static final int MIN_TIMEZONE_OFFSET = 14 * 60;
+
+}
diff --git a/javax/xml/datatype/DatatypeFactory.java b/javax/xml/datatype/DatatypeFactory.java
new file mode 100644
index 0000000..29cf490
--- /dev/null
+++ b/javax/xml/datatype/DatatypeFactory.java
@@ -0,0 +1,1027 @@
+/*
+ * 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.
+ */
+
+//$Id: DatatypeFactory.java 884950 2009-11-27 18:46:18Z mrglavas $
+
+package javax.xml.datatype;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.GregorianCalendar;
+
+/**
+ * <p>Factory that creates new <code>javax.xml.datatype</code> <code>Object</code>s that map XML to/from Java <code>Object</code>s.</p>
+ *
+ * <p id="DatatypeFactory.newInstance">{@link #newInstance()} is used to create a new <code>DatatypeFactory</code>.
+ * The following implementation resolution mechanisms are used in the following order:</p>
+ * <ol>
+ *    <li>
+ *      If the system property specified by {@link #DATATYPEFACTORY_PROPERTY}, "<code>javax.xml.datatype.DatatypeFactory</code>",
+ *      exists, a class with the name of the property's value is instantiated.
+ *      Any Exception thrown during the instantiation process is wrapped as a {@link DatatypeConfigurationException}.
+ *    </li>
+ *    <li>
+ *      If the file ${JAVA_HOME}/lib/jaxp.properties exists, it is loaded in a {@link java.util.Properties} <code>Object</code>.
+ *      The <code>Properties</code> <code>Object </code> is then queried for the property as documented in the prior step
+ *      and processed as documented in the prior step.
+ *    </li>
+ *    <li>
+ *      The services resolution mechanism is used, e.g. <code>META-INF/services/java.xml.datatype.DatatypeFactory</code>.
+ *      Any Exception thrown during the instantiation process is wrapped as a {@link DatatypeConfigurationException}.
+ *    </li>
+ *    <li>
+ *      The final mechanism is to attempt to instantiate the <code>Class</code> specified by
+ *      {@link #DATATYPEFACTORY_IMPLEMENTATION_CLASS}, "<code>javax.xml.datatype.DatatypeFactoryImpl</code>".
+ *      Any Exception thrown during the instantiation process is wrapped as a {@link DatatypeConfigurationException}.
+ *    </li>
+ * </ol>
+ *
+ * <p>Note that you must supply your own implementation (such as Xerces); Android does not ship with a default implementation.
+ *
+ * @author <a href="mailto:[email protected]">Joseph Fialli</a>
+ * @author <a href="mailto:[email protected]">Jeff Suttor</a>
+ * @version $Revision: 884950 $, $Date: 2009-11-27 10:46:18 -0800 (Fri, 27 Nov 2009) $
+ * @since 1.5
+ */
+public abstract class DatatypeFactory {
+
+    /**
+     * <p>Default property name as defined in JSR 206: Java(TM) API for XML Processing (JAXP) 1.3.</p>
+     *
+     * <p>Default value is <code>javax.xml.datatype.DatatypeFactory</code>.</p>
+     */
+    public static final String DATATYPEFACTORY_PROPERTY = "javax.xml.datatype.DatatypeFactory";
+
+    /**
+     * <p>Default implementation class name as defined in JSR 206: Java(TM) API for XML Processing (JAXP) 1.3.</p>
+     *
+     * <p>Default value is <code>org.apache.xerces.jaxp.datatype.DatatypeFactoryImpl</code>.</p>
+     */
+    // This uses "new String" to avoid being inlined as a constant.
+    public static final String DATATYPEFACTORY_IMPLEMENTATION_CLASS = new String("org.apache.xerces.jaxp.datatype.DatatypeFactoryImpl");
+
+    /**
+     * <p>Protected constructor to prevent instantiation outside of package.</p>
+     *
+     * <p>Use {@link #newInstance()} to create a <code>DatatypeFactory</code>.</p>
+     */
+    protected DatatypeFactory() {}
+
+    /**
+     * <p>Obtain a new instance of a <code>DatatypeFactory</code>.</p>
+     *
+     * <p>The implementation resolution mechanisms are <a href="#DatatypeFactory.newInstance">defined</a> in this
+     * <code>Class</code>'s documentation.</p>
+     * <p>Note that you must supply your own implementation (such as Xerces); Android does not ship with a default implementation.
+     *
+     * @return New instance of a <code>DocumentBuilderFactory</code>
+     *
+     * @throws DatatypeConfigurationException If the implementation is not
+     *   available or cannot be instantiated.
+     */
+    public static DatatypeFactory newInstance()
+        throws DatatypeConfigurationException {
+        try {
+            return (DatatypeFactory) FactoryFinder.find(
+                    /* The default property name according to the JAXP spec */
+                    DATATYPEFACTORY_PROPERTY,
+                    /* The fallback implementation class name */
+                    DATATYPEFACTORY_IMPLEMENTATION_CLASS);
+        }
+        catch (FactoryFinder.ConfigurationError e) {
+            throw new DatatypeConfigurationException(e.getMessage(), e.getException());
+        }
+    }
+
+    /**
+     * Returns an instance of the named implementation of {@code DatatypeFactory}.
+     *
+     * @throws DatatypeConfigurationException if {@code factoryClassName} is not available or cannot
+     *     be instantiated.
+     * @since 1.6
+     */
+    public static DatatypeFactory newInstance(String factoryClassName, ClassLoader classLoader)
+            throws DatatypeConfigurationException {
+        if (factoryClassName == null) {
+            throw new DatatypeConfigurationException("factoryClassName == null");
+        }
+        if (classLoader == null) {
+            classLoader = Thread.currentThread().getContextClassLoader();
+        }
+        try {
+            Class<?> type = classLoader != null
+                    ? classLoader.loadClass(factoryClassName)
+                    : Class.forName(factoryClassName);
+            return (DatatypeFactory) type.newInstance();
+        } catch (ClassNotFoundException e) {
+            throw new DatatypeConfigurationException(e);
+        } catch (InstantiationException e) {
+            throw new DatatypeConfigurationException(e);
+        } catch (IllegalAccessException e) {
+            throw new DatatypeConfigurationException(e);
+        }
+    }
+
+    /**
+     * <p>Obtain a new instance of a <code>Duration</code>
+     * specifying the <code>Duration</code> as its string representation, "PnYnMnDTnHnMnS",
+     * as defined in XML Schema 1.0 section 3.2.6.1.</p>
+     *
+     * <p>XML Schema Part 2: Datatypes, 3.2.6 duration, defines <code>duration</code> as:</p>
+     * <blockquote>
+     * duration represents a duration of time.
+     * The value space of duration is a six-dimensional space where the coordinates designate the
+     * Gregorian year, month, day, hour, minute, and second components defined in Section 5.5.3.2 of [ISO 8601], respectively.
+     * These components are ordered in their significance by their order of appearance i.e. as
+     * year, month, day, hour, minute, and second.
+     * </blockquote>
+     * <p>All six values are set and available from the created {@link Duration}</p>
+     *
+     * <p>The XML Schema specification states that values can be of an arbitrary size.
+     * Implementations may chose not to or be incapable of supporting arbitrarily large and/or small values.
+     * An {@link UnsupportedOperationException} will be thrown with a message indicating implementation limits
+     * if implementation capacities are exceeded.</p>
+     *
+     * @param lexicalRepresentation <code>String</code> representation of a <code>Duration</code>.
+     *
+     * @return New <code>Duration</code> created from parsing the <code>lexicalRepresentation</code>.
+     *
+     * @throws IllegalArgumentException If <code>lexicalRepresentation</code> is not a valid representation of a <code>Duration</code>.
+     * @throws UnsupportedOperationException If implementation cannot support requested values.
+     * @throws NullPointerException if <code>lexicalRepresentation</code> is <code>null</code>.
+     */
+    public abstract Duration newDuration(final String lexicalRepresentation);
+
+    /**
+     * <p>Obtain a new instance of a <code>Duration</code>
+     * specifying the <code>Duration</code> as milliseconds.</p>
+     *
+     * <p>XML Schema Part 2: Datatypes, 3.2.6 duration, defines <code>duration</code> as:</p>
+     * <blockquote>
+     * duration represents a duration of time.
+     * The value space of duration is a six-dimensional space where the coordinates designate the
+     * Gregorian year, month, day, hour, minute, and second components defined in Section 5.5.3.2 of [ISO 8601], respectively.
+     * These components are ordered in their significance by their order of appearance i.e. as
+     * year, month, day, hour, minute, and second.
+     * </blockquote>
+     * <p>All six values are set by computing their values from the specified milliseconds
+     * and are available using the <code>get</code> methods of  the created {@link Duration}.
+     * The values conform to and are defined by:</p>
+     * <ul>
+     *   <li>ISO 8601:2000(E) Section 5.5.3.2 Alternative format</li>
+     *   <li><a href="http://www.w3.org/TR/xmlschema-2/#isoformats">
+     *     W3C XML Schema 1.0 Part 2, Appendix D, ISO 8601 Date and Time Formats</a>
+     *   </li>
+     *   <li>{@link XMLGregorianCalendar}  Date/Time Datatype Field Mapping Between XML Schema 1.0 and Java Representation</li>
+     * </ul>
+     *
+     * <p>The default start instance is defined by {@link GregorianCalendar}'s use of the start of the epoch: i.e.,
+     * {@link java.util.Calendar#YEAR} = 1970,
+     * {@link java.util.Calendar#MONTH} = {@link java.util.Calendar#JANUARY},
+     * {@link java.util.Calendar#DATE} = 1, etc.
+     * This is important as there are variations in the Gregorian Calendar,
+     * e.g. leap years have different days in the month = {@link java.util.Calendar#FEBRUARY}
+     * so the result of {@link Duration#getMonths()} and {@link Duration#getDays()} can be influenced.</p>
+     *
+     * @param durationInMilliSeconds Duration in milliseconds to create.
+     *
+     * @return New <code>Duration</code> representing <code>durationInMilliSeconds</code>.
+     */
+    public abstract Duration newDuration(final long durationInMilliSeconds);
+
+    /**
+     * <p>Obtain a new instance of a <code>Duration</code>
+     * specifying the <code>Duration</code> as isPositive, years, months, days, hours, minutes, seconds.</p>
+     *
+     * <p>The XML Schema specification states that values can be of an arbitrary size.
+     * Implementations may chose not to or be incapable of supporting arbitrarily large and/or small values.
+     * An {@link UnsupportedOperationException} will be thrown with a message indicating implementation limits
+     * if implementation capacities are exceeded.</p>
+     *
+     * <p>A <code>null</code> value indicates that field is not set.</p>
+     *
+     * @param isPositive Set to <code>false</code> to create a negative duration. When the length
+     *   of the duration is zero, this parameter will be ignored.
+     * @param years of this <code>Duration</code>
+     * @param months of this <code>Duration</code>
+     * @param days of this <code>Duration</code>
+     * @param hours of this <code>Duration</code>
+     * @param minutes of this <code>Duration</code>
+     * @param seconds of this <code>Duration</code>
+     *
+     * @return New <code>Duration</code> created from the specified values.
+     *
+     * @throws IllegalArgumentException If values are not a valid representation of a <code>Duration</code>.
+     * @throws UnsupportedOperationException If implementation cannot support requested values.
+     */
+    public abstract Duration newDuration(
+            final boolean isPositive,
+            final BigInteger years,
+            final BigInteger months,
+            final BigInteger days,
+            final BigInteger hours,
+            final BigInteger minutes,
+            final BigDecimal seconds);
+
+    /**
+     * <p>Obtain a new instance of a <code>Duration</code>
+     * specifying the <code>Duration</code> as isPositive, years, months, days, hours, minutes, seconds.</p>
+     *
+     * <p>A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.</p>
+     *
+     * @param isPositive Set to <code>false</code> to create a negative duration. When the length
+     *   of the duration is zero, this parameter will be ignored.
+     * @param years of this <code>Duration</code>
+     * @param months of this <code>Duration</code>
+     * @param days of this <code>Duration</code>
+     * @param hours of this <code>Duration</code>
+     * @param minutes of this <code>Duration</code>
+     * @param seconds of this <code>Duration</code>
+     *
+     * @return New <code>Duration</code> created from the specified values.
+     *
+     * @throws IllegalArgumentException If values are not a valid representation of a <code>Duration</code>.
+     *
+     * @see #newDuration(
+     *   boolean isPositive,
+     *   BigInteger years,
+     *   BigInteger months,
+     *   BigInteger days,
+     *   BigInteger hours,
+     *   BigInteger minutes,
+     *   BigDecimal seconds)
+     */
+    public Duration newDuration(
+            final boolean isPositive,
+            final int years,
+            final int months,
+            final int days,
+            final int hours,
+            final int minutes,
+            final int seconds) {
+
+        // years may not be set
+        BigInteger realYears = (years != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) years) : null;
+
+        // months may not be set
+        BigInteger realMonths = (months != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) months) : null;
+
+        // days may not be set
+        BigInteger realDays = (days != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) days) : null;
+
+        // hours may not be set
+        BigInteger realHours = (hours != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) hours) : null;
+
+        // minutes may not be set
+        BigInteger realMinutes = (minutes != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) minutes) : null;
+
+        // seconds may not be set
+        BigDecimal realSeconds = (seconds != DatatypeConstants.FIELD_UNDEFINED) ? BigDecimal.valueOf((long) seconds) : null;
+
+        return newDuration(
+                isPositive,
+                realYears,
+                realMonths,
+                realDays,
+                realHours,
+                realMinutes,
+                realSeconds
+        );
+    }
+
+    /**
+     * <p>Create a <code>Duration</code> of type <code>xdt:dayTimeDuration</code> by parsing its <code>String</code> representation,
+     * "<em>PnDTnHnMnS</em>", <a href="http://www.w3.org/TR/xpath-datamodel#dt-dayTimeDuration">
+     *   XQuery 1.0 and XPath 2.0 Data Model, xdt:dayTimeDuration</a>.</p>
+     *
+     * <p>The datatype <code>xdt:dayTimeDuration</code> is a subtype of <code>xs:duration</code>
+     * whose lexical representation contains only day, hour, minute, and second components.
+     * This datatype resides in the namespace <code>http://www.w3.org/2003/11/xpath-datatypes</code>.</p>
+     *
+     * <p>All four values are set and available from the created {@link Duration}</p>
+     *
+     * <p>The XML Schema specification states that values can be of an arbitrary size.
+     * Implementations may chose not to or be incapable of supporting arbitrarily large and/or small values.
+     * An {@link UnsupportedOperationException} will be thrown with a message indicating implementation limits
+     * if implementation capacities are exceeded.</p>
+     *
+     * @param lexicalRepresentation Lexical representation of a duration.
+     *
+     * @return New <code>Duration</code> created using the specified <code>lexicalRepresentation</code>.
+     *
+     * @throws IllegalArgumentException If the given string does not conform to the aforementioned specification.
+     * @throws UnsupportedOperationException If implementation cannot support requested values.
+     * @throws NullPointerException If <code>lexicalRepresentation</code> is <code>null</code>.
+     */
+    public Duration newDurationDayTime(final String lexicalRepresentation) {
+        if (lexicalRepresentation == null) {
+            throw new NullPointerException("lexicalRepresentation == null");
+        }
+        // The lexical representation must match the pattern [^YM]*(T.*)?
+        int pos = lexicalRepresentation.indexOf('T');
+        int length = (pos >= 0) ? pos : lexicalRepresentation.length();
+        for (int i = 0; i < length; ++i) {
+            char c = lexicalRepresentation.charAt(i);
+            if (c == 'Y' || c == 'M') {
+                throw new IllegalArgumentException("Invalid dayTimeDuration value: " + lexicalRepresentation);
+            }
+        }
+        return newDuration(lexicalRepresentation);
+    }
+
+    /**
+     * <p>Create a <code>Duration</code> of type <code>xdt:dayTimeDuration</code> using the specified milliseconds as defined in
+     * <a href="http://www.w3.org/TR/xpath-datamodel#dt-dayTimeDuration">
+     *   XQuery 1.0 and XPath 2.0 Data Model, xdt:dayTimeDuration</a>.</p>
+     *
+     * <p>The datatype <code>xdt:dayTimeDuration</code> is a subtype of <code>xs:duration</code>
+     * whose lexical representation contains only day, hour, minute, and second components.
+     * This datatype resides in the namespace <code>http://www.w3.org/2003/11/xpath-datatypes</code>.</p>
+     *
+     * <p>All four values are set by computing their values from the specified milliseconds
+     * and are available using the <code>get</code> methods of  the created {@link Duration}.
+     * The values conform to and are defined by:</p>
+     * <ul>
+     *   <li>ISO 8601:2000(E) Section 5.5.3.2 Alternative format</li>
+     *   <li><a href="http://www.w3.org/TR/xmlschema-2/#isoformats">
+     *     W3C XML Schema 1.0 Part 2, Appendix D, ISO 8601 Date and Time Formats</a>
+     *   </li>
+     *   <li>{@link XMLGregorianCalendar}  Date/Time Datatype Field Mapping Between XML Schema 1.0 and Java Representation</li>
+     * </ul>
+     *
+     * <p>The default start instance is defined by {@link GregorianCalendar}'s use of the start of the epoch: i.e.,
+     * {@link java.util.Calendar#YEAR} = 1970,
+     * {@link java.util.Calendar#MONTH} = {@link java.util.Calendar#JANUARY},
+     * {@link java.util.Calendar#DATE} = 1, etc.
+     * This is important as there are variations in the Gregorian Calendar,
+     * e.g. leap years have different days in the month = {@link java.util.Calendar#FEBRUARY}
+     * so the result of {@link Duration#getDays()} can be influenced.</p>
+     *
+     * <p>Any remaining milliseconds after determining the day, hour, minute and second are discarded.</p>
+     *
+     * @param durationInMilliseconds Milliseconds of <code>Duration</code> to create.
+     *
+     * @return New <code>Duration</code> created with the specified <code>durationInMilliseconds</code>.
+     *
+     * @see <a href="http://www.w3.org/TR/xpath-datamodel#dt-dayTimeDuration">
+     *   XQuery 1.0 and XPath 2.0 Data Model, xdt:dayTimeDuration</a>
+     */
+    public Duration newDurationDayTime(final long durationInMilliseconds) {
+        long _durationInMilliseconds = durationInMilliseconds;
+        if (_durationInMilliseconds == 0) {
+            return newDuration(true, DatatypeConstants.FIELD_UNDEFINED,
+                    DatatypeConstants.FIELD_UNDEFINED, 0, 0, 0, 0);
+        }
+        boolean tooLong = false;
+        final boolean isPositive;
+        if (_durationInMilliseconds < 0) {
+            isPositive = false;
+            if (_durationInMilliseconds == Long.MIN_VALUE) {
+                _durationInMilliseconds++;
+                tooLong = true;
+            }
+            _durationInMilliseconds *= -1;
+        }
+        else {
+            isPositive = true;
+        }
+
+        long val = _durationInMilliseconds;
+        int milliseconds = (int) (val % 60000L); // 60000 milliseconds per minute
+        if (tooLong) {
+            ++milliseconds;
+        }
+        if (milliseconds % 1000 == 0) {
+            int seconds = milliseconds / 1000;
+            val = val / 60000L;
+            int minutes = (int) (val % 60L); // 60 minutes per hour
+            val = val / 60L;
+            int hours = (int) (val % 24L); // 24 hours per day
+            long days = val / 24L;
+            if (days <= ((long) Integer.MAX_VALUE)) {
+                return newDuration(isPositive, DatatypeConstants.FIELD_UNDEFINED,
+                        DatatypeConstants.FIELD_UNDEFINED, (int) days, hours, minutes, seconds);
+            }
+            else {
+                return newDuration(isPositive, null, null,
+                        BigInteger.valueOf(days), BigInteger.valueOf(hours),
+                        BigInteger.valueOf(minutes), BigDecimal.valueOf(milliseconds, 3));
+            }
+        }
+
+        BigDecimal seconds = BigDecimal.valueOf(milliseconds, 3);
+        val = val / 60000L;
+        BigInteger minutes = BigInteger.valueOf(val % 60L); // 60 minutes per hour
+        val = val / 60L;
+        BigInteger hours = BigInteger.valueOf(val % 24L); // 24 hours per day
+        val = val / 24L;
+        BigInteger days = BigInteger.valueOf(val);
+        return newDuration(isPositive, null, null, days, hours, minutes, seconds);
+    }
+
+    /**
+     * <p>Create a <code>Duration</code> of type <code>xdt:dayTimeDuration</code> using the specified
+     * <code>day</code>, <code>hour</code>, <code>minute</code> and <code>second</code> as defined in
+     * <a href="http://www.w3.org/TR/xpath-datamodel#dt-dayTimeDuration">
+     *   XQuery 1.0 and XPath 2.0 Data Model, xdt:dayTimeDuration</a>.</p>
+     *
+     * <p>The datatype <code>xdt:dayTimeDuration</code> is a subtype of <code>xs:duration</code>
+     * whose lexical representation contains only day, hour, minute, and second components.
+     * This datatype resides in the namespace <code>http://www.w3.org/2003/11/xpath-datatypes</code>.</p>
+     *
+     * <p>The XML Schema specification states that values can be of an arbitrary size.
+     * Implementations may chose not to or be incapable of supporting arbitrarily large and/or small values.
+     * An {@link UnsupportedOperationException} will be thrown with a message indicating implementation limits
+     * if implementation capacities are exceeded.</p>
+     *
+     * <p>A <code>null</code> value indicates that field is not set.</p>
+     *
+     * @param isPositive Set to <code>false</code> to create a negative duration. When the length
+     *   of the duration is zero, this parameter will be ignored.
+     * @param day Day of <code>Duration</code>.
+     * @param hour Hour of <code>Duration</code>.
+     * @param minute Minute of <code>Duration</code>.
+     * @param second Second of <code>Duration</code>.
+     *
+     * @return New <code>Duration</code> created with the specified <code>day</code>, <code>hour</code>, <code>minute</code>
+     * and <code>second</code>.
+     *
+     * @throws IllegalArgumentException If any values would create an invalid <code>Duration</code>.
+     * @throws UnsupportedOperationException If implementation cannot support requested values.
+     */
+    public Duration newDurationDayTime(
+            final boolean isPositive,
+            final BigInteger day,
+            final BigInteger hour,
+            final BigInteger minute,
+            final BigInteger second) {
+
+        return newDuration(
+                isPositive,
+                null,  // years
+                null, // months
+                day,
+                hour,
+                minute,
+                (second != null)? new BigDecimal(second):null
+        );
+    }
+
+    /**
+     * <p>Create a <code>Duration</code> of type <code>xdt:dayTimeDuration</code> using the specified
+     * <code>day</code>, <code>hour</code>, <code>minute</code> and <code>second</code> as defined in
+     * <a href="http://www.w3.org/TR/xpath-datamodel#dt-dayTimeDuration">
+     *   XQuery 1.0 and XPath 2.0 Data Model, xdt:dayTimeDuration</a>.</p>
+     *
+     * <p>The datatype <code>xdt:dayTimeDuration</code> is a subtype of <code>xs:duration</code>
+     * whose lexical representation contains only day, hour, minute, and second components.
+     * This datatype resides in the namespace <code>http://www.w3.org/2003/11/xpath-datatypes</code>.</p>
+     *
+     * <p>A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.</p>
+     *
+     * @param isPositive Set to <code>false</code> to create a negative duration. When the length
+     *   of the duration is zero, this parameter will be ignored.
+     * @param day Day of <code>Duration</code>.
+     * @param hour Hour of <code>Duration</code>.
+     * @param minute Minute of <code>Duration</code>.
+     * @param second Second of <code>Duration</code>.
+     *
+     * @return New <code>Duration</code> created with the specified <code>day</code>, <code>hour</code>, <code>minute</code>
+     * and <code>second</code>.
+     *
+     * @throws IllegalArgumentException If any values would create an invalid <code>Duration</code>.
+     */
+    public Duration newDurationDayTime(
+            final boolean isPositive,
+            final int day,
+            final int hour,
+            final int minute,
+            final int second) {
+        return newDuration(isPositive,
+                DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED,
+                day, hour, minute, second);
+    }
+
+    /**
+     * <p>Create a <code>Duration</code> of type <code>xdt:yearMonthDuration</code> by parsing its <code>String</code> representation,
+     * "<em>PnYnM</em>", <a href="http://www.w3.org/TR/xpath-datamodel#dt-yearMonthDuration">
+     *   XQuery 1.0 and XPath 2.0 Data Model, xdt:yearMonthDuration</a>.</p>
+     *
+     * <p>The datatype <code>xdt:yearMonthDuration</code> is a subtype of <code>xs:duration</code>
+     * whose lexical representation contains only year and month components.
+     * This datatype resides in the namespace {@link javax.xml.XMLConstants#W3C_XPATH_DATATYPE_NS_URI}.</p>
+     *
+     * <p>Both values are set and available from the created {@link Duration}</p>
+     *
+     * <p>The XML Schema specification states that values can be of an arbitrary size.
+     * Implementations may chose not to or be incapable of supporting arbitrarily large and/or small values.
+     * An {@link UnsupportedOperationException} will be thrown with a message indicating implementation limits
+     * if implementation capacities are exceeded.</p>
+     *
+     * @param lexicalRepresentation Lexical representation of a duration.
+     *
+     * @return New <code>Duration</code> created using the specified <code>lexicalRepresentation</code>.
+     *
+     * @throws IllegalArgumentException If the <code>lexicalRepresentation</code> does not conform to the specification.
+     * @throws UnsupportedOperationException If implementation cannot support requested values.
+     * @throws NullPointerException If <code>lexicalRepresentation</code> is <code>null</code>.
+     */
+    public Duration newDurationYearMonth(final String lexicalRepresentation) {
+        if (lexicalRepresentation == null) {
+            throw new NullPointerException("lexicalRepresentation == null");
+        }
+        // The lexical representation must match the pattern [^DT]*.
+        int length = lexicalRepresentation.length();
+        for (int i = 0; i < length; ++i) {
+            char c = lexicalRepresentation.charAt(i);
+            if (c == 'D' || c == 'T') {
+                throw new IllegalArgumentException("Invalid yearMonthDuration value: " + lexicalRepresentation);
+            }
+        }
+        return newDuration(lexicalRepresentation);
+    }
+
+    /**
+     * <p>Create a <code>Duration</code> of type <code>xdt:yearMonthDuration</code> using the specified milliseconds as defined in
+     * <a href="http://www.w3.org/TR/xpath-datamodel#dt-yearMonthDuration">
+     *   XQuery 1.0 and XPath 2.0 Data Model, xdt:yearMonthDuration</a>.</p>
+     *
+     * <p>The datatype <code>xdt:yearMonthDuration</code> is a subtype of <code>xs:duration</code>
+     * whose lexical representation contains only year and month components.
+     * This datatype resides in the namespace {@link javax.xml.XMLConstants#W3C_XPATH_DATATYPE_NS_URI}.</p>
+     *
+     * <p>Both values are set by computing their values from the specified milliseconds
+     * and are available using the <code>get</code> methods of  the created {@link Duration}.
+     * The values conform to and are defined by:</p>
+     * <ul>
+     *   <li>ISO 8601:2000(E) Section 5.5.3.2 Alternative format</li>
+     *   <li><a href="http://www.w3.org/TR/xmlschema-2/#isoformats">
+     *     W3C XML Schema 1.0 Part 2, Appendix D, ISO 8601 Date and Time Formats</a>
+     *   </li>
+     *   <li>{@link XMLGregorianCalendar}  Date/Time Datatype Field Mapping Between XML Schema 1.0 and Java Representation</li>
+     * </ul>
+     *
+     * <p>The default start instance is defined by {@link GregorianCalendar}'s use of the start of the epoch: i.e.,
+     * {@link java.util.Calendar#YEAR} = 1970,
+     * {@link java.util.Calendar#MONTH} = {@link java.util.Calendar#JANUARY},
+     * {@link java.util.Calendar#DATE} = 1, etc.
+     * This is important as there are variations in the Gregorian Calendar,
+     * e.g. leap years have different days in the month = {@link java.util.Calendar#FEBRUARY}
+     * so the result of {@link Duration#getMonths()} can be influenced.</p>
+     *
+     * <p>Any remaining milliseconds after determining the year and month are discarded.</p>
+     *
+     * @param durationInMilliseconds Milliseconds of <code>Duration</code> to create.
+     *
+     * @return New <code>Duration</code> created using the specified <code>durationInMilliseconds</code>.
+     */
+    public Duration newDurationYearMonth(final long durationInMilliseconds) {
+
+        return newDuration(durationInMilliseconds);
+    }
+
+    /**
+     * <p>Create a <code>Duration</code> of type <code>xdt:yearMonthDuration</code> using the specified
+     * <code>year</code> and <code>month</code> as defined in
+     * <a href="http://www.w3.org/TR/xpath-datamodel#dt-yearMonthyDuration">
+     *   XQuery 1.0 and XPath 2.0 Data Model, xdt:yearMonthDuration</a>.</p>
+     *
+     * <p>The XML Schema specification states that values can be of an arbitrary size.
+     * Implementations may chose not to or be incapable of supporting arbitrarily large and/or small values.
+     * An {@link UnsupportedOperationException} will be thrown with a message indicating implementation limits
+     * if implementation capacities are exceeded.</p>
+     *
+     * <p>A <code>null</code> value indicates that field is not set.</p>
+     *
+     * @param isPositive Set to <code>false</code> to create a negative duration. When the length
+     *   of the duration is zero, this parameter will be ignored.
+     * @param year Year of <code>Duration</code>.
+     * @param month Month of <code>Duration</code>.
+     *
+     * @return New <code>Duration</code> created using the specified <code>year</code> and <code>month</code>.
+     *
+     * @throws IllegalArgumentException If any values would create an invalid <code>Duration</code>.
+     * @throws UnsupportedOperationException If implementation cannot support requested values.
+     */
+    public Duration newDurationYearMonth(
+            final boolean isPositive,
+            final BigInteger year,
+            final BigInteger month) {
+
+        return newDuration(
+                isPositive,
+                year,
+                month,
+                null, // days
+                null, // hours
+                null, // minutes
+                null  // seconds
+        );
+    }
+
+    /**
+     * <p>Create a <code>Duration</code> of type <code>xdt:yearMonthDuration</code> using the specified
+     * <code>year</code> and <code>month</code> as defined in
+     * <a href="http://www.w3.org/TR/xpath-datamodel#dt-yearMonthyDuration">
+     *   XQuery 1.0 and XPath 2.0 Data Model, xdt:yearMonthDuration</a>.</p>
+     *
+     * <p>A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.</p>
+     *
+     * @param isPositive Set to <code>false</code> to create a negative duration. When the length
+     *   of the duration is zero, this parameter will be ignored.
+     * @param year Year of <code>Duration</code>.
+     * @param month Month of <code>Duration</code>.
+     *
+     * @return New <code>Duration</code> created using the specified <code>year</code> and <code>month</code>.
+     *
+     * @throws IllegalArgumentException If any values would create an invalid <code>Duration</code>.
+     */
+    public Duration newDurationYearMonth(
+            final boolean isPositive,
+            final int year,
+            final int month) {
+        return newDuration(isPositive, year, month,
+                DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED,
+                DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED);
+    }
+
+    /**
+     * <p>Create a new instance of an <code>XMLGregorianCalendar</code>.</p>
+     *
+     * <p>All date/time datatype fields set to {@link DatatypeConstants#FIELD_UNDEFINED} or null.</p>
+     *
+     * @return New <code>XMLGregorianCalendar</code> with all date/time datatype fields set to
+     *   {@link DatatypeConstants#FIELD_UNDEFINED} or null.
+     */
+    public abstract XMLGregorianCalendar newXMLGregorianCalendar();
+
+    /**
+     * <p>Create a new XMLGregorianCalendar by parsing the String as a lexical representation.</p>
+     *
+     * <p>Parsing the lexical string representation is defined in
+     * <a href="http://www.w3.org/TR/xmlschema-2/#dateTime-order">XML Schema 1.0 Part 2, Section 3.2.[7-14].1,
+     * <em>Lexical Representation</em>.</a></p>
+     *
+     * <p>The string representation may not have any leading and trailing whitespaces.</p>
+     *
+     * <p>The parsing is done field by field so that
+     * the following holds for any lexically correct String x:</p>
+     * <pre>
+     * newXMLGregorianCalendar(x).toXMLFormat().equals(x)
+     * </pre>
+     * <p>Except for the noted lexical/canonical representation mismatches
+     * listed in <a href="http://www.w3.org/2001/05/xmlschema-errata#e2-45">
+     * XML Schema 1.0 errata, Section 3.2.7.2</a>.</p>
+     *
+     * @param lexicalRepresentation Lexical representation of one the eight XML Schema date/time datatypes.
+     *
+     * @return <code>XMLGregorianCalendar</code> created from the <code>lexicalRepresentation</code>.
+     *
+     * @throws IllegalArgumentException If the <code>lexicalRepresentation</code> is not a valid <code>XMLGregorianCalendar</code>.
+     * @throws NullPointerException If <code>lexicalRepresentation</code> is <code>null</code>.
+     */
+    public abstract XMLGregorianCalendar newXMLGregorianCalendar(final String lexicalRepresentation);
+
+    /**
+     * <p>Create an <code>XMLGregorianCalendar</code> from a {@link GregorianCalendar}.</p>
+     *
+     * <table border="2" rules="all" cellpadding="2">
+     *   <thead>
+     *     <tr>
+     *       <th align="center" colspan="2">
+     *          Field by Field Conversion from
+     *          {@link GregorianCalendar} to an {@link XMLGregorianCalendar}
+     *       </th>
+     *     </tr>
+     *     <tr>
+     *        <th><code>java.util.GregorianCalendar</code> field</th>
+     *        <th><code>javax.xml.datatype.XMLGregorianCalendar</code> field</th>
+     *     </tr>
+     *   </thead>
+     *   <tbody>
+     *     <tr>
+     *       <td><code>ERA == GregorianCalendar.BC ? -YEAR : YEAR</code></td>
+     *       <td>{@link XMLGregorianCalendar#setYear(int year)}</td>
+     *     </tr>
+     *     <tr>
+     *       <td><code>MONTH + 1</code></td>
+     *       <td>{@link XMLGregorianCalendar#setMonth(int month)}</td>
+     *     </tr>
+     *     <tr>
+     *       <td><code>DAY_OF_MONTH</code></td>
+     *       <td>{@link XMLGregorianCalendar#setDay(int day)}</td>
+     *     </tr>
+     *     <tr>
+     *       <td><code>HOUR_OF_DAY, MINUTE, SECOND, MILLISECOND</code></td>
+     *       <td>{@link XMLGregorianCalendar#setTime(int hour, int minute, int second, BigDecimal fractional)}</td>
+     *     </tr>
+     *     <tr>
+     *       <td>
+     *         <code>(ZONE_OFFSET + DST_OFFSET) / (60*1000)</code><br/>
+     *         <em>(in minutes)</em>
+     *       </td>
+     *       <td>{@link XMLGregorianCalendar#setTimezone(int offset)}<sup><em>*</em></sup>
+     *       </td>
+     *     </tr>
+     *   </tbody>
+     * </table>
+     * <p><em>*</em>conversion loss of information. It is not possible to represent
+     * a <code>java.util.GregorianCalendar</code> daylight savings timezone id in the
+     * XML Schema 1.0 date/time datatype representation.</p>
+     *
+     * <p>To compute the return value's <code>TimeZone</code> field,
+     * <ul>
+     * <li>when <code>this.getTimezone() != FIELD_UNDEFINED</code>,
+     * create a <code>java.util.TimeZone</code> with a custom timezone id
+     * using the <code>this.getTimezone()</code>.</li>
+     * <li>else use the <code>GregorianCalendar</code> default timezone value
+     * for the host is defined as specified by
+     * <code>java.util.TimeZone.getDefault()</code>.</li></p>
+     *
+     * @param cal <code>java.util.GregorianCalendar</code> used to create <code>XMLGregorianCalendar</code>
+     *
+     * @return <code>XMLGregorianCalendar</code> created from <code>java.util.GregorianCalendar</code>
+     *
+     * @throws NullPointerException If <code>cal</code> is <code>null</code>.
+     */
+    public abstract XMLGregorianCalendar newXMLGregorianCalendar(final GregorianCalendar cal);
+
+    /**
+     * <p>Constructor allowing for complete value spaces allowed by
+     * W3C XML Schema 1.0 recommendation for xsd:dateTime and related
+     * builtin datatypes. Note that <code>year</code> parameter supports
+     * arbitrarily large numbers and fractionalSecond has infinite
+     * precision.</p>
+     *
+     * <p>A <code>null</code> value indicates that field is not set.</p>
+     *
+     * @param year of <code>XMLGregorianCalendar</code> to be created.
+     * @param month of <code>XMLGregorianCalendar</code> to be created.
+     * @param day of <code>XMLGregorianCalendar</code> to be created.
+     * @param hour of <code>XMLGregorianCalendar</code> to be created.
+     * @param minute of <code>XMLGregorianCalendar</code> to be created.
+     * @param second of <code>XMLGregorianCalendar</code> to be created.
+     * @param fractionalSecond of <code>XMLGregorianCalendar</code> to be created.
+     * @param timezone of <code>XMLGregorianCalendar</code> to be created.
+     *
+     * @return <code>XMLGregorianCalendar</code> created from specified values.
+     *
+     * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field
+     *   as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar}
+     *   or if the composite values constitute an invalid <code>XMLGregorianCalendar</code> instance
+     *   as determined by {@link XMLGregorianCalendar#isValid()}.
+     */
+    public abstract XMLGregorianCalendar newXMLGregorianCalendar(
+            final BigInteger year,
+            final int month,
+            final int day,
+            final int hour,
+            final int minute,
+            final int second,
+            final BigDecimal fractionalSecond,
+            final int timezone);
+
+    /**
+     * <p>Constructor of value spaces that a
+     * <code>java.util.GregorianCalendar</code> instance would need to convert to an
+     * <code>XMLGregorianCalendar</code> instance.</p>
+     *
+     * <p><code>XMLGregorianCalendar eon</code> and
+     * <code>fractionalSecond</code> are set to <code>null</code></p>
+     *
+     * <p>A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.</p>
+     *
+     * @param year of <code>XMLGregorianCalendar</code> to be created.
+     * @param month of <code>XMLGregorianCalendar</code> to be created.
+     * @param day of <code>XMLGregorianCalendar</code> to be created.
+     * @param hour of <code>XMLGregorianCalendar</code> to be created.
+     * @param minute of <code>XMLGregorianCalendar</code> to be created.
+     * @param second of <code>XMLGregorianCalendar</code> to be created.
+     * @param millisecond of <code>XMLGregorianCalendar</code> to be created.
+     * @param timezone of <code>XMLGregorianCalendar</code> to be created.
+     *
+     * @return <code>XMLGregorianCalendar</code> created from specified values.
+     *
+     * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field
+     *   as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar}
+     *   or if the composite values constitute an invalid <code>XMLGregorianCalendar</code> instance
+     *   as determined by {@link XMLGregorianCalendar#isValid()}.
+     */
+    public XMLGregorianCalendar newXMLGregorianCalendar(
+            final int year,
+            final int month,
+            final int day,
+            final int hour,
+            final int minute,
+            final int second,
+            final int millisecond,
+            final int timezone) {
+
+        // year may be undefined
+        BigInteger realYear = (year != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) year) : null;
+
+        // millisecond may be undefined
+        // millisecond must be >= 0 millisecond <= 1000
+        BigDecimal realMillisecond = null; // undefined value
+        if (millisecond != DatatypeConstants.FIELD_UNDEFINED) {
+            if (millisecond < 0 || millisecond > 1000) {
+                throw new IllegalArgumentException(
+                        "javax.xml.datatype.DatatypeFactory#newXMLGregorianCalendar("
+                        + "int year, int month, int day, int hour, int minute, int second, int millisecond, int timezone)"
+                        + "with invalid millisecond: " + millisecond
+                );
+            }
+            realMillisecond = BigDecimal.valueOf((long) millisecond, 3);
+        }
+
+        return newXMLGregorianCalendar(
+                realYear,
+                month,
+                day,
+                hour,
+                minute,
+                second,
+                realMillisecond,
+                timezone
+        );
+    }
+
+    /**
+     * <p>Create a Java representation of XML Schema builtin datatype <code>date</code> or <code>g*</code>.</p>
+     *
+     * <p>For example, an instance of <code>gYear</code> can be created invoking this factory
+     * with <code>month</code> and <code>day</code> parameters set to
+     * {@link DatatypeConstants#FIELD_UNDEFINED}.</p>
+     *
+     * <p>A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.</p>
+     *
+     * @param year of <code>XMLGregorianCalendar</code> to be created.
+     * @param month of <code>XMLGregorianCalendar</code> to be created.
+     * @param day of <code>XMLGregorianCalendar</code> to be created.
+     * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set.
+     *
+     * @return <code>XMLGregorianCalendar</code> created from parameter values.
+     *
+     * @see DatatypeConstants#FIELD_UNDEFINED
+     *
+     * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field
+     *   as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar}
+     *   or if the composite values constitute an invalid <code>XMLGregorianCalendar</code> instance
+     *   as determined by {@link XMLGregorianCalendar#isValid()}.
+     */
+    public XMLGregorianCalendar newXMLGregorianCalendarDate(
+            final int year,
+            final int month,
+            final int day,
+            final int timezone) {
+
+        return newXMLGregorianCalendar(
+                year,
+                month,
+                day,
+                DatatypeConstants.FIELD_UNDEFINED, // hour
+                DatatypeConstants.FIELD_UNDEFINED, // minute
+                DatatypeConstants.FIELD_UNDEFINED, // second
+                DatatypeConstants.FIELD_UNDEFINED, // millisecond
+                timezone);
+    }
+
+    /**
+     * <p>Create a Java instance of XML Schema builtin datatype <code>time</code>.</p>
+     *
+     * <p>A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.</p>
+     *
+     * @param hours number of hours
+     * @param minutes number of minutes
+     * @param seconds number of seconds
+     * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set.
+     *
+     * @return <code>XMLGregorianCalendar</code> created from parameter values.
+     *
+     * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field
+     *   as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar}
+     *   or if the composite values constitute an invalid <code>XMLGregorianCalendar</code> instance
+     *   as determined by {@link XMLGregorianCalendar#isValid()}.
+     *
+     * @see DatatypeConstants#FIELD_UNDEFINED
+     */
+    public XMLGregorianCalendar newXMLGregorianCalendarTime(
+            final int hours,
+            final int minutes,
+            final int seconds,
+            final int timezone) {
+
+        return newXMLGregorianCalendar(
+                DatatypeConstants.FIELD_UNDEFINED, // Year
+                DatatypeConstants.FIELD_UNDEFINED, // Month
+                DatatypeConstants.FIELD_UNDEFINED, // Day
+                hours,
+                minutes,
+                seconds,
+                DatatypeConstants.FIELD_UNDEFINED, //Millisecond
+                timezone);
+    }
+
+    /**
+     * <p>Create a Java instance of XML Schema builtin datatype time.</p>
+     *
+     * <p>A <code>null</code> value indicates that field is not set.</p>
+     * <p>A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.</p>
+     *
+     * @param hours number of hours
+     * @param minutes number of minutes
+     * @param seconds number of seconds
+     * @param fractionalSecond value of <code>null</code> indicates that this optional field is not set.
+     * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set.
+     *
+     * @return <code>XMLGregorianCalendar</code> created from parameter values.
+     *
+     * @see DatatypeConstants#FIELD_UNDEFINED
+     *
+     * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field
+     *   as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar}
+     *   or if the composite values constitute an invalid <code>XMLGregorianCalendar</code> instance
+     *   as determined by {@link XMLGregorianCalendar#isValid()}.
+     */
+    public XMLGregorianCalendar newXMLGregorianCalendarTime(
+            final int hours,
+            final int minutes,
+            final int seconds,
+            final BigDecimal fractionalSecond,
+            final int timezone) {
+
+        return newXMLGregorianCalendar(
+                null, // year
+                DatatypeConstants.FIELD_UNDEFINED, // month
+                DatatypeConstants.FIELD_UNDEFINED, // day
+                hours,
+                minutes,
+                seconds,
+                fractionalSecond,
+                timezone);
+    }
+
+    /**
+     * <p>Create a Java instance of XML Schema builtin datatype time.</p>
+     *
+     * <p>A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.</p>
+     *
+     * @param hours number of hours
+     * @param minutes number of minutes
+     * @param seconds number of seconds
+     * @param milliseconds number of milliseconds
+     * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set.
+     *
+     * @return <code>XMLGregorianCalendar</code> created from parameter values.
+     *
+     * @see DatatypeConstants#FIELD_UNDEFINED
+     *
+     * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field
+     *   as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar}
+     *   or if the composite values constitute an invalid <code>XMLGregorianCalendar</code> instance
+     *   as determined by {@link XMLGregorianCalendar#isValid()}.
+     */
+    public XMLGregorianCalendar newXMLGregorianCalendarTime(
+            final int hours,
+            final int minutes,
+            final int seconds,
+            final int milliseconds,
+            final int timezone) {
+
+        // millisecond may be undefined
+        // millisecond must be >= 0 millisecond <= 1000
+        BigDecimal realMilliseconds = null; // undefined value
+        if (milliseconds != DatatypeConstants.FIELD_UNDEFINED) {
+            if (milliseconds < 0 || milliseconds > 1000) {
+                throw new IllegalArgumentException(
+                        "javax.xml.datatype.DatatypeFactory#newXMLGregorianCalendarTime("
+                        + "int hours, int minutes, int seconds, int milliseconds, int timezone)"
+                        + "with invalid milliseconds: " + milliseconds
+                );
+            }
+            realMilliseconds = BigDecimal.valueOf((long) milliseconds, 3);
+        }
+
+        return newXMLGregorianCalendarTime(
+                hours,
+                minutes,
+                seconds,
+                realMilliseconds,
+                timezone
+        );
+    }
+}
diff --git a/javax/xml/datatype/Duration.java b/javax/xml/datatype/Duration.java
new file mode 100644
index 0000000..fcdd4c5
--- /dev/null
+++ b/javax/xml/datatype/Duration.java
@@ -0,0 +1,980 @@
+/*
+ * 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.
+ */
+
+//$Id: Duration.java 759828 2009-03-30 01:26:29Z mrglavas $
+
+package javax.xml.datatype;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import javax.xml.namespace.QName;
+
+/**
+ * <p>Immutable representation of a time span as defined in
+ * the W3C XML Schema 1.0 specification.</p>
+ *
+ * <p>A Duration object represents a period of Gregorian time,
+ * which consists of six fields (years, months, days, hours,
+ * minutes, and seconds) plus a sign (+/-) field.</p>
+ *
+ * <p>The first five fields have non-negative (>=0) integers or null
+ * (which represents that the field is not set),
+ * and the seconds field has a non-negative decimal or null.
+ * A negative sign indicates a negative duration.</p>
+ *
+ * <p>This class provides a number of methods that make it easy
+ * to use for the duration datatype of XML Schema 1.0 with
+ * the errata.</p>
+ *
+ * <h2>Order relationship</h2>
+ * <p>Duration objects only have partial order, where two values A and B
+ * maybe either:</p>
+ * <ol>
+ *  <li>A&lt;B (A is shorter than B)
+ *  <li>A&gt;B (A is longer than B)
+ *  <li>A==B   (A and B are of the same duration)
+ *  <li>A&lt;>B (Comparison between A and B is indeterminate)
+ * </ol>
+ *
+ * <p>For example, 30 days cannot be meaningfully compared to one month.
+ * The {@link #compare(Duration duration)} method implements this
+ * relationship.</p>
+ *
+ * <p>See the {@link #isLongerThan(Duration)} method for details about
+ * the order relationship among <code>Duration</code> objects.</p>
+ *
+ * <h2>Operations over Duration</h2>
+ * <p>This class provides a set of basic arithmetic operations, such
+ * as addition, subtraction and multiplication.
+ * Because durations don't have total order, an operation could
+ * fail for some combinations of operations. For example, you cannot
+ * subtract 15 days from 1 month. See the javadoc of those methods
+ * for detailed conditions where this could happen.</p>
+ *
+ * <p>Also, division of a duration by a number is not provided because
+ * the <code>Duration</code> class can only deal with finite precision
+ * decimal numbers. For example, one cannot represent 1 sec divided by 3.</p>
+ *
+ * <p>However, you could substitute a division by 3 with multiplying
+ * by numbers such as 0.3 or 0.333.</p>
+ *
+ * <h2>Range of allowed values</h2>
+ * <p>
+ * Because some operations of <code>Duration</code> rely on {@link Calendar}
+ * even though {@link Duration} can hold very large or very small values,
+ * some of the methods may not work correctly on such <code>Duration</code>s.
+ * The impacted methods document their dependency on {@link Calendar}.
+ *
+ *
+ * @author <a href="mailto:[email protected]">Joseph Fialli</a>
+ * @author <a href="mailto:[email protected]">Kohsuke Kawaguchi</a>
+ * @author <a href="mailto:[email protected]">Jeff Suttor</a>
+ * @version $Revision: 759828 $, $Date: 2009-03-29 18:26:29 -0700 (Sun, 29 Mar 2009) $
+ * @see XMLGregorianCalendar#add(Duration)
+ * @since 1.5
+ */
+public abstract class   Duration {
+
+    /**
+     * <p>Return the name of the XML Schema date/time type that this instance
+     * maps to. Type is computed based on fields that are set,
+     * i.e. {@link #isSet(DatatypeConstants.Field field)} == <code>true</code>.</p>
+     *
+     * <table border="2" rules="all" cellpadding="2">
+     *   <thead>
+     *     <tr>
+     *       <th align="center" colspan="7">
+     *         Required fields for XML Schema 1.0 Date/Time Datatypes.<br/>
+     *         <i>(timezone is optional for all date/time datatypes)</i>
+     *       </th>
+     *     </tr>
+     *   </thead>
+     *   <tbody>
+     *     <tr>
+     *       <td>Datatype</td>
+     *       <td>year</td>
+     *       <td>month</td>
+     *       <td>day</td>
+     *       <td>hour</td>
+     *       <td>minute</td>
+     *       <td>second</td>
+     *     </tr>
+     *     <tr>
+     *       <td>{@link DatatypeConstants#DURATION}</td>
+     *       <td>X</td>
+     *       <td>X</td>
+     *       <td>X</td>
+     *       <td>X</td>
+     *       <td>X</td>
+     *       <td>X</td>
+     *     </tr>
+     *     <tr>
+     *       <td>{@link DatatypeConstants#DURATION_DAYTIME}</td>
+     *       <td></td>
+     *       <td></td>
+     *       <td>X</td>
+     *       <td>X</td>
+     *       <td>X</td>
+     *       <td>X</td>
+     *     </tr>
+     *     <tr>
+     *       <td>{@link DatatypeConstants#DURATION_YEARMONTH}</td>
+     *       <td>X</td>
+     *       <td>X</td>
+     *       <td></td>
+     *       <td></td>
+     *       <td></td>
+     *       <td></td>
+     *     </tr>
+     *   </tbody>
+     * </table>
+     *
+     * @return one of the following constants:
+     *   {@link DatatypeConstants#DURATION},
+     *   {@link DatatypeConstants#DURATION_DAYTIME} or
+     *   {@link DatatypeConstants#DURATION_YEARMONTH}.
+     *
+     * @throws IllegalStateException If the combination of set fields does not match one of the XML Schema date/time datatypes.
+     */
+    public QName getXMLSchemaType() {
+
+        boolean yearSet = isSet(DatatypeConstants.YEARS);
+        boolean monthSet = isSet(DatatypeConstants.MONTHS);
+        boolean daySet = isSet(DatatypeConstants.DAYS);
+        boolean hourSet = isSet(DatatypeConstants.HOURS);
+        boolean minuteSet = isSet(DatatypeConstants.MINUTES);
+        boolean secondSet = isSet(DatatypeConstants.SECONDS);
+
+        // DURATION
+        if (yearSet
+                && monthSet
+                && daySet
+                && hourSet
+                && minuteSet
+                && secondSet) {
+            return DatatypeConstants.DURATION;
+        }
+
+        // DURATION_DAYTIME
+        if (!yearSet
+                && !monthSet
+                && daySet
+                && hourSet
+                && minuteSet
+                && secondSet) {
+            return DatatypeConstants.DURATION_DAYTIME;
+        }
+
+        // DURATION_YEARMONTH
+        if (yearSet
+                && monthSet
+                && !daySet
+                && !hourSet
+                && !minuteSet
+                && !secondSet) {
+            return DatatypeConstants.DURATION_YEARMONTH;
+        }
+
+        // nothing matches
+        throw new IllegalStateException(
+                "javax.xml.datatype.Duration#getXMLSchemaType():"
+                + " this Duration does not match one of the XML Schema date/time datatypes:"
+                + " year set = " + yearSet
+                + " month set = " + monthSet
+                + " day set = " + daySet
+                + " hour set = " + hourSet
+                + " minute set = " + minuteSet
+                + " second set = " + secondSet
+        );
+    }
+
+    /**
+     * Returns the sign of this duration in -1,0, or 1.
+     *
+     * @return
+     *      -1 if this duration is negative, 0 if the duration is zero,
+     *      and 1 if the duration is positive.
+     */
+    public abstract int getSign();
+
+    /**
+     * <p>Get the years value of this <code>Duration</code> as an <code>int</code> or <code>0</code> if not present.</p>
+     *
+     * <p><code>getYears()</code> is a convenience method for
+     * {@link #getField(DatatypeConstants.Field field) getField(DatatypeConstants.YEARS)}.</p>
+     *
+     * <p>As the return value is an <code>int</code>, an incorrect value will be returned for <code>Duration</code>s
+     * with years that go beyond the range of an <code>int</code>.
+     * Use {@link #getField(DatatypeConstants.Field field) getField(DatatypeConstants.YEARS)} to avoid possible loss of precision.</p>
+     *
+     * @return If the years field is present, return its value as an <code>int</code>, else return <code>0</code>.
+     */
+    public int getYears() {
+        return getFieldValueAsInt(DatatypeConstants.YEARS);
+    }
+
+    /**
+     * Obtains the value of the MONTHS field as an integer value,
+     * or 0 if not present.
+     *
+     * This method works just like {@link #getYears()} except
+     * that this method works on the MONTHS field.
+     *
+     * @return Months of this <code>Duration</code>.
+     */
+    public int getMonths() {
+        return getFieldValueAsInt(DatatypeConstants.MONTHS);
+    }
+
+    /**
+     * Obtains the value of the DAYS field as an integer value,
+     * or 0 if not present.
+     *
+     * This method works just like {@link #getYears()} except
+     * that this method works on the DAYS field.
+     *
+     * @return Days of this <code>Duration</code>.
+     */
+    public int getDays() {
+        return getFieldValueAsInt(DatatypeConstants.DAYS);
+    }
+
+    /**
+     * Obtains the value of the HOURS field as an integer value,
+     * or 0 if not present.
+     *
+     * This method works just like {@link #getYears()} except
+     * that this method works on the HOURS field.
+     *
+     * @return Hours of this <code>Duration</code>.
+     *
+     */
+    public int getHours() {
+        return getFieldValueAsInt(DatatypeConstants.HOURS);
+    }
+
+    /**
+     * Obtains the value of the MINUTES field as an integer value,
+     * or 0 if not present.
+     *
+     * This method works just like {@link #getYears()} except
+     * that this method works on the MINUTES field.
+     *
+     * @return Minutes of this <code>Duration</code>.
+     *
+     */
+    public int getMinutes() {
+        return getFieldValueAsInt(DatatypeConstants.MINUTES);
+    }
+
+    /**
+     * Obtains the value of the SECONDS field as an integer value,
+     * or 0 if not present.
+     *
+     * This method works just like {@link #getYears()} except
+     * that this method works on the SECONDS field.
+     *
+     * @return seconds in the integer value. The fraction of seconds
+     *   will be discarded (for example, if the actual value is 2.5,
+     *   this method returns 2)
+     */
+    public int getSeconds() {
+        return getFieldValueAsInt(DatatypeConstants.SECONDS);
+    }
+
+    /**
+     * <p>Returns the length of the duration in milliseconds.</p>
+     *
+     * <p>If the seconds field carries more digits than millisecond order,
+     * those will be simply discarded (or in other words, rounded to zero.)
+     * For example, for any Calendar value <code>x</code>,</p>
+     * <pre>
+     * <code>new Duration("PT10.00099S").getTimeInMills(x) == 10000</code>.
+     * <code>new Duration("-PT10.00099S").getTimeInMills(x) == -10000</code>.
+     * </pre>
+     *
+     * <p>
+     * Note that this method uses the {@link #addTo(Calendar)} method,
+     * which may work incorrectly with <code>Duration</code> objects with
+     * very large values in its fields. See the {@link #addTo(Calendar)}
+     * method for details.
+     *
+     * @param startInstant
+     *      The length of a month/year varies. The <code>startInstant</code> is
+     *      used to disambiguate this variance. Specifically, this method
+     *      returns the difference between <code>startInstant</code> and
+     *      <code>startInstant+duration</code>
+     *
+     * @return milliseconds between <code>startInstant</code> and
+     *   <code>startInstant</code> plus this <code>Duration</code>
+     *
+     * @throws NullPointerException if <code>startInstant</code> parameter
+     * is null.
+     *
+     */
+    public long getTimeInMillis(final Calendar startInstant) {
+        Calendar cal = (Calendar) startInstant.clone();
+        addTo(cal);
+        return getCalendarTimeInMillis(cal)
+        - getCalendarTimeInMillis(startInstant);
+    }
+
+    /**
+     * <p>Returns the length of the duration in milliseconds.</p>
+     *
+     * <p>If the seconds field carries more digits than millisecond order,
+     * those will be simply discarded (or in other words, rounded to zero.)
+     * For example, for any <code>Date</code> value <code>x</code>,</p>
+     * <pre>
+     * <code>new Duration("PT10.00099S").getTimeInMills(x) == 10000</code>.
+     * <code>new Duration("-PT10.00099S").getTimeInMills(x) == -10000</code>.
+     * </pre>
+     *
+     * <p>
+     * Note that this method uses the {@link #addTo(Date)} method,
+     * which may work incorrectly with <code>Duration</code> objects with
+     * very large values in its fields. See the {@link #addTo(Date)}
+     * method for details.
+     *
+     * @param startInstant
+     *      The length of a month/year varies. The <code>startInstant</code> is
+     *      used to disambiguate this variance. Specifically, this method
+     *      returns the difference between <code>startInstant</code> and
+     *      <code>startInstant+duration</code>.
+     *
+     * @throws NullPointerException
+     *      If the startInstant parameter is null.
+     *
+     * @return milliseconds between <code>startInstant</code> and
+     *   <code>startInstant</code> plus this <code>Duration</code>
+     *
+     * @see #getTimeInMillis(Calendar)
+     */
+    public long getTimeInMillis(final Date startInstant) {
+        Calendar cal = new GregorianCalendar();
+        cal.setTime(startInstant);
+        this.addTo(cal);
+        return getCalendarTimeInMillis(cal) - startInstant.getTime();
+    }
+
+    /**
+     * Gets the value of a field.
+     *
+     * Fields of a duration object may contain arbitrary large value.
+     * Therefore this method is designed to return a {@link Number} object.
+     *
+     * In case of YEARS, MONTHS, DAYS, HOURS, and MINUTES, the returned
+     * number will be a non-negative integer. In case of seconds,
+     * the returned number may be a non-negative decimal value.
+     *
+     * @param field
+     *      one of the six Field constants (YEARS,MONTHS,DAYS,HOURS,
+     *      MINUTES, or SECONDS.)
+     * @return
+     *      If the specified field is present, this method returns
+     *      a non-null non-negative {@link Number} object that
+     *      represents its value. If it is not present, return null.
+     *      For YEARS, MONTHS, DAYS, HOURS, and MINUTES, this method
+     *      returns a {@link java.math.BigInteger} object. For SECONDS, this
+     *      method returns a {@link java.math.BigDecimal}.
+     *
+     * @throws NullPointerException If the <code>field</code> is <code>null</code>.
+     */
+    public abstract Number getField(final DatatypeConstants.Field field);
+
+    /**
+     * Gets the value of a field as an <code>int</code>.
+     *
+     * @param field
+     *      one of the six Field constants (YEARS,MONTHS,DAYS,HOURS,
+     *      MINUTES, or SECONDS.)
+     * @return
+     *      If the field is present, return its value as an <code>int</code>,
+     *      else return <code>0</code>.
+     */
+    private int getFieldValueAsInt(final DatatypeConstants.Field field) {
+        Number n = getField(field);
+        if (n != null) {
+            return n.intValue();
+        }
+        return 0;
+    }
+
+    /**
+     * Checks if a field is set.
+     *
+     * A field of a duration object may or may not be present.
+     * This method can be used to test if a field is present.
+     *
+     * @param field
+     *      one of the six Field constants (YEARS,MONTHS,DAYS,HOURS,
+     *      MINUTES, or SECONDS.)
+     * @return
+     *      true if the field is present. false if not.
+     *
+     * @throws NullPointerException
+     *      If the field parameter is null.
+     */
+    public abstract boolean isSet(final DatatypeConstants.Field field);
+
+    /**
+     * <p>Computes a new duration whose value is <code>this+rhs</code>.</p>
+     *
+     * <p>For example,</p>
+     * <pre>
+     * "1 day" + "-3 days" = "-2 days"
+     * "1 year" + "1 day" = "1 year and 1 day"
+     * "-(1 hour,50 minutes)" + "-20 minutes" = "-(1 hours,70 minutes)"
+     * "15 hours" + "-3 days" = "-(2 days,9 hours)"
+     * "1 year" + "-1 day" = IllegalStateException
+     * </pre>
+     *
+     * <p>Since there's no way to meaningfully subtract 1 day from 1 month,
+     * there are cases where the operation fails in
+     * {@link IllegalStateException}.</p>
+     *
+     * <p>
+     * Formally, the computation is defined as follows.</p>
+     * <p>
+     * Firstly, we can assume that two <code>Duration</code>s to be added
+     * are both positive without losing generality (i.e.,
+     * <code>(-X)+Y=Y-X</code>, <code>X+(-Y)=X-Y</code>,
+     * <code>(-X)+(-Y)=-(X+Y)</code>)
+     *
+     * <p>
+     * Addition of two positive <code>Duration</code>s are simply defined as
+     * field by field addition where missing fields are treated as 0.
+     * <p>
+     * A field of the resulting <code>Duration</code> will be unset if and
+     * only if respective fields of two input <code>Duration</code>s are unset.
+     * <p>
+     * Note that <code>lhs.add(rhs)</code> will be always successful if
+     * <code>lhs.signum()*rhs.signum()!=-1</code> or both of them are
+     * normalized.</p>
+     *
+     * @param rhs <code>Duration</code> to add to this <code>Duration</code>
+     *
+     * @return
+     *      non-null valid Duration object.
+     *
+     * @throws NullPointerException
+     *      If the rhs parameter is null.
+     * @throws IllegalStateException
+     *      If two durations cannot be meaningfully added. For
+     *      example, adding negative one day to one month causes
+     *      this exception.
+     *
+     *
+     * @see #subtract(Duration)
+     */
+    public abstract Duration add(final Duration rhs);
+
+    /**
+     * Adds this duration to a {@link Calendar} object.
+     *
+     * <p>
+     * Calls {@link java.util.Calendar#add(int,int)} in the
+     * order of YEARS, MONTHS, DAYS, HOURS, MINUTES, SECONDS, and MILLISECONDS
+     * if those fields are present. Because the {@link Calendar} class
+     * uses int to hold values, there are cases where this method
+     * won't work correctly (for example if values of fields
+     * exceed the range of int.)
+     * </p>
+     *
+     * <p>
+     * Also, since this duration class is a Gregorian duration, this
+     * method will not work correctly if the given {@link Calendar}
+     * object is based on some other calendar systems.
+     * </p>
+     *
+     * <p>
+     * Any fractional parts of this <code>Duration</code> object
+     * beyond milliseconds will be simply ignored. For example, if
+     * this duration is "P1.23456S", then 1 is added to SECONDS,
+     * 234 is added to MILLISECONDS, and the rest will be unused.
+     * </p>
+     *
+     * <p>
+     * Note that because {@link Calendar#add(int, int)} is using
+     * <tt>int</tt>, <code>Duration</code> with values beyond the
+     * range of <tt>int</tt> in its fields
+     * will cause overflow/underflow to the given {@link Calendar}.
+     * {@link XMLGregorianCalendar#add(Duration)} provides the same
+     * basic operation as this method while avoiding
+     * the overflow/underflow issues.
+     *
+     * @param calendar
+     *      A calendar object whose value will be modified.
+     * @throws NullPointerException
+     *      if the calendar parameter is null.
+     */
+    public abstract void addTo(Calendar calendar);
+
+    /**
+     * Adds this duration to a {@link Date} object.
+     *
+     * <p>
+     * The given date is first converted into
+     * a {@link java.util.GregorianCalendar}, then the duration
+     * is added exactly like the {@link #addTo(Calendar)} method.
+     *
+     * <p>
+     * The updated time instant is then converted back into a
+     * {@link Date} object and used to update the given {@link Date} object.
+     *
+     * <p>
+     * This somewhat redundant computation is necessary to unambiguously
+     * determine the duration of months and years.
+     *
+     * @param date
+     *      A date object whose value will be modified.
+     * @throws NullPointerException
+     *      if the date parameter is null.
+     */
+    public void addTo(Date date) {
+
+        // check data parameter
+        if (date == null) {
+            throw new NullPointerException("date == null");
+        }
+
+        Calendar cal = new GregorianCalendar();
+        cal.setTime(date);
+        this.addTo(cal);
+        date.setTime(getCalendarTimeInMillis(cal));
+    }
+
+    /**
+     * <p>Computes a new duration whose value is <code>this-rhs</code>.</p>
+     *
+     * <p>For example:</p>
+     * <pre>
+     * "1 day" - "-3 days" = "4 days"
+     * "1 year" - "1 day" = IllegalStateException
+     * "-(1 hour,50 minutes)" - "-20 minutes" = "-(1hours,30 minutes)"
+     * "15 hours" - "-3 days" = "3 days and 15 hours"
+     * "1 year" - "-1 day" = "1 year and 1 day"
+     * </pre>
+     *
+     * <p>Since there's no way to meaningfully subtract 1 day from 1 month,
+     * there are cases where the operation fails in {@link IllegalStateException}.</p>
+     *
+     * <p>Formally the computation is defined as follows.
+     * First, we can assume that two <code>Duration</code>s are both positive
+     * without losing generality.  (i.e.,
+     * <code>(-X)-Y=-(X+Y)</code>, <code>X-(-Y)=X+Y</code>,
+     * <code>(-X)-(-Y)=-(X-Y)</code>)</p>
+     *
+     * <p>Then two durations are subtracted field by field.
+     * If the sign of any non-zero field <tt>F</tt> is different from
+     * the sign of the most significant field,
+     * 1 (if <tt>F</tt> is negative) or -1 (otherwise)
+     * will be borrowed from the next bigger unit of <tt>F</tt>.</p>
+     *
+     * <p>This process is repeated until all the non-zero fields have
+     * the same sign.</p>
+     *
+     * <p>If a borrow occurs in the days field (in other words, if
+     * the computation needs to borrow 1 or -1 month to compensate
+     * days), then the computation fails by throwing an
+     * {@link IllegalStateException}.</p>
+     *
+     * @param rhs <code>Duration</code> to subtract from this <code>Duration</code>.
+     *
+     * @return New <code>Duration</code> created from subtracting <code>rhs</code> from this <code>Duration</code>.
+     *
+     * @throws IllegalStateException
+     *      If two durations cannot be meaningfully subtracted. For
+     *      example, subtracting one day from one month causes
+     *      this exception.
+     *
+     * @throws NullPointerException
+     *      If the rhs parameter is null.
+     *
+     * @see #add(Duration)
+     */
+    public Duration subtract(final Duration rhs) {
+        return add(rhs.negate());
+    }
+
+    /**
+     * <p>Computes a new duration whose value is <code>factor</code> times
+     * longer than the value of this duration.</p>
+     *
+     * <p>This method is provided for the convenience.
+     * It is functionally equivalent to the following code:</p>
+     * <pre>
+     * multiply(new BigDecimal(String.valueOf(factor)))
+     * </pre>
+     *
+     * @param factor Factor times longer of new <code>Duration</code> to create.
+     *
+     * @return New <code>Duration</code> that is <code>factor</code>times longer than this <code>Duration</code>.
+     *
+     * @see #multiply(BigDecimal)
+     */
+    public Duration multiply(int factor) {
+        return multiply(BigDecimal.valueOf(factor));
+    }
+
+    /**
+     * Computes a new duration whose value is <code>factor</code> times
+     * longer than the value of this duration.
+     *
+     * <p>
+     * For example,
+     * <pre>
+     * "P1M" (1 month) * "12" = "P12M" (12 months)
+     * "PT1M" (1 min) * "0.3" = "PT18S" (18 seconds)
+     * "P1M" (1 month) * "1.5" = IllegalStateException
+     * </pre>
+     *
+     * <p>
+     * Since the <code>Duration</code> class is immutable, this method
+     * doesn't change the value of this object. It simply computes
+     * a new Duration object and returns it.
+     *
+     * <p>
+     * The operation will be performed field by field with the precision
+     * of {@link BigDecimal}. Since all the fields except seconds are
+     * restricted to hold integers,
+     * any fraction produced by the computation will be
+     * carried down toward the next lower unit. For example,
+     * if you multiply "P1D" (1 day) with "0.5", then it will be 0.5 day,
+     * which will be carried down to "PT12H" (12 hours).
+     * When fractions of month cannot be meaningfully carried down
+     * to days, or year to months, this will cause an
+     * {@link IllegalStateException} to be thrown.
+     * For example if you multiple one month by 0.5.</p>
+     *
+     * <p>
+     * To avoid {@link IllegalStateException}, use
+     * the {@link #normalizeWith(Calendar)} method to remove the years
+     * and months fields.
+     *
+     * @param factor to multiply by
+     *
+     * @return
+     *      returns a non-null valid <code>Duration</code> object
+     *
+     * @throws IllegalStateException if operation produces fraction in
+     * the months field.
+     *
+     * @throws NullPointerException if the <code>factor</code> parameter is
+     * <code>null</code>.
+     *
+     */
+    public abstract Duration multiply(final BigDecimal factor);
+
+    /**
+     * Returns a new <code>Duration</code> object whose
+     * value is <code>-this</code>.
+     *
+     * <p>
+     * Since the <code>Duration</code> class is immutable, this method
+     * doesn't change the value of this object. It simply computes
+     * a new Duration object and returns it.
+     *
+     * @return
+     *      always return a non-null valid <code>Duration</code> object.
+     */
+    public abstract Duration negate();
+
+    /**
+     * <p>Converts the years and months fields into the days field
+     * by using a specific time instant as the reference point.</p>
+     *
+     * <p>For example, duration of one month normalizes to 31 days
+     * given the start time instance "July 8th 2003, 17:40:32".</p>
+     *
+     * <p>Formally, the computation is done as follows:</p>
+     * <ol>
+     *  <li>the given Calendar object is cloned</li>
+     *  <li>the years, months and days fields will be added to the {@link Calendar} object
+     *      by using the {@link Calendar#add(int,int)} method</li>
+     *  <li>the difference between the two Calendars in computed in milliseconds and converted to days,
+     *     if a remainder occurs due to Daylight Savings Time, it is discarded</li>
+     *  <li>the computed days, along with the hours, minutes and seconds
+     *      fields of this duration object is used to construct a new
+     *      Duration object.</li>
+     * </ol>
+     *
+     * <p>Note that since the Calendar class uses <code>int</code> to
+     * hold the value of year and month, this method may produce
+     * an unexpected result if this duration object holds
+     * a very large value in the years or months fields.</p>
+     *
+     * @param startTimeInstant <code>Calendar</code> reference point.
+     *
+     * @return <code>Duration</code> of years and months of this <code>Duration</code> as days.
+     *
+     * @throws NullPointerException If the startTimeInstant parameter is null.
+     */
+    public abstract Duration normalizeWith(final Calendar startTimeInstant);
+
+    /**
+     * <p>Partial order relation comparison with this <code>Duration</code> instance.</p>
+     *
+     * <p>Comparison result must be in accordance with
+     * <a href="http://www.w3.org/TR/xmlschema-2/#duration-order">W3C XML Schema 1.0 Part 2, Section 3.2.7.6.2,
+     * <i>Order relation on duration</i></a>.</p>
+     *
+     * <p>Return:</p>
+     * <ul>
+     *   <li>{@link DatatypeConstants#LESSER} if this <code>Duration</code> is shorter than <code>duration</code> parameter</li>
+     *   <li>{@link DatatypeConstants#EQUAL} if this <code>Duration</code> is equal to <code>duration</code> parameter</li>
+     *   <li>{@link DatatypeConstants#GREATER} if this <code>Duration</code> is longer than <code>duration</code> parameter</li>
+     *   <li>{@link DatatypeConstants#INDETERMINATE} if a conclusive partial order relation cannot be determined</li>
+     * </ul>
+     *
+     * @param duration to compare
+     *
+     * @return the relationship between <code>this</code> <code>Duration</code>and <code>duration</code> parameter as
+     *   {@link DatatypeConstants#LESSER}, {@link DatatypeConstants#EQUAL}, {@link DatatypeConstants#GREATER}
+     *   or {@link DatatypeConstants#INDETERMINATE}.
+     *
+     * @throws UnsupportedOperationException If the underlying implementation
+     *   cannot reasonably process the request, e.g. W3C XML Schema allows for
+     *   arbitrarily large/small/precise values, the request may be beyond the
+     *   implementations capability.
+     * @throws NullPointerException if <code>duration</code> is <code>null</code>.
+     *
+     * @see #isShorterThan(Duration)
+     * @see #isLongerThan(Duration)
+     */
+    public abstract int compare(final Duration duration);
+
+    /**
+     * <p>Checks if this duration object is strictly longer than
+     * another <code>Duration</code> object.</p>
+     *
+     * <p>Duration X is "longer" than Y if and only if X>Y
+     * as defined in the section 3.2.6.2 of the XML Schema 1.0
+     * specification.</p>
+     *
+     * <p>For example, "P1D" (one day) > "PT12H" (12 hours) and
+     * "P2Y" (two years) > "P23M" (23 months).</p>
+     *
+     * @param duration <code>Duration</code> to test this <code>Duration</code> against.
+     *
+     * @throws UnsupportedOperationException If the underlying implementation
+     *   cannot reasonably process the request, e.g. W3C XML Schema allows for
+     *   arbitrarily large/small/precise values, the request may be beyond the
+     *   implementations capability.
+     * @throws NullPointerException If <code>duration</code> is null.
+     *
+     * @return
+     *      true if the duration represented by this object
+     *      is longer than the given duration. false otherwise.
+     *
+     * @see #isShorterThan(Duration)
+     * @see #compare(Duration duration)
+     */
+    public boolean isLongerThan(final Duration duration) {
+        return compare(duration) == DatatypeConstants.GREATER;
+    }
+
+    /**
+     * <p>Checks if this duration object is strictly shorter than
+     * another <code>Duration</code> object.</p>
+     *
+     * @param duration <code>Duration</code> to test this <code>Duration</code> against.
+     *
+     * @return <code>true</code> if <code>duration</code> parameter is shorter than this <code>Duration</code>,
+     *   else <code>false</code>.
+     *
+     * @throws UnsupportedOperationException If the underlying implementation
+     *   cannot reasonably process the request, e.g. W3C XML Schema allows for
+     *   arbitrarily large/small/precise values, the request may be beyond the
+     *   implementations capability.
+     * @throws NullPointerException if <code>duration</code> is null.
+     *
+     * @see #isLongerThan(Duration duration)
+     * @see #compare(Duration duration)
+     */
+    public boolean isShorterThan(final Duration duration) {
+        return compare(duration) == DatatypeConstants.LESSER;
+    }
+
+    /**
+     * <p>Checks if this duration object has the same duration
+     * as another <code>Duration</code> object.</p>
+     *
+     * <p>For example, "P1D" (1 day) is equal to "PT24H" (24 hours).</p>
+     *
+     * <p>Duration X is equal to Y if and only if time instant
+     * t+X and t+Y are the same for all the test time instants
+     * specified in the section 3.2.6.2 of the XML Schema 1.0
+     * specification.</p>
+     *
+     * <p>Note that there are cases where two <code>Duration</code>s are
+     * "incomparable" to each other, like one month and 30 days.
+     * For example,</p>
+     * <pre>
+     * !new Duration("P1M").isShorterThan(new Duration("P30D"))
+     * !new Duration("P1M").isLongerThan(new Duration("P30D"))
+     * !new Duration("P1M").equals(new Duration("P30D"))
+     * </pre>
+     *
+     * @param duration
+     *      A non-null valid <code>Duration</code> object.
+     *
+     * @return
+     *      <code>true</code> if this duration is the same length as
+     *         <code>duration</code>.
+     *      <code>false</code> if <code>duration</code> is not a
+     *         <code>Duration</code> object, is <code>null</code>,
+     *         or its length is different from this duration.
+     *
+     * @throws UnsupportedOperationException If the underlying implementation
+     *   cannot reasonably process the request, e.g. W3C XML Schema allows for
+     *   arbitrarily large/small/precise values, the request may be beyond the
+     *   implementations capability.
+     *
+     * @see #compare(Duration duration)
+     */
+    public boolean equals(final Object duration) {
+        if (duration == this) {
+            return true;
+        }
+        if (duration instanceof Duration) {
+            return compare((Duration) duration) == DatatypeConstants.EQUAL;
+        }
+        return false;
+    }
+
+    /**
+     * Returns a hash code consistent with the definition of the equals method.
+     *
+     * @see Object#hashCode()
+     */
+    public abstract int hashCode();
+
+    /**
+     * <p>Returns a <code>String</code> representation of this <code>Duration</code> <code>Object</code>.</p>
+     *
+     * <p>The result is formatted according to the XML Schema 1.0 specification and can be always parsed back later into the
+     * equivalent <code>Duration</code> <code>Object</code> by {@link DatatypeFactory#newDuration(String  lexicalRepresentation)}.</p>
+     *
+     * <p>Formally, the following holds for any <code>Duration</code>
+     * <code>Object</code> x:</p>
+     * <pre>
+     * new Duration(x.toString()).equals(x)
+     * </pre>
+     *
+     * @return A non-<code>null</code> valid <code>String</code> representation of this <code>Duration</code>.
+     */
+    public String toString() {
+        StringBuilder buf = new StringBuilder();
+
+        if (getSign() < 0) {
+            buf.append('-');
+        }
+        buf.append('P');
+
+        BigInteger years = (BigInteger) getField(DatatypeConstants.YEARS);
+        if (years != null) {
+            buf.append(years).append('Y');
+        }
+
+        BigInteger months = (BigInteger) getField(DatatypeConstants.MONTHS);
+        if (months != null) {
+            buf.append(months).append('M');
+        }
+
+        BigInteger days = (BigInteger) getField(DatatypeConstants.DAYS);
+        if (days != null) {
+            buf.append(days).append('D');
+        }
+
+        BigInteger hours = (BigInteger) getField(DatatypeConstants.HOURS);
+        BigInteger minutes = (BigInteger) getField(DatatypeConstants.MINUTES);
+        BigDecimal seconds = (BigDecimal) getField(DatatypeConstants.SECONDS);
+        if (hours != null || minutes != null || seconds != null) {
+            buf.append('T');
+            if (hours != null) {
+                buf.append(hours).append('H');
+            }
+            if (minutes != null) {
+                buf.append(minutes).append('M');
+            }
+            if (seconds != null) {
+                buf.append(toString(seconds)).append('S');
+            }
+        }
+
+        return buf.toString();
+    }
+
+    /**
+     * <p>Turns {@link BigDecimal} to a string representation.</p>
+     *
+     * <p>Due to a behavior change in the {@link BigDecimal#toString()}
+     * method in JDK1.5, this had to be implemented here.</p>
+     *
+     * @param bd <code>BigDecimal</code> to format as a <code>String</code>
+     *
+     * @return  <code>String</code> representation of <code>BigDecimal</code>
+     */
+    private String toString(BigDecimal bd) {
+        String intString = bd.unscaledValue().toString();
+        int scale = bd.scale();
+
+        if (scale == 0) {
+            return intString;
+        }
+
+        /* Insert decimal point */
+        StringBuilder buf;
+        int insertionPoint = intString.length() - scale;
+        if (insertionPoint == 0) { /* Point goes right before intVal */
+            return "0." + intString;
+        }
+        else if (insertionPoint > 0) { /* Point goes inside intVal */
+            buf = new StringBuilder(intString);
+            buf.insert(insertionPoint, '.');
+        }
+        else { /* We must insert zeros between point and intVal */
+            buf = new StringBuilder(3 - insertionPoint + intString.length());
+            buf.append("0.");
+            for (int i = 0; i < -insertionPoint; i++) {
+                buf.append('0');
+            }
+            buf.append(intString);
+        }
+        return buf.toString();
+    }
+
+
+    /**
+     * <p>Calls the {@link Calendar#getTimeInMillis} method.
+     * Prior to JDK1.4, this method was protected and therefore
+     * cannot be invoked directly.</p>
+     *
+     * <p>TODO: In future, this should be replaced by <code>cal.getTimeInMillis()</code>.</p>
+     *
+     * @param cal <code>Calendar</code> to get time in milliseconds.
+     *
+     * @return Milliseconds of <code>cal</code>.
+     */
+    private static long getCalendarTimeInMillis(final Calendar cal) {
+        return cal.getTime().getTime();
+    }
+}
diff --git a/javax/xml/datatype/FactoryFinder.java b/javax/xml/datatype/FactoryFinder.java
new file mode 100644
index 0000000..c31bee3
--- /dev/null
+++ b/javax/xml/datatype/FactoryFinder.java
@@ -0,0 +1,355 @@
+/*
+ * 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.
+ */
+
+// $Id: FactoryFinder.java 670432 2008-06-23 02:02:08Z mrglavas $
+
+package javax.xml.datatype;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.Properties;
+import libcore.io.IoUtils;
+
+/**
+ * <p>Implement pluggable data types.</p>
+ *
+ * <p>This class is duplicated for each JAXP subpackage so keep it in
+ * sync.  It is package private for secure class loading.</p>
+ *
+ * @author <a href="mailto:[email protected]">Jeff Suttor</a>
+ * @version $Revision: 670432 $, $Date: 2008-06-22 19:02:08 -0700 (Sun, 22 Jun 2008) $
+ * @since 1.5
+ */
+final class FactoryFinder {
+
+    /** <p>Name of class to display in output messages.</p> */
+    private static final String CLASS_NAME = "javax.xml.datatype.FactoryFinder";
+
+    /** <p>Debug flag to trace loading process.</p> */
+    private static boolean debug = false;
+
+    /**
+     * <p>Cache properties for performance. Use a static class to avoid double-checked
+     * locking.</p>
+     */
+    private static class CacheHolder {
+
+        private static Properties cacheProps = new Properties();
+
+        static {
+            String javah = System.getProperty("java.home");
+            String configFile = javah + File.separator + "lib" + File.separator + "jaxp.properties";
+            File f = new File(configFile);
+            if (f.exists()) {
+                if (debug) debugPrintln("Read properties file " + f);
+                try (FileInputStream inputStream = new FileInputStream(f)) {
+                    cacheProps.load(inputStream);
+                } catch (Exception ex) {
+                    if (debug) {
+                        ex.printStackTrace();
+                    }
+                }
+            }
+        }
+    }
+
+    /** Default columns per line. */
+    private static final int DEFAULT_LINE_LENGTH = 80;
+
+    /**
+     * <p>Check to see if debugging enabled by property.</p>
+     *
+     * <p>Use try/catch block to support applets, which throws
+     * SecurityException out of this code.</p>
+     */
+    static {
+        String val = System.getProperty("jaxp.debug");
+        // Allow simply setting the prop to turn on debug
+        debug = val != null && (! "false".equals(val));
+    }
+
+    private FactoryFinder() {}
+
+    /**
+     * <p>Output debugging messages.</p>
+     *
+     * @param msg <code>String</code> to print to <code>stderr</code>.
+     */
+    private static void debugPrintln(String msg) {
+        if (debug) {
+            System.err.println(
+                CLASS_NAME
+                + ":"
+                + msg);
+        }
+    }
+
+    /**
+     * <p>Find the appropriate <code>ClassLoader</code> to use.</p>
+     *
+     * <p>The context ClassLoader is preferred.</p>
+     *
+     * @return <code>ClassLoader</code> to use.
+     *
+     * @throws ConfigurationError If a valid <code>ClassLoader</code> cannot be identified.
+     */
+    private static ClassLoader findClassLoader() throws ConfigurationError {
+        // Figure out which ClassLoader to use for loading the provider
+        // class.  If there is a Context ClassLoader then use it.
+
+        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+
+        if (debug) debugPrintln(
+            "Using context class loader: "
+            + classLoader);
+
+        if (classLoader == null) {
+            // if we have no Context ClassLoader
+            // so use the current ClassLoader
+            classLoader = FactoryFinder.class.getClassLoader();
+            if (debug) debugPrintln(
+                "Using the class loader of FactoryFinder: "
+                + classLoader);
+        }
+
+        return classLoader;
+    }
+
+    /**
+     * <p>Create an instance of a class using the specified ClassLoader.</p>
+     *
+     * @param className Name of class to create.
+     * @param classLoader ClassLoader to use to create named class.
+     *
+     * @return New instance of specified class created using the specified ClassLoader.
+     *
+     * @throws ConfigurationError If class could not be created.
+     */
+    static Object newInstance(
+        String className,
+        ClassLoader classLoader)
+        throws ConfigurationError {
+
+        try {
+            Class spiClass;
+            if (classLoader == null) {
+                spiClass = Class.forName(className);
+            } else {
+                spiClass = classLoader.loadClass(className);
+            }
+
+            if (debug) {
+                debugPrintln("Loaded " + className + " from " + which(spiClass));
+            }
+
+            return spiClass.newInstance();
+        } catch (ClassNotFoundException x) {
+            throw new ConfigurationError(
+                "Provider " + className + " not found", x);
+        } catch (Exception x) {
+            throw new ConfigurationError(
+                "Provider " + className + " could not be instantiated: " + x, x);
+        }
+    }
+
+    /**
+     * Finds the implementation Class object in the specified order.  Main
+     * entry point.
+     * Package private so this code can be shared.
+     *
+     * @param factoryId Name of the factory to find, same as a property name
+     * @param fallbackClassName Implementation class name, if nothing else is found.  Use null to mean no fallback.
+     *
+     * @return Class Object of factory, never null
+     *
+     * @throws ConfigurationError If Class cannot be found.
+     */
+    static Object find(String factoryId, String fallbackClassName) throws ConfigurationError {
+
+        ClassLoader classLoader = findClassLoader();
+
+        // Use the system property first
+        String systemProp = System.getProperty(factoryId);
+        if (systemProp != null && systemProp.length() > 0) {
+            if (debug) debugPrintln("found " + systemProp + " in the system property " + factoryId);
+            return newInstance(systemProp, classLoader);
+        }
+
+        // try to read from $java.home/lib/jaxp.properties
+        try {
+            String factoryClassName = CacheHolder.cacheProps.getProperty(factoryId);
+            if (debug) debugPrintln("found " + factoryClassName + " in $java.home/jaxp.properties");
+
+            if (factoryClassName != null) {
+                return newInstance(factoryClassName, classLoader);
+            }
+        } catch (Exception ex) {
+            if (debug) {
+                ex.printStackTrace();
+            }
+        }
+
+        // Try Jar Service Provider Mechanism
+        Object provider = findJarServiceProvider(factoryId);
+        if (provider != null) {
+            return provider;
+        }
+
+        if (fallbackClassName == null) {
+            throw new ConfigurationError(
+                "Provider for " + factoryId + " cannot be found", null);
+        }
+
+        if (debug) debugPrintln("loaded from fallback value: " + fallbackClassName);
+        return newInstance(fallbackClassName, classLoader);
+    }
+
+    /*
+     * Try to find provider using Jar Service Provider Mechanism
+     *
+     * @return instance of provider class if found or null
+     */
+    private static Object findJarServiceProvider(String factoryId) throws ConfigurationError {
+        String serviceId = "META-INF/services/" + factoryId;
+        InputStream is = null;
+
+        // First try the Context ClassLoader
+        ClassLoader cl = Thread.currentThread().getContextClassLoader();
+        if (cl != null) {
+            is = cl.getResourceAsStream(serviceId);
+        }
+
+        if (is == null) {
+            cl = FactoryFinder.class.getClassLoader();
+            is = cl.getResourceAsStream(serviceId);
+        }
+
+        if (is == null) {
+            // No provider found
+            return null;
+        }
+
+        if (debug) debugPrintln("found jar resource=" + serviceId + " using ClassLoader: " + cl);
+
+        BufferedReader rd;
+        try {
+            rd = new BufferedReader(new InputStreamReader(is, "UTF-8"), DEFAULT_LINE_LENGTH);
+        } catch (java.io.UnsupportedEncodingException e) {
+            rd = new BufferedReader(new InputStreamReader(is), DEFAULT_LINE_LENGTH);
+        }
+
+        String factoryClassName = null;
+        try {
+            // XXX Does not handle all possible input as specified by the
+            // Jar Service Provider specification
+            factoryClassName = rd.readLine();
+        } catch (IOException x) {
+            // No provider found
+            return null;
+        } finally {
+            IoUtils.closeQuietly(rd);
+        }
+
+        if (factoryClassName != null &&
+            ! "".equals(factoryClassName)) {
+            if (debug) debugPrintln("found in resource, value="
+                   + factoryClassName);
+
+            return newInstance(factoryClassName, cl);
+        }
+
+        // No provider found
+        return null;
+    }
+
+    /**
+     * <p>Configuration Error.</p>
+     */
+    static class ConfigurationError extends Error {
+
+        private static final long serialVersionUID = -3644413026244211347L;
+
+        /**
+         * <p>Exception that caused the error.</p>
+         */
+        private Exception exception;
+
+        /**
+         * <p>Construct a new instance with the specified detail string and
+         * exception.</p>
+         *
+         * @param msg Detail message for this error.
+         * @param x Exception that caused the error.
+         */
+        ConfigurationError(String msg, Exception x) {
+            super(msg);
+            this.exception = x;
+        }
+
+        /**
+         * <p>Get the Exception that caused the error.</p>
+         *
+         * @return Exception that caused the error.
+         */
+        Exception getException() {
+            return exception;
+        }
+    }
+
+    /**
+     * Returns the location where the given Class is loaded from.
+     */
+    private static String which(Class clazz) {
+        try {
+            String classnameAsResource = clazz.getName().replace('.', '/') + ".class";
+
+            ClassLoader loader = clazz.getClassLoader();
+
+            URL it;
+
+            if (loader != null) {
+                it = loader.getResource(classnameAsResource);
+            } else {
+                it = ClassLoader.getSystemResource(classnameAsResource);
+            }
+
+            if (it != null) {
+                return it.toString();
+            }
+        }
+        // The VM ran out of memory or there was some other serious problem. Re-throw.
+        catch (VirtualMachineError vme) {
+            throw vme;
+        }
+        // ThreadDeath should always be re-thrown
+        catch (ThreadDeath td) {
+            throw td;
+        }
+        catch (Throwable t) {
+            // work defensively.
+            if (debug) {
+                t.printStackTrace();
+            }
+        }
+        return "unknown location";
+    }
+}
diff --git a/javax/xml/datatype/XMLGregorianCalendar.java b/javax/xml/datatype/XMLGregorianCalendar.java
new file mode 100644
index 0000000..6796104
--- /dev/null
+++ b/javax/xml/datatype/XMLGregorianCalendar.java
@@ -0,0 +1,1037 @@
+/*
+ * 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.
+ */
+
+// $Id: XMLGregorianCalendar.java 759822 2009-03-30 01:15:11Z mrglavas $
+
+package javax.xml.datatype;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.GregorianCalendar;
+import java.util.TimeZone;
+import javax.xml.namespace.QName;
+
+/**
+ * <p>Representation for W3C XML Schema 1.0 date/time datatypes.
+ * Specifically, these date/time datatypes are
+ * <a href="#DATETIME"><code>dateTime</code></a>,
+ * <a href="#TIME"><code>time</code></a>,
+ * <a href="#DATE"><code>date</code></a>,
+ * <a href="#GYEARMONTH"><code>gYearMonth</code></a>,
+ * <a href="#GMONTHDAY"><code>gMonthDay</code></a>,
+ * <a href="#GYEAR"><code>gYear</code></a>
+ * <a href="#GMONTH"><code>gMonth</code></a> and
+ * <a href="#GDAY"><code>gDay</code></a> defined in the XML Namespace
+ * <code>"http://www.w3.org/2001/XMLSchema"</code>.
+ * These datatypes are normatively defined in
+ * <a href="http://www.w3.org/TR/xmlschema-2/#dateTime">W3C XML Schema 1.0 Part 2, Section 3.2.7-14</a>.</p>
+ *
+ * <p>The table below defines the mapping between XML Schema 1.0
+ * date/time datatype fields and this class' fields. It also summarizes
+ * the value constraints for the date and time fields defined in
+ * <a href="http://www.w3.org/TR/xmlschema-2/#isoformats">W3C XML Schema 1.0 Part 2, Appendix D,
+ * <i>ISO 8601 Date and Time Formats</i></a>.</p>
+ *
+ * <a name="datetimefieldsmapping"/>
+ * <table border="2" rules="all" cellpadding="2">
+ *   <thead>
+ *     <tr>
+ *       <th align="center" colspan="3">
+ *         Date/Time Datatype Field Mapping Between XML Schema 1.0 and Java Representation
+ *       </th>
+ *     </tr>
+ *   </thead>
+ *   <tbody>
+ *     <tr>
+ *       <th>XML Schema 1.0<br/>
+ *           datatype<br/>
+ *            field</th>
+ *       <th>Related<br/>XMLGregorianCalendar<br/>Accessor(s)</th>
+ *       <th>Value Range</th>
+ *     </tr>
+ *     <a name="datetimefield-year"/>
+ *     <tr>
+ *       <td> year </td>
+ *       <td> {@link #getYear()} + {@link #getEon()} or<br/>
+ *            {@link #getEonAndYear}
+ *       </td>
+ *       <td> <code>getYear()</code> is a value between -(10^9-1) to (10^9)-1
+ *            or {@link DatatypeConstants#FIELD_UNDEFINED}.<br/>
+ *            {@link #getEon()} is high order year value in billion of years.<br/>
+ *            <code>getEon()</code> has values greater than or equal to (10^9) or less than or equal to -(10^9).
+ *            A value of null indicates field is undefined.</br>
+ *            Given that <a href="http://www.w3.org/2001/05/xmlschema-errata#e2-63">XML Schema 1.0 errata</a> states that the year zero
+ *            will be a valid lexical value in a future version of XML Schema,
+ *            this class allows the year field to be set to zero. Otherwise,
+ *            the year field value is handled exactly as described
+ *            in the errata and [ISO-8601-1988]. Note that W3C XML Schema 1.0
+ *            validation does not allow for the year field to have a value of zero.
+ *            </td>
+ *     </tr>
+ *     <a name="datetimefield-month"/>
+ *     <tr>
+ *       <td> month </td>
+ *       <td> {@link #getMonth()} </td>
+ *       <td> 1 to 12 or {@link DatatypeConstants#FIELD_UNDEFINED} </td>
+ *     </tr>
+ *     <a name="datetimefield-day"/>
+ *     <tr>
+ *       <td> day </td>
+ *       <td> {@link #getDay()} </td>
+ *       <td> Independent of month, max range is 1 to 31 or {@link DatatypeConstants#FIELD_UNDEFINED}.<br/>
+ *            The normative value constraint stated relative to month
+ *            field's value is in <a href="http://www.w3.org/TR/xmlschema-2/#isoformats">W3C XML Schema 1.0 Part 2, Appendix D</a>.
+ *       </td>
+ *     </tr>
+ *     <tr id="datetimefield-hour">
+ *       <td>hour</td>
+ *       <td>{@link #getHour()}</td>
+ *       <td>
+ *         0 to 24 or {@link DatatypeConstants#FIELD_UNDEFINED}.
+ *         For a value of 24, the minute and second field must be zero per
+ *         <a href="http://www.w3.org/2001/05/xmlschema-errata#e2-45">XML Schema Errata</a>.
+ *       </td>
+ *     </tr>
+ *     <a name="datetimefield-minute"/>
+ *     <tr>
+ *       <td> minute </td>
+ *       <td> {@link #getMinute()} </td>
+ *       <td> 0 to 59 or {@link DatatypeConstants#FIELD_UNDEFINED} </td>
+ *     </tr>
+ *     <a name="datetimefield-second"/>
+ *     <tr>
+ *       <td>second</td>
+ *       <td>
+ *         {@link #getSecond()} + {@link #getMillisecond()}/1000 or<br/>
+ *         {@link #getSecond()} + {@link #getFractionalSecond()}
+ *       </td>
+ *       <td>
+ *         {@link #getSecond()} from 0 to 60 or {@link DatatypeConstants#FIELD_UNDEFINED}.<br/>
+ *         <i>(Note: 60 only allowable for leap second.)</i><br/>
+ *         {@link #getFractionalSecond()} allows for infinite precision over the range from 0.0 to 1.0 when
+ *         the {@link #getSecond()} is defined.<br/>
+ *         <code>FractionalSecond</code> is optional and has a value of <code>null</code> when it is undefined.<br />
+ *            {@link #getMillisecond()} is the convenience
+ *            millisecond precision of value of {@link #getFractionalSecond()}.
+ *       </td>
+ *     </tr>
+ *     <tr id="datetimefield-timezone">
+ *       <td> timezone </td>
+ *       <td> {@link #getTimezone()} </td>
+ *       <td> Number of minutes or {@link DatatypeConstants#FIELD_UNDEFINED}.
+ *         Value range from -14 hours (-14 * 60 minutes) to 14 hours (14 * 60 minutes).
+ *       </td>
+ *     </tr>
+ *   </tbody>
+ *  </table>
+ *
+ * <p>All maximum value space constraints listed for the fields in the table
+ * above are checked by factory methods, @{link DatatypeFactory},
+ * setter methods and parse methods of
+ * this class. <code>IllegalArgumentException</code> is thrown when a
+ * parameter's value is outside the value constraint for the field or
+ * if the composite
+ * values constitute an invalid XMLGregorianCalendar instance (for example, if
+ * the 31st of June is specified).
+ * </p>
+ *
+ * <p>The following operations are defined for this class:
+ * <ul>
+ *   <li>accessors/mutators for independent date/time fields</li>
+ *   <li>conversion between this class and W3C XML Schema 1.0 lexical representation,
+ *     {@link #toString()}, {@link DatatypeFactory#newXMLGregorianCalendar(String lexicalRepresentation)}</li>
+ *   <li>conversion between this class and {@link GregorianCalendar},
+ *     {@link #toGregorianCalendar(java.util.TimeZone timezone, java.util.Locale aLocale, XMLGregorianCalendar defaults)},
+ *     {@link DatatypeFactory}</li>
+ *   <li>partial order relation comparator method, {@link #compare(XMLGregorianCalendar xmlGregorianCalendar)}</li>
+ *   <li>{@link #equals(Object)} defined relative to {@link #compare(XMLGregorianCalendar xmlGregorianCalendar)}.</li>
+ *   <li>addition operation with {@link Duration}
+ *      instance as defined in <a href="http://www.w3.org/TR/xmlschema-2/#adding-durations-to-dateTimes">
+ *      W3C XML Schema 1.0 Part 2, Appendix E, <i>Adding durations to dateTimes</i></a>.
+ *   </li>
+ * </ul>
+ * </p>
+ *
+ * @author <a href="mailto:[email protected]">Joseph Fialli</a>
+ * @author <a href="mailto:[email protected]">Kohsuke Kawaguchi</a>
+ * @author <a href="mailto:[email protected]">Jeff Suttor</a>
+ * @version $Revision: 759822 $, $Date: 2009-03-29 18:15:11 -0700 (Sun, 29 Mar 2009) $
+ * @see Duration
+ * @see DatatypeFactory
+ * @since 1.5
+ */
+
+public abstract class XMLGregorianCalendar
+    implements Cloneable {
+
+    /**
+     * <p>Unset all fields to undefined.</p>
+     *
+     * <p>Set all int fields to {@link DatatypeConstants#FIELD_UNDEFINED} and reference fields
+     * to null.</p>
+     */
+    public abstract void clear();
+
+    /**
+     * <p>Reset this <code>XMLGregorianCalendar</code> to its original values.</p>
+     *
+     * <p><code>XMLGregorianCalendar</code> is reset to the same values as when it was created with
+     * {@link DatatypeFactory#newXMLGregorianCalendar()},
+     * {@link DatatypeFactory#newXMLGregorianCalendar(String lexicalRepresentation)},
+     * {@link DatatypeFactory#newXMLGregorianCalendar(
+     *   BigInteger year,
+     *   int month,
+     *   int day,
+     *   int hour,
+     *   int minute,
+     *   int second,
+     *   BigDecimal fractionalSecond,
+     *   int timezone)},
+     * {@link DatatypeFactory#newXMLGregorianCalendar(
+     *   int year,
+     *   int month,
+     *   int day,
+     *   int hour,
+     *   int minute,
+     *   int second,
+     *   int millisecond,
+     *   int timezone)},
+     * {@link DatatypeFactory#newXMLGregorianCalendar(GregorianCalendar cal)},
+     * {@link DatatypeFactory#newXMLGregorianCalendarDate(
+     *   int year,
+     *   int month,
+     *   int day,
+     *   int timezone)},
+     * {@link DatatypeFactory#newXMLGregorianCalendarTime(
+     *   int hours,
+     *   int minutes,
+     *   int seconds,
+     *   int timezone)},
+     * {@link DatatypeFactory#newXMLGregorianCalendarTime(
+     *   int hours,
+     *   int minutes,
+     *   int seconds,
+     *   BigDecimal fractionalSecond,
+     *   int timezone)} or
+     * {@link DatatypeFactory#newXMLGregorianCalendarTime(
+     *   int hours,
+     *   int minutes,
+     *   int seconds,
+     *   int milliseconds,
+     *   int timezone)}.
+     * </p>
+     *
+     * <p><code>reset()</code> is designed to allow the reuse of existing <code>XMLGregorianCalendar</code>s
+     * thus saving resources associated with the creation of new <code>XMLGregorianCalendar</code>s.</p>
+     */
+    public abstract void reset();
+
+    /**
+     * <p>Set low and high order component of XSD <code>dateTime</code> year field.</p>
+     *
+     * <p>Unset this field by invoking the setter with a parameter value of <code>null</code>.</p>
+     *
+     * @param year value constraints summarized in <a href="#datetimefield-year">year field of date/time field mapping table</a>.
+     *
+     * @throws IllegalArgumentException if <code>year</code> parameter is
+     * outside value constraints for the field as specified in
+     * <a href="#datetimefieldmapping">date/time field mapping table</a>.
+     */
+    public abstract void setYear(BigInteger year);
+
+    /**
+     * <p>Set year of XSD <code>dateTime</code> year field.</p>
+     *
+     * <p>Unset this field by invoking the setter with a parameter value of
+     * {@link DatatypeConstants#FIELD_UNDEFINED}.</p>
+     *
+     * <p>Note: if the absolute value of the <code>year</code> parameter
+     * is less than 10^9, the eon component of the XSD year field is set to
+     * <code>null</code> by this method.</p>
+     *
+     * @param year value constraints are summarized in <a href="#datetimefield-year">year field of date/time field mapping table</a>.
+     *   If year is {@link DatatypeConstants#FIELD_UNDEFINED}, then eon is set to <code>null</code>.
+     */
+    public abstract void setYear(int year);
+
+    /**
+     * <p>Set month.</p>
+     *
+     * <p>Unset this field by invoking the setter with a parameter value of {@link DatatypeConstants#FIELD_UNDEFINED}.</p>
+     *
+     * @param month value constraints summarized in <a href="#datetimefield-month">month field of date/time field mapping table</a>.
+     *
+     * @throws IllegalArgumentException if <code>month</code> parameter is
+     * outside value constraints for the field as specified in
+     * <a href="#datetimefieldmapping">date/time field mapping table</a>.
+     */
+    public abstract void setMonth(int month);
+
+    /**
+     * <p>Set days in month.</p>
+     *
+     * <p>Unset this field by invoking the setter with a parameter value of {@link DatatypeConstants#FIELD_UNDEFINED}.</p>
+     *
+     * @param day value constraints summarized in <a href="#datetimefield-day">day field of date/time field mapping table</a>.
+     *
+     * @throws IllegalArgumentException if <code>day</code> parameter is
+     * outside value constraints for the field as specified in
+     * <a href="#datetimefieldmapping">date/time field mapping table</a>.
+     */
+    public abstract void setDay(int day);
+
+    /**
+     * <p>Set the number of minutes in the timezone offset.</p>
+     *
+     * <p>Unset this field by invoking the setter with a parameter value of {@link DatatypeConstants#FIELD_UNDEFINED}.</p>
+     *
+     * @param offset value constraints summarized in <a href="#datetimefield-timezone">
+     *   timezone field of date/time field mapping table</a>.
+     *
+     * @throws IllegalArgumentException if <code>offset</code> parameter is
+     * outside value constraints for the field as specified in
+     * <a href="#datetimefieldmapping">date/time field mapping table</a>.
+     */
+    public abstract void setTimezone(int offset);
+
+    /**
+     * <p>Set time as one unit.</p>
+     *
+     * @param hour value constraints are summarized in
+     * <a href="#datetimefield-hour">hour field of date/time field mapping table</a>.
+     * @param minute value constraints are summarized in
+     * <a href="#datetimefield-minute">minute field of date/time field mapping table</a>.
+     * @param second value constraints are summarized in
+     * <a href="#datetimefield-second">second field of date/time field mapping table</a>.
+     *
+     * @see #setTime(int, int, int, BigDecimal)
+     *
+     * @throws IllegalArgumentException if any parameter is
+     * outside value constraints for the field as specified in
+     * <a href="#datetimefieldmapping">date/time field mapping table</a>.
+     */
+    public void setTime(int hour, int minute, int second) {
+
+        setTime(
+            hour,
+            minute,
+            second,
+            null // fractional
+        );
+    }
+
+    /**
+      * <p>Set hours.</p>
+      *
+      * <p>Unset this field by invoking the setter with a parameter value of {@link DatatypeConstants#FIELD_UNDEFINED}.</p>
+      *
+      * @param hour value constraints summarized in <a href="#datetimefield-hour">hour field of date/time field mapping table</a>.
+      *
+      * @throws IllegalArgumentException if <code>hour</code> parameter is outside value constraints for the field as specified in
+      *   <a href="#datetimefieldmapping">date/time field mapping table</a>.
+     */
+    public abstract void setHour(int hour);
+
+    /**
+     * <p>Set minutes.</p>
+     *
+     * <p>Unset this field by invoking the setter with a parameter value of {@link DatatypeConstants#FIELD_UNDEFINED}.</p>
+     *
+     * @param minute value constraints summarized in <a href="#datetimefield-minute">minute field of date/time field mapping table</a>.
+     *
+     * @throws IllegalArgumentException if <code>minute</code> parameter is outside value constraints for the field as specified in
+     *   <a href="#datetimefieldmapping">date/time field mapping table</a>.
+    */
+    public abstract void setMinute(int minute);
+
+    /**
+     * <p>Set seconds.</p>
+     *
+     * <p>Unset this field by invoking the setter with a parameter value of {@link DatatypeConstants#FIELD_UNDEFINED}.</p>
+     *
+     * @param second value constraints summarized in <a href="#datetimefield-second">second field of date/time field mapping table</a>.
+     *
+     * @throws IllegalArgumentException if <code>second</code> parameter is outside value constraints for the field as specified in
+     *   <a href="#datetimefieldmapping">date/time field mapping table</a>.
+    */
+    public abstract void setSecond(int second);
+
+    /**
+     * <p>Set milliseconds.</p>
+     *
+     * <p>Unset this field by invoking the setter with a parameter value of {@link DatatypeConstants#FIELD_UNDEFINED}.</p>
+     *
+     * @param millisecond value constraints summarized in
+     *   <a href="#datetimefield-millisecond">millisecond field of date/time field mapping table</a>.
+     *
+     * @throws IllegalArgumentException if <code>millisecond</code> parameter is outside value constraints for the field as specified
+     *   in <a href="#datetimefieldmapping">date/time field mapping table</a>.
+    */
+    public abstract void setMillisecond(int millisecond);
+
+    /**
+     * <p>Set fractional seconds.</p>
+     *
+     * <p>Unset this field by invoking the setter with a parameter value of <code>null</code>.</p>
+     *
+     * @param fractional value constraints summarized in
+     *   <a href="#datetimefield-fractional">fractional field of date/time field mapping table</a>.
+     *
+     * @throws IllegalArgumentException if <code>fractional</code> parameter is outside value constraints for the field as specified
+     *   in <a href="#datetimefieldmapping">date/time field mapping table</a>.
+    */
+    public abstract void setFractionalSecond(BigDecimal fractional);
+
+    /**
+     * <p>Set time as one unit, including the optional infinite precision
+     * fractional seconds.</p>
+     *
+     * @param hour value constraints are summarized in
+     * <a href="#datetimefield-hour">hour field of date/time field mapping table</a>.
+     * @param minute value constraints are summarized in
+     * <a href="#datetimefield-minute">minute field of date/time field mapping table</a>.
+     * @param second value constraints are summarized in
+     * <a href="#datetimefield-second">second field of date/time field mapping table</a>.
+     * @param fractional value of <code>null</code> indicates this optional
+     *   field is not set.
+     *
+     * @throws IllegalArgumentException if any parameter is
+     * outside value constraints for the field as specified in
+     * <a href="#datetimefieldmapping">date/time field mapping table</a>.
+     */
+    public void setTime(
+        int hour,
+        int minute,
+        int second,
+        BigDecimal fractional) {
+
+        setHour(hour);
+        setMinute(minute);
+        setSecond(second);
+        setFractionalSecond(fractional);
+    }
+
+    /**
+     * <p>Set time as one unit, including optional milliseconds.</p>
+     *
+     * @param hour value constraints are summarized in
+     * <a href="#datetimefield-hour">hour field of date/time field mapping table</a>.
+     * @param minute value constraints are summarized in
+     * <a href="#datetimefield-minute">minute field of date/time field mapping table</a>.
+     * @param second value constraints are summarized in
+     * <a href="#datetimefield-second">second field of date/time field mapping table</a>.
+     * @param millisecond value of {@link DatatypeConstants#FIELD_UNDEFINED} indicates this
+     *                    optional field is not set.
+     *
+     * @throws IllegalArgumentException if any parameter is
+     * outside value constraints for the field as specified in
+     * <a href="#datetimefieldmapping">date/time field mapping table</a>.
+     */
+    public void setTime(int hour, int minute, int second, int millisecond) {
+
+        setHour(hour);
+        setMinute(minute);
+        setSecond(second);
+        setMillisecond(millisecond);
+    }
+
+    /**
+     * <p>Return high order component for XML Schema 1.0 dateTime datatype field for
+     * <code>year</code>.
+     * <code>null</code> if this optional part of the year field is not defined.</p>
+     *
+     * <p>Value constraints for this value are summarized in
+     * <a href="#datetimefield-year">year field of date/time field mapping table</a>.</p>
+     * @return eon of this <code>XMLGregorianCalendar</code>. The value
+     * returned is an integer multiple of 10^9.
+     *
+     * @see #getYear()
+     * @see #getEonAndYear()
+     */
+    public abstract BigInteger getEon();
+
+    /**
+     * <p>Return low order component for XML Schema 1.0 dateTime datatype field for
+     * <code>year</code> or {@link DatatypeConstants#FIELD_UNDEFINED}.</p>
+     *
+     * <p>Value constraints for this value are summarized in
+     * <a href="#datetimefield-year">year field of date/time field mapping table</a>.</p>
+     *
+     * @return year  of this <code>XMLGregorianCalendar</code>.
+     *
+     * @see #getEon()
+     * @see #getEonAndYear()
+     */
+    public abstract int getYear();
+
+    /**
+     * <p>Return XML Schema 1.0 dateTime datatype field for
+     * <code>year</code>.</p>
+     *
+     * <p>Value constraints for this value are summarized in
+     * <a href="#datetimefield-year">year field of date/time field mapping table</a>.</p>
+     *
+     * @return sum of <code>eon</code> and <code>BigInteger.valueOf(year)</code>
+     * when both fields are defined. When only <code>year</code> is defined,
+     * return it. When both <code>eon</code> and <code>year</code> are not
+     * defined, return <code>null</code>.
+     *
+     * @see #getEon()
+     * @see #getYear()
+     */
+    public abstract BigInteger getEonAndYear();
+
+    /**
+     * <p>Return number of month or {@link DatatypeConstants#FIELD_UNDEFINED}.</p>
+     *
+     * <p>Value constraints for this value are summarized in
+     * <a href="#datetimefield-month">month field of date/time field mapping table</a>.</p>
+     *
+     * @return year  of this <code>XMLGregorianCalendar</code>.
+     *
+     */
+    public abstract int getMonth();
+
+    /**
+     * Return day in month or {@link DatatypeConstants#FIELD_UNDEFINED}.</p>
+     *
+     * <p>Value constraints for this value are summarized in
+     * <a href="#datetimefield-day">day field of date/time field mapping table</a>.</p>
+     *
+     * @see #setDay(int)
+     */
+    public abstract int getDay();
+
+    /**
+     * Return timezone offset in minutes or
+     * {@link DatatypeConstants#FIELD_UNDEFINED} if this optional field is not defined.
+     *
+     * <p>Value constraints for this value are summarized in
+     * <a href="#datetimefield-timezone">timezone field of date/time field mapping table</a>.</p>
+     *
+     * @see #setTimezone(int)
+     */
+    public abstract int getTimezone();
+
+    /**
+     * Return hours or {@link DatatypeConstants#FIELD_UNDEFINED}.
+     * Returns {@link DatatypeConstants#FIELD_UNDEFINED} if this field is not defined.
+     *
+     * <p>Value constraints for this value are summarized in
+     * <a href="#datetimefield-hour">hour field of date/time field mapping table</a>.</p>
+     * @see #setTime(int, int, int)
+     */
+    public abstract int getHour();
+
+    /**
+     * Return minutes or {@link DatatypeConstants#FIELD_UNDEFINED}.</p>
+     * Returns {@link DatatypeConstants#FIELD_UNDEFINED} if this field is not defined.
+     *
+     * <p>Value constraints for this value are summarized in
+     * <a href="#datetimefield-minute">minute field of date/time field mapping table</a>.</p>
+     * @see #setTime(int, int, int)
+     */
+    public abstract int getMinute();
+
+    /**
+     * <p>Return seconds or {@link DatatypeConstants#FIELD_UNDEFINED}.</p>
+     *
+     * <p>Returns {@link DatatypeConstants#FIELD_UNDEFINED} if this field is not defined.
+     * When this field is not defined, the optional xs:dateTime
+     * fractional seconds field, represented by
+     * {@link #getFractionalSecond()} and {@link #getMillisecond()},
+     * must not be defined.</p>
+     *
+     * <p>Value constraints for this value are summarized in
+     * <a href="#datetimefield-second">second field of date/time field mapping table</a>.</p>
+     *
+     * @return Second  of this <code>XMLGregorianCalendar</code>.
+     *
+     * @see #getFractionalSecond()
+     * @see #getMillisecond()
+     * @see #setTime(int, int, int)
+     */
+    public abstract int getSecond();
+
+    /**
+     * <p>Return millisecond precision of {@link #getFractionalSecond()}.</p>
+     *
+     * <p>This method represents a convenience accessor to infinite
+     * precision fractional second value returned by
+     * {@link #getFractionalSecond()}. The returned value is the rounded
+     * down to milliseconds value of
+     * {@link #getFractionalSecond()}. When {@link #getFractionalSecond()}
+     * returns <code>null</code>, this method must return
+     * {@link DatatypeConstants#FIELD_UNDEFINED}.</p>
+     *
+     * <p>Value constraints for this value are summarized in
+     * <a href="#datetimefield-second">second field of date/time field mapping table</a>.</p>
+     *
+     * @return Millisecond  of this <code>XMLGregorianCalendar</code>.
+     *
+     * @see #getFractionalSecond()
+     * @see #setTime(int, int, int)
+     */
+    public int getMillisecond() {
+
+        BigDecimal fractionalSeconds = getFractionalSecond();
+
+        // is field undefined?
+        if (fractionalSeconds == null) {
+            return DatatypeConstants.FIELD_UNDEFINED;
+        }
+
+        return getFractionalSecond().movePointRight(3).intValue();
+    }
+
+    /**
+     * <p>Return fractional seconds.</p>
+     *
+     * <p><code>null</code> is returned when this optional field is not defined.</p>
+     *
+     * <p>Value constraints are detailed in
+     * <a href="#datetimefield-second">second field of date/time field mapping table</a>.</p>
+     *
+     * <p>This optional field can only have a defined value when the
+     * xs:dateTime second field, represented by {@link #getSecond()},
+     * does not return {@link DatatypeConstants#FIELD_UNDEFINED}.</p>
+     *
+     * @return fractional seconds  of this <code>XMLGregorianCalendar</code>.
+     *
+     * @see #getSecond()
+     * @see #setTime(int, int, int, BigDecimal)
+     */
+    public abstract BigDecimal getFractionalSecond();
+
+    // comparisons
+    /**
+     * <p>Compare two instances of W3C XML Schema 1.0 date/time datatypes
+     * according to partial order relation defined in
+     * <a href="http://www.w3.org/TR/xmlschema-2/#dateTime-order">W3C XML Schema 1.0 Part 2, Section 3.2.7.3,
+     * <i>Order relation on dateTime</i></a>.</p>
+     *
+     * <p><code>xsd:dateTime</code> datatype field mapping to accessors of
+     * this class are defined in
+     * <a href="#datetimefieldmapping">date/time field mapping table</a>.</p>
+     *
+     * @param xmlGregorianCalendar Instance of <code>XMLGregorianCalendar</code> to compare
+     *
+     * @return The relationship between <code>this</code> <code>XMLGregorianCalendar</code> and
+     *   the specified <code>xmlGregorianCalendar</code> as
+     *   {@link DatatypeConstants#LESSER},
+     *   {@link DatatypeConstants#EQUAL},
+     *   {@link DatatypeConstants#GREATER} or
+     *   {@link DatatypeConstants#INDETERMINATE}.
+     *
+     * @throws NullPointerException if <code>xmlGregorianCalendar</code> is null.
+     */
+    public abstract int compare(XMLGregorianCalendar xmlGregorianCalendar);
+
+    /**
+     * <p>Normalize this instance to UTC.</p>
+     *
+     * <p>2000-03-04T23:00:00+03:00 normalizes to 2000-03-04T20:00:00Z</p>
+     * <p>Implements W3C XML Schema Part 2, Section 3.2.7.3 (A).</p>
+     *
+     * @return <code>this</code> <code>XMLGregorianCalendar</code> normalized to UTC.
+     */
+    public abstract XMLGregorianCalendar normalize();
+
+    /**
+     * <p>Indicates whether parameter <code>obj</code> is "equal to" this one.</p>
+     *
+     * @param obj to compare.
+     *
+     * @return <code>true</code> when <code>obj</code> is an instance of <code>XMLGregorianCalendar</code>
+     *   and  {@link #compare(XMLGregorianCalendar obj)} returns {@link DatatypeConstants#EQUAL}, otherwise <code>false</code>.
+     */
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (obj instanceof XMLGregorianCalendar) {
+            return compare((XMLGregorianCalendar) obj) == DatatypeConstants.EQUAL;
+        }
+        return false;
+    }
+
+    /**
+     * <p>Returns a hash code consistent with the definition of the equals method.</p>
+     *
+     * @return hash code of this object.
+     */
+    public int hashCode() {
+
+        // Following two dates compare to EQUALS since in different timezones.
+        // 2000-01-15T12:00:00-05:00 == 2000-01-15T13:00:00-04:00
+        //
+        // Must ensure both instances generate same hashcode by normalizing
+        // this to UTC timezone.
+        int timezone = getTimezone();
+        if (timezone == DatatypeConstants.FIELD_UNDEFINED) {
+            timezone = 0;
+        }
+        XMLGregorianCalendar gc = this;
+        if (timezone != 0) {
+            gc = this.normalize();
+        }
+        return gc.getYear()
+        + gc.getMonth()
+        + gc.getDay()
+        + gc.getHour()
+        + gc.getMinute()
+        + gc.getSecond();
+    }
+
+    /**
+     * <p>Return the lexical representation of <code>this</code> instance.
+     * The format is specified in
+     * <a href="http://www.w3.org/TR/xmlschema-2/#dateTime-order">XML Schema 1.0 Part 2, Section 3.2.[7-14].1,
+     * <i>Lexical Representation</i>".</a></p>
+     *
+     * <p>Specific target lexical representation format is determined by
+     * {@link #getXMLSchemaType()}.</p>
+     *
+     * @return XML, as <code>String</code>, representation of this <code>XMLGregorianCalendar</code>
+     *
+     * @throws IllegalStateException if the combination of set fields
+     *    does not match one of the eight defined XML Schema builtin date/time datatypes.
+     */
+    public abstract String toXMLFormat();
+
+    /**
+     * <p>Return the name of the XML Schema date/time type that this instance
+     * maps to. Type is computed based on fields that are set.</p>
+     *
+     * <table border="2" rules="all" cellpadding="2">
+     *   <thead>
+     *     <tr>
+     *       <th align="center" colspan="7">
+     *         Required fields for XML Schema 1.0 Date/Time Datatypes.<br/>
+     *         <i>(timezone is optional for all date/time datatypes)</i>
+     *       </th>
+     *     </tr>
+     *   </thead>
+     *   <tbody>
+     *     <tr>
+     *       <td>Datatype</td>
+     *       <td>year</td>
+     *       <td>month</td>
+     *       <td>day</td>
+     *       <td>hour</td>
+     *       <td>minute</td>
+     *       <td>second</td>
+     *     </tr>
+     *     <tr>
+     *       <td>{@link DatatypeConstants#DATETIME}</td>
+     *       <td>X</td>
+     *       <td>X</td>
+     *       <td>X</td>
+     *       <td>X</td>
+     *       <td>X</td>
+     *       <td>X</td>
+     *     </tr>
+     *     <tr>
+     *       <td>{@link DatatypeConstants#DATE}</td>
+     *       <td>X</td>
+     *       <td>X</td>
+     *       <td>X</td>
+     *       <td></td>
+     *       <td></td>
+     *       <td></td>
+     *     </tr>
+     *     <tr>
+     *       <td>{@link DatatypeConstants#TIME}</td>
+     *       <td></td>
+     *       <td></td>
+     *       <td></td>
+     *       <td>X</td>
+     *       <td>X</td>
+     *       <td>X</td>
+     *     </tr>
+     *     <tr>
+     *       <td>{@link DatatypeConstants#GYEARMONTH}</td>
+     *       <td>X</td>
+     *       <td>X</td>
+     *       <td></td>
+     *       <td></td>
+     *       <td></td>
+     *       <td></td>
+     *     </tr>
+     *     <tr>
+     *       <td>{@link DatatypeConstants#GMONTHDAY}</td>
+     *       <td></td>
+     *       <td>X</td>
+     *       <td>X</td>
+     *       <td></td>
+     *       <td></td>
+     *       <td></td>
+     *     </tr>
+     *     <tr>
+     *       <td>{@link DatatypeConstants#GYEAR}</td>
+     *       <td>X</td>
+     *       <td></td>
+     *       <td></td>
+     *       <td></td>
+     *       <td></td>
+     *       <td></td>
+     *     </tr>
+     *     <tr>
+     *       <td>{@link DatatypeConstants#GMONTH}</td>
+     *       <td></td>
+     *       <td>X</td>
+     *       <td></td>
+     *       <td></td>
+     *       <td></td>
+     *       <td></td>
+     *     </tr>
+     *     <tr>
+     *       <td>{@link DatatypeConstants#GDAY}</td>
+     *       <td></td>
+     *       <td></td>
+     *       <td>X</td>
+     *       <td></td>
+     *       <td></td>
+     *       <td></td>
+     *     </tr>
+     *   </tbody>
+     * </table>
+     *
+     * @throws java.lang.IllegalStateException if the combination of set fields
+     *    does not match one of the eight defined XML Schema builtin
+     *    date/time datatypes.
+     * @return One of the following class constants:
+     *   {@link DatatypeConstants#DATETIME},
+     *   {@link DatatypeConstants#TIME},
+     *   {@link DatatypeConstants#DATE},
+     *   {@link DatatypeConstants#GYEARMONTH},
+     *   {@link DatatypeConstants#GMONTHDAY},
+     *   {@link DatatypeConstants#GYEAR},
+     *   {@link DatatypeConstants#GMONTH} or
+     *   {@link DatatypeConstants#GDAY}.
+     */
+    public abstract QName getXMLSchemaType();
+
+    /**
+     * <p>Returns a <code>String</code> representation of this <code>XMLGregorianCalendar</code> <code>Object</code>.</p>
+     *
+     * <p>The result is a lexical representation generated by {@link #toXMLFormat()}.</p>
+     *
+     * @return A non-<code>null</code> valid <code>String</code> representation of this <code>XMLGregorianCalendar</code>.
+     *
+     * @throws IllegalStateException if the combination of set fields
+     *    does not match one of the eight defined XML Schema builtin date/time datatypes.
+     *
+     * @see #toXMLFormat()
+     */
+    public String toString() {
+
+        return toXMLFormat();
+    }
+
+    /**
+     * Validate instance by <code>getXMLSchemaType()</code> constraints.
+     * @return true if data values are valid.
+     */
+    public abstract boolean isValid();
+
+    /**
+     * <p>Add <code>duration</code> to this instance.</p>
+     *
+     * <p>The computation is specified in
+     * <a href="http://www.w3.org/TR/xmlschema-2/#adding-durations-to-dateTimes">XML Schema 1.0 Part 2, Appendix E,
+     * <i>Adding durations to dateTimes</i>></a>.
+     * <a href="#datetimefieldsmapping">date/time field mapping table</a>
+     * defines the mapping from XML Schema 1.0 <code>dateTime</code> fields
+     * to this class' representation of those fields.</p>
+     *
+     * @param duration Duration to add to this <code>XMLGregorianCalendar</code>.
+     *
+     * @throws NullPointerException  when <code>duration</code> parameter is <code>null</code>.
+     */
+    public abstract void add(Duration duration);
+
+    /**
+     * <p>Convert this <code>XMLGregorianCalendar</code> to a {@link GregorianCalendar}.</p>
+     *
+     * <p>When <code>this</code> instance has an undefined field, this
+     * conversion relies on the <code>java.util.GregorianCalendar</code> default
+     * for its corresponding field. A notable difference between
+     * XML Schema 1.0 date/time datatypes and <code>java.util.GregorianCalendar</code>
+     * is that Timezone value is optional for date/time datatypes and it is
+     * a required field for <code>java.util.GregorianCalendar</code>. See javadoc
+     * for <code>java.util.TimeZone.getDefault()</code> on how the default
+     * is determined. To explicitly specify the <code>TimeZone</code>
+     * instance, see
+     * {@link #toGregorianCalendar(TimeZone, Locale, XMLGregorianCalendar)}.</p>
+     *
+     * <table border="2" rules="all" cellpadding="2">
+     *   <thead>
+     *     <tr>
+     *       <th align="center" colspan="2">
+     *          Field by Field Conversion from this class to
+     *          <code>java.util.GregorianCalendar</code>
+     *       </th>
+     *     </tr>
+     *   </thead>
+     *   <tbody>
+     *     <tr>
+     *        <td><code>java.util.GregorianCalendar</code> field</td>
+     *        <td><code>javax.xml.datatype.XMLGregorianCalendar</code> field</td>
+     *     </tr>
+     *     <tr>
+     *       <td><code>ERA</code></td>
+     *       <td>{@link #getEonAndYear()}<code>.signum() < 0 ? GregorianCalendar.BC : GregorianCalendar.AD</code></td>
+     *     </tr>
+     *     <tr>
+     *       <td><code>YEAR</code></td>
+     *       <td>{@link #getEonAndYear()}<code>.abs().intValue()</code><i>*</i></td>
+     *     </tr>
+     *     <tr>
+     *       <td><code>MONTH</code></td>
+     *       <td>{@link #getMonth()} - {@link DatatypeConstants#JANUARY} + {@link GregorianCalendar#JANUARY}</td>
+     *     </tr>
+     *     <tr>
+     *       <td><code>DAY_OF_MONTH</code></td>
+     *       <td>{@link #getDay()}</td>
+     *     </tr>
+     *     <tr>
+     *       <td><code>HOUR_OF_DAY</code></td>
+     *       <td>{@link #getHour()}</td>
+     *     </tr>
+     *     <tr>
+     *       <td><code>MINUTE</code></td>
+     *       <td>{@link #getMinute()}</td>
+     *     </tr>
+     *     <tr>
+     *       <td><code>SECOND</code></td>
+     *       <td>{@link #getSecond()}</td>
+     *     </tr>
+     *     <tr>
+     *       <td><code>MILLISECOND</code></td>
+     *       <td>get millisecond order from {@link #getFractionalSecond()}<i>*</i> </td>
+     *     </tr>
+     *     <tr>
+     *       <td><code>GregorianCalendar.setTimeZone(TimeZone)</code></td>
+     *       <td>{@link #getTimezone()} formatted into Custom timezone id</td>
+     *     </tr>
+     *   </tbody>
+     * </table>
+     * <i>*</i> designates possible loss of precision during the conversion due
+     * to source datatype having higher precision than target datatype.
+     *
+     * <p>To ensure consistency in conversion implementations, the new
+     * <code>GregorianCalendar</code> should be instantiated in following
+     * manner.
+     * <ul>
+     *   <li>Using <code>timeZone</code> value as defined above, create a new
+     * <code>java.util.GregorianCalendar(timeZone,Locale.getDefault())</code>.
+     *   </li>
+     *   <li>Initialize all GregorianCalendar fields by calling {(@link GegorianCalendar#clear()}.</li>
+     *   <li>Obtain a pure Gregorian Calendar by invoking
+     *   <code>GregorianCalendar.setGregorianChange(
+     *   new Date(Long.MIN_VALUE))</code>.</li>
+     *   <li>Its fields ERA, YEAR, MONTH, DAY_OF_MONTH, HOUR_OF_DAY,
+     *       MINUTE, SECOND and MILLISECOND are set using the method
+     *       <code>Calendar.set(int,int)</code></li>
+     * </ul>
+     * </p>
+     *
+     * @see #toGregorianCalendar(java.util.TimeZone, java.util.Locale, XMLGregorianCalendar)
+     */
+    public abstract GregorianCalendar toGregorianCalendar();
+
+    /**
+     * <p>Convert this <code>XMLGregorianCalendar</code> along with provided parameters
+     * to a {@link GregorianCalendar} instance.</p>
+     *
+     * <p> Since XML Schema 1.0 date/time datetypes has no concept of
+     * timezone ids or daylight savings timezone ids, this conversion operation
+     * allows the user to explicitly specify one with
+     * <code>timezone</code> parameter.</p>
+     *
+     * <p>To compute the return value's <code>TimeZone</code> field,
+     * <ul>
+     * <li>when parameter <code>timeZone</code> is non-null,
+     * it is the timezone field.</li>
+     * <li>else when <code>this.getTimezone() != FIELD_UNDEFINED</code>,
+     * create a <code>java.util.TimeZone</code> with a custom timezone id
+     * using the <code>this.getTimezone()</code>.</li>
+     * <li>else when <code>defaults.getTimezone() != FIELD_UNDEFINED</code>,
+     * create a <code>java.util.TimeZone</code> with a custom timezone id
+     * using <code>defaults.getTimezone()</code>.</li>
+     * <li>else use the <code>GregorianCalendar</code> default timezone value
+     * for the host is defined as specified by
+     * <code>java.util.TimeZone.getDefault()</code>.</li></ul></p>
+     *
+     * <p>To ensure consistency in conversion implementations, the new
+     * <code>GregorianCalendar</code> should be instantiated in following
+     * manner.
+     * <ul>
+     *   <li>Create a new <code>java.util.GregorianCalendar(TimeZone,
+     *       Locale)</code> with TimeZone set as specified above and the
+     *       <code>Locale</code> parameter.
+     *   </li>
+     *   <li>Initialize all GregorianCalendar fields by calling {@link GregorianCalendar#clear()}</li>
+     *   <li>Obtain a pure Gregorian Calendar by invoking
+     *   <code>GregorianCalendar.setGregorianChange(
+     *   new Date(Long.MIN_VALUE))</code>.</li>
+     *   <li>Its fields ERA, YEAR, MONTH, DAY_OF_MONTH, HOUR_OF_DAY,
+     *       MINUTE, SECOND and MILLISECOND are set using the method
+     *       <code>Calendar.set(int,int)</code></li>
+     * </ul></p>
+     *
+     * @param timezone provide Timezone. <code>null</code> is a legal value.
+     * @param aLocale  provide explicit Locale. Use default GregorianCalendar locale if
+     *                 value is <code>null</code>.
+     * @param defaults provide default field values to use when corresponding
+     *                 field for this instance is FIELD_UNDEFINED or null.
+     *                 If <code>defaults</code>is <code>null</code> or a field
+     *                 within the specified <code>defaults</code> is undefined,
+     *                 just use <code>java.util.GregorianCalendar</code> defaults.
+     * @return a java.util.GregorianCalendar conversion of this instance.
+     */
+    public abstract GregorianCalendar toGregorianCalendar(
+        java.util.TimeZone timezone,
+        java.util.Locale aLocale,
+        XMLGregorianCalendar defaults);
+
+    /**
+     * <p>Returns a <code>java.util.TimeZone</code> for this class.</p>
+     *
+     * <p>If timezone field is defined for this instance,
+     * returns TimeZone initialized with custom timezone id
+     * of zoneoffset. If timezone field is undefined,
+     * try the defaultZoneoffset that was passed in.
+     * If defaultZoneoffset is FIELD_UNDEFINED, return
+     * default timezone for this host.
+     * (Same default as java.util.GregorianCalendar).</p>
+     *
+     * @param defaultZoneoffset default zoneoffset if this zoneoffset is
+     * {@link DatatypeConstants#FIELD_UNDEFINED}.
+     *
+     * @return TimeZone for this.
+     */
+    public abstract TimeZone getTimeZone(int defaultZoneoffset);
+
+    /**
+     * <p>Creates and returns a copy of this object.</p>
+     *
+     * @return copy of this <code>Object</code>
+     */
+    public abstract Object clone();
+}
diff --git a/javax/xml/namespace/NamespaceContext.java b/javax/xml/namespace/NamespaceContext.java
new file mode 100644
index 0000000..2d3024a
--- /dev/null
+++ b/javax/xml/namespace/NamespaceContext.java
@@ -0,0 +1,256 @@
+/*
+ * 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.
+ */
+
+// $Id: NamespaceContext.java 446598 2006-09-15 12:55:40Z jeremias $
+
+package javax.xml.namespace;
+
+import java.util.Iterator;
+
+/**
+ * <p>Interface for read only XML Namespace context processing.</p>
+ *
+ * <p>An XML Namespace has the properties:</p>
+ * <ul>
+ *   <li>Namespace URI:
+ *       Namespace name expressed as a URI to which the prefix is bound</li>
+ *   <li>prefix: syntactically, this is the part of the attribute name
+ *       following the <code>XMLConstants.XMLNS_ATTRIBUTE</code>
+ *       ("xmlns") in the Namespace declaration</li>
+ * </ul>
+ * <p> example: <code>&lt;element xmlns:prefix="http://Namespace-name-URI"&gt;</code></p>
+ *
+ * <p>All <code>get*(*)</code> methods operate in the current scope
+ * for Namespace URI and prefix resolution.</p>
+ *
+ * <p>Note that a Namespace URI can be bound to
+ * <strong>multiple</strong> prefixes in the current scope.  This can
+ * occur when multiple <code>XMLConstants.XMLNS_ATTRIBUTE</code>
+ * ("xmlns") Namespace declarations occur in the same Start-Tag and
+ * refer to the same Namespace URI. e.g.<br />
+ * <pre>
+ * &lt;element xmlns:prefix1="http://Namespace-name-URI"
+ *          xmlns:prefix2="http://Namespace-name-URI"&gt;
+ * </pre>
+ * This can also occur when the same Namespace URI is used in multiple
+ * <code>XMLConstants.XMLNS_ATTRIBUTE</code> ("xmlns") Namespace
+ * declarations in the logical parent element hierarchy.  e.g.<br />
+ * <pre>
+ * &lt;parent xmlns:prefix1="http://Namespace-name-URI">
+ *   &lt;child xmlns:prefix2="http://Namespace-name-URI"&gt;
+ *     ...
+ *   &lt;/child&gt;
+ * &lt;/parent&gt;
+ * </pre></p>
+ *
+ * <p>A prefix can only be bound to a <strong>single</strong>
+ * Namespace URI in the current scope.</p>
+ *
+ * @author <a href="mailto:[email protected]">Jeff Suttor</a>
+ * @version $Revision: 446598 $, $Date: 2006-09-15 05:55:40 -0700 (Fri, 15 Sep 2006) $
+ * @see javax.xml.XMLConstants javax.XMLConstants for declarations of common XML values
+ * @see <a href="http://www.w3.org/TR/xmlschema-2/#QName">XML Schema Part2: Datatypes</a>
+ * @see <a href="http://www.w3.org/TR/REC-xml-names/#ns-qualnames">Namespaces in XML</a>
+ * @see <a href="http://www.w3.org/XML/xml-names-19990114-errata">Namespaces in XML Errata</a>
+ * @since 1.5
+ */
+
+public interface NamespaceContext {
+
+    /**
+     * <p>Get Namespace URI bound to a prefix in the current scope.</p>
+     *
+     * <p>When requesting a Namespace URI by prefix, the following
+     * table describes the returned Namespace URI value for all
+     * possible prefix values:</p>
+     *
+     * <table border="2" rules="all" cellpadding="4">
+     *   <thead>
+     *     <tr>
+     *       <td align="center" colspan="2">
+     *         <code>getNamespaceURI(prefix)</code>
+     *         return value for specified prefixes
+     *       </td>
+     *     </tr>
+     *     <tr>
+     *       <td>prefix parameter</td>
+     *       <td>Namespace URI return value</td>
+     *     </tr>
+     *   </thead>
+     *   <tbody>
+     *     <tr>
+     *       <td><code>DEFAULT_NS_PREFIX</code> ("")</td>
+     *       <td>default Namespace URI in the current scope or
+     *         <code>{@link javax.xml.XMLConstants#NULL_NS_URI XMLConstants.NULL_NS_URI("")}</code>
+     *         when there is no default Namespace URI in the current scope</td>
+     *     </tr>
+     *     <tr>
+     *       <td>bound prefix</td>
+     *       <td>Namespace URI bound to prefix in current scope</td>
+     *     </tr>
+     *     <tr>
+     *       <td>unbound prefix</td>
+     *       <td><code>{@link javax.xml.XMLConstants#NULL_NS_URI XMLConstants.NULL_NS_URI("")}</code> </td>
+     *     </tr>
+     *     <tr>
+     *       <td><code>XMLConstants.XML_NS_PREFIX</code> ("xml")</td>
+     *       <td><code>XMLConstants.XML_NS_URI</code>
+     *           ("http://www.w3.org/XML/1998/namespace")</td>
+     *     </tr>
+     *     <tr>
+     *       <td><code>XMLConstants.XMLNS_ATTRIBUTE</code> ("xmlns")</td>
+     *       <td><code>XMLConstants.XMLNS_ATTRIBUTE_NS_URI</code>
+     *         ("http://www.w3.org/2000/xmlns/")</td>
+     *     </tr>
+     *     <tr>
+     *       <td><code>null</code></td>
+     *       <td><code>IllegalArgumentException</code> is thrown</td>
+     *     </tr>
+     *    </tbody>
+     * </table>
+     *
+     * @param prefix prefix to look up
+     * @return Namespace URI bound to prefix in the current scope
+     */
+    String getNamespaceURI(String prefix);
+
+    /**
+     * <p>Get prefix bound to Namespace URI in the current scope.</p>
+     *
+     * <p>To get all prefixes bound to a Namespace URI in the current
+     * scope, use {@link #getPrefixes(String namespaceURI)}.</p>
+     *
+     * <p>When requesting a prefix by Namespace URI, the following
+     * table describes the returned prefix value for all Namespace URI
+     * values:</p>
+     *
+     * <table border="2" rules="all" cellpadding="4">
+     *   <thead>
+     *     <tr>
+     *       <td align="center" colspan="2">
+     *         <code>getPrefix(namespaceURI)</code> return value for
+     *         specified Namespace URIs
+     *       </td>
+     *     </tr>
+     *     <tr>
+     *       <td>Namespace URI parameter</td>
+     *       <td>prefix value returned</td>
+     *     </tr>
+     *   </thead>
+     *   <tbody>
+     *     <tr>
+     *       <td>&lt;default Namespace URI&gt;</td>
+     *       <td><code>XMLConstants.DEFAULT_NS_PREFIX</code> ("")
+     *       </td>
+     *     </tr>
+     *     <tr>
+     *       <td>bound Namespace URI</td>
+     *       <td>prefix bound to Namespace URI in the current scope,
+     *           if multiple prefixes are bound to the Namespace URI in
+     *           the current scope, a single arbitrary prefix, whose
+     *           choice is implementation dependent, is returned</td>
+     *     </tr>
+     *     <tr>
+     *       <td>unbound Namespace URI</td>
+     *       <td><code>null</code></td>
+     *     </tr>
+     *     <tr>
+     *       <td><code>XMLConstants.XML_NS_URI</code>
+     *           ("http://www.w3.org/XML/1998/namespace")</td>
+     *       <td><code>XMLConstants.XML_NS_PREFIX</code> ("xml")</td>
+     *     </tr>
+     *     <tr>
+     *       <td><code>XMLConstants.XMLNS_ATTRIBUTE_NS_URI</code>
+     *           ("http://www.w3.org/2000/xmlns/")</td>
+     *       <td><code>XMLConstants.XMLNS_ATTRIBUTE</code> ("xmlns")</td>
+     *     </tr>
+     *     <tr>
+     *       <td><code>null</code></td>
+     *       <td><code>IllegalArgumentException</code> is thrown</td>
+     *     </tr>
+     *   </tbody>
+     * </table>
+     *
+     * @param namespaceURI URI of Namespace to lookup
+     * @return prefix bound to Namespace URI in current context
+     */
+    String getPrefix(String namespaceURI);
+
+    /**
+     * <p>Get all prefixes bound to a Namespace URI in the current
+     * scope.</p>
+     *
+     * <p>An Iterator over String elements is returned in an arbitrary, <strong>implementation dependent</strong>, order.</p>
+     *
+     * <p><strong>The <code>Iterator</code> is
+     * <em>not</em> modifiable.  e.g. the
+     * <code>remove()</code> method will throw
+     * <code>UnsupportedOperationException</code>.</strong></p>
+     *
+     * <p>When requesting prefixes by Namespace URI, the following
+     * table describes the returned prefixes value for all Namespace
+     * URI values:</p>
+     *
+     * <table border="2" rules="all" cellpadding="4">
+     *   <thead>
+     *     <tr>
+     *       <td align="center" colspan="2"><code>
+     *         getPrefixes(namespaceURI)</code> return value for
+     *         specified Namespace URIs</td>
+     *     </tr>
+     *     <tr>
+     *       <td>Namespace URI parameter</td>
+     *       <td>prefixes value returned</td>
+     *     </tr>
+     *   </thead>
+     *   <tbody>
+     *     <tr>
+     *       <td>bound Namespace URI,
+     *         including the &lt;default Namespace URI&gt;</td>
+     *       <td><code>Iterator</code> over prefixes bound to Namespace URI in
+     *         the current scope in an arbitrary, <strong>implementation dependent</strong>,
+     *         order</td>
+     *     </tr>
+     *     <tr>
+     *       <td>unbound Namespace URI</td>
+     *       <td>empty <code>Iterator</code></td>
+     *     </tr>
+     *     <tr>
+     *       <td><code>XMLConstants.XML_NS_URI</code>
+     *           ("http://www.w3.org/XML/1998/namespace")</td>
+     *       <td><code>Iterator</code> with one element set to
+     *         <code>XMLConstants.XML_NS_PREFIX</code> ("xml")</td>
+     *     </tr>
+     *     <tr>
+     *       <td><code>XMLConstants.XMLNS_ATTRIBUTE_NS_URI</code>
+     *           ("http://www.w3.org/2000/xmlns/")</td>
+     *       <td><code>Iterator</code> with one element set to
+     *         <code>XMLConstants.XMLNS_ATTRIBUTE</code> ("xmlns")</td>
+     *     </tr>
+     *     <tr>
+     *       <td><code>null</code></td>
+     *       <td><code>IllegalArgumentException</code> is thrown</td>
+     *     </tr>
+     *   </tbody>
+     * </table>
+     *
+     * @param namespaceURI URI of Namespace to lookup
+     * @return <code>Iterator</code> for all prefixes bound to the
+     * Namespace URI in the current scope
+     */
+    Iterator getPrefixes(String namespaceURI);
+}
diff --git a/javax/xml/namespace/QName.java b/javax/xml/namespace/QName.java
new file mode 100644
index 0000000..a82487f
--- /dev/null
+++ b/javax/xml/namespace/QName.java
@@ -0,0 +1,484 @@
+/*
+ * 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.
+ */
+
+// $Id: QName.java 754581 2009-03-15 01:32:39Z mrglavas $
+
+package javax.xml.namespace;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import javax.xml.XMLConstants;
+
+/**
+ * <p><code>QName</code> represents a <strong>qualified name</strong>
+ * as defined in the XML specifications: <a
+ * href="http://www.w3.org/TR/xmlschema-2/#QName">XML Schema Part2:
+ * Datatypes specification</a>, <a
+ * href="http://www.w3.org/TR/REC-xml-names/#ns-qualnames">Namespaces
+ * in XML</a>, <a
+ * href="http://www.w3.org/XML/xml-names-19990114-errata">Namespaces
+ * in XML Errata</a>.</p>
+ *
+ * <p>The value of a <code>QName</code> contains a <strong>Namespace
+ * URI</strong>, <strong>local part</strong> and
+ * <strong>prefix</strong>.</p>
+ *
+ * <p>The prefix is included in <code>QName</code> to retain lexical
+ * information <strong><em>when present</em></strong> in an {@link
+ * javax.xml.transform.Source XML input source}. The prefix is
+ * <strong><em>NOT</em></strong> used in {@link #equals(Object)
+ * QName.equals(Object)} or to compute the {@link #hashCode()
+ * QName.hashCode()}.  Equality and the hash code are defined using
+ * <strong><em>only</em></strong> the Namespace URI and local part.</p>
+ *
+ * <p>If not specified, the Namespace URI is set to {@link
+ * javax.xml.XMLConstants#NULL_NS_URI XMLConstants.NULL_NS_URI}.
+ * If not specified, the prefix is set to {@link
+ * javax.xml.XMLConstants#DEFAULT_NS_PREFIX
+ * XMLConstants.DEFAULT_NS_PREFIX}.</p>
+ *
+ * <p><code>QName</code> is immutable.</p>
+ *
+ * @author <a href="mailto:[email protected]">Jeff Suttor</a>
+ * @version $Revision: 754581 $, $Date: 2009-03-14 18:32:39 -0700 (Sat, 14 Mar 2009) $
+ * @see <a href="http://www.w3.org/TR/xmlschema-2/#QName">XML Schema Part2: Datatypes specification</a>
+ * @see <a href="http://www.w3.org/TR/REC-xml-names/#ns-qualnames">Namespaces in XML</a>
+ * @see <a href="http://www.w3.org/XML/xml-names-19990114-errata">Namespaces in XML Errata</a>
+ * @since 1.5
+ */
+
+public class QName implements Serializable {
+
+    /**
+     * <p>Stream Unique Identifier.</p>
+     *
+     * <p>To enable the compatibility <code>serialVersionUID</code>
+     * set the System Property
+     * <code>org.apache.xml.namespace.QName.useCompatibleSerialVersionUID</code>
+     * to a value of "1.0".</p>
+     */
+    private static final long serialVersionUID;
+
+    /**
+     * <p>The original default Stream Unique Identifier.</p>
+     */
+    private static final long defaultSerialVersionUID = -9120448754896609940L;
+
+    /**
+     * <p>The compatibility Stream Unique Identifier that was introduced
+     * with Java 5 SE SDK.</p>
+     */
+    private static final long compatibilitySerialVersionUID = 4418622981026545151L;
+
+    static {
+        String compatPropValue = System.getProperty("org.apache.xml.namespace.QName.useCompatibleSerialVersionUID");
+        // If 1.0 use compatibility serialVersionUID
+        serialVersionUID = !"1.0".equals(compatPropValue) ? defaultSerialVersionUID : compatibilitySerialVersionUID;
+    }
+
+    /**
+     * <p>Namespace URI of this <code>QName</code>.</p>
+     */
+    private final String namespaceURI;
+
+    /**
+     * <p>local part of this <code>QName</code>.</p>
+     */
+    private final String localPart;
+
+    /**
+     * <p>prefix of this <code>QName</code>.</p>
+     */
+    private String prefix;
+
+    /**
+     * <p><code>String</code> representation of this <code>QName</code>.</p>
+     */
+    private transient String qNameAsString;
+
+    /**
+     * <p><code>QName</code> constructor specifying the Namespace URI
+     * and local part.</p>
+     *
+     * <p>If the Namespace URI is <code>null</code>, it is set to
+     * {@link javax.xml.XMLConstants#NULL_NS_URI
+     * XMLConstants.NULL_NS_URI}.  This value represents no
+     * explicitly defined Namespace as defined by the <a
+     * href="http://www.w3.org/TR/REC-xml-names/#ns-qualnames">Namespaces
+     * in XML</a> specification.  This action preserves compatible
+     * behavior with QName 1.0.  Explicitly providing the {@link
+     * javax.xml.XMLConstants#NULL_NS_URI
+     * XMLConstants.NULL_NS_URI} value is the preferred coding
+     * style.</p>
+     *
+     * <p>If the local part is <code>null</code> an
+     * <code>IllegalArgumentException</code> is thrown.
+     * A local part of "" is allowed to preserve
+     * compatible behavior with QName 1.0. </p>
+     *
+     * <p>When using this constructor, the prefix is set to {@link
+     * javax.xml.XMLConstants#DEFAULT_NS_PREFIX
+     * XMLConstants.DEFAULT_NS_PREFIX}.</p>
+     *
+     * <p>The Namespace URI is not validated as a
+     * <a href="http://www.ietf.org/rfc/rfc2396.txt">URI reference</a>.
+     * The local part is not validated as a
+     * <a href="http://www.w3.org/TR/REC-xml-names/#NT-NCName">NCName</a>
+     * as specified in <a href="http://www.w3.org/TR/REC-xml-names/">Namespaces
+     * in XML</a>.</p>
+     *
+     * @param namespaceURI Namespace URI of the <code>QName</code>
+     * @param localPart    local part of the <code>QName</code>
+     *
+     * @see #QName(String namespaceURI, String localPart, String
+     * prefix) QName(String namespaceURI, String localPart, String
+     * prefix)
+     */
+    public QName(final String namespaceURI, final String localPart) {
+        this(namespaceURI, localPart, XMLConstants.DEFAULT_NS_PREFIX);
+    }
+
+    /**
+     * <p><code>QName</code> constructor specifying the Namespace URI,
+     * local part and prefix.</p>
+     *
+     * <p>If the Namespace URI is <code>null</code>, it is set to
+     * {@link javax.xml.XMLConstants#NULL_NS_URI
+     * XMLConstants.NULL_NS_URI}.  This value represents no
+     * explicitly defined Namespace as defined by the <a
+     * href="http://www.w3.org/TR/REC-xml-names/#ns-qualnames">Namespaces
+     * in XML</a> specification.  This action preserves compatible
+     * behavior with QName 1.0.  Explicitly providing the {@link
+     * javax.xml.XMLConstants#NULL_NS_URI
+     * XMLConstants.NULL_NS_URI} value is the preferred coding
+     * style.</p>
+     *
+     * <p>If the local part is <code>null</code> an
+     * <code>IllegalArgumentException</code> is thrown.
+     * A local part of "" is allowed to preserve
+     * compatible behavior with QName 1.0. </p>
+     *
+     * <p>If the prefix is <code>null</code>, an
+     * <code>IllegalArgumentException</code> is thrown.  Use {@link
+     * javax.xml.XMLConstants#DEFAULT_NS_PREFIX
+     * XMLConstants.DEFAULT_NS_PREFIX} to explicitly indicate that no
+     * prefix is present or the prefix is not relevant.</p>
+     *
+     * <p>The Namespace URI is not validated as a
+     * <a href="http://www.ietf.org/rfc/rfc2396.txt">URI reference</a>.
+     * The local part and prefix are not validated as a
+     * <a href="http://www.w3.org/TR/REC-xml-names/#NT-NCName">NCName</a>
+     * as specified in <a href="http://www.w3.org/TR/REC-xml-names/">Namespaces
+     * in XML</a>.</p>
+     *
+     * @param namespaceURI Namespace URI of the <code>QName</code>
+     * @param localPart    local part of the <code>QName</code>
+     * @param prefix       prefix of the <code>QName</code>
+     */
+    public QName(String namespaceURI, String localPart, String prefix) {
+
+        // map null Namespace URI to default to preserve compatibility with QName 1.0
+        if (namespaceURI == null) {
+            this.namespaceURI = XMLConstants.NULL_NS_URI;
+        } else {
+            this.namespaceURI = namespaceURI;
+        }
+
+        // local part is required.  "" is allowed to preserve compatibility with QName 1.0
+        if (localPart == null) {
+            throw new IllegalArgumentException("local part cannot be \"null\" when creating a QName");
+        }
+        this.localPart = localPart;
+
+        // prefix is required
+        if (prefix == null) {
+            throw new IllegalArgumentException("prefix cannot be \"null\" when creating a QName");
+        }
+        this.prefix = prefix;
+    }
+
+    /**
+     * <p><code>QName</code> constructor specifying the local part.</p>
+     *
+     * <p>If the local part is <code>null</code> an
+     * <code>IllegalArgumentException</code> is thrown.
+     * A local part of "" is allowed to preserve
+     * compatible behavior with QName 1.0. </p>
+     *
+     * <p>When using this constructor, the Namespace URI is set to
+     * {@link javax.xml.XMLConstants#NULL_NS_URI
+     * XMLConstants.NULL_NS_URI} and the prefix is set to {@link
+     * javax.xml.XMLConstants#DEFAULT_NS_PREFIX
+     * XMLConstants.DEFAULT_NS_PREFIX}.</p>
+     *
+     * <p><em>In an XML context, all Element and Attribute names exist
+     * in the context of a Namespace.  Making this explicit during the
+     * construction of a <code>QName</code> helps prevent hard to
+     * diagnosis XML validity errors.  The constructors {@link
+     * #QName(String namespaceURI, String localPart) QName(String
+     * namespaceURI, String localPart)} and
+     * {@link #QName(String namespaceURI, String localPart, String prefix)}
+     * are preferred.</em></p>
+     *
+     * <p>The local part is not validated as a
+     * <a href="http://www.w3.org/TR/REC-xml-names/#NT-NCName">NCName</a>
+     * as specified in <a href="http://www.w3.org/TR/REC-xml-names/">Namespaces
+     * in XML</a>.</p>
+     *
+     * @param localPart local part of the <code>QName</code>
+     * @see #QName(String namespaceURI, String localPart) QName(String
+     * namespaceURI, String localPart)
+     * @see #QName(String namespaceURI, String localPart, String
+     * prefix) QName(String namespaceURI, String localPart, String
+     * prefix)
+     */
+    public QName(String localPart) {
+        this(
+            XMLConstants.NULL_NS_URI,
+            localPart,
+            XMLConstants.DEFAULT_NS_PREFIX);
+    }
+
+    /**
+     * <p>Get the Namespace URI of this <code>QName</code>.</p>
+     *
+     * @return Namespace URI of this <code>QName</code>
+     */
+    public String getNamespaceURI() {
+        return namespaceURI;
+    }
+
+    /**
+     * <p>Get the local part of this <code>QName</code>.</p>
+     *
+     *  @return local part of this <code>QName</code>
+     */
+    public String getLocalPart() {
+        return localPart;
+    }
+
+    /**
+     * <p>Get the prefix of this <code>QName</code>.</p>
+     *
+     * <p>The prefix assigned to a <code>QName</code> might
+     * <strong><em>NOT</em></strong> be valid in a different
+     * context. For example, a <code>QName</code> may be assigned a
+     * prefix in the context of parsing a document but that prefix may
+     * be invalid in the context of a different document.</p>
+     *
+     *  @return prefix of this <code>QName</code>
+     */
+    public String getPrefix() {
+        return prefix;
+    }
+
+    /**
+     * <p>Test this <code>QName</code> for equality with another
+     * <code>Object</code>.</p>
+     *
+     * <p>If the <code>Object</code> to be tested is not a
+     * <code>QName</code> or is <code>null</code>, then this method
+     * returns <code>false</code>.</p>
+     *
+     * <p>Two <code>QName</code>s are considered equal if and only if
+     * both the Namespace URI and local part are equal. This method
+     * uses <code>String.equals()</code> to check equality of the
+     * Namespace URI and local part. The prefix is
+     * <strong><em>NOT</em></strong> used to determine equality.</p>
+     *
+     * <p>This method satisfies the general contract of {@link
+     * java.lang.Object#equals(Object) Object.equals(Object)}</p>
+     *
+     * @param objectToTest the <code>Object</code> to test for
+     * equality with this <code>QName</code>
+     * @return <code>true</code> if the given <code>Object</code> is
+     * equal to this <code>QName</code> else <code>false</code>
+     */
+    public final boolean equals(Object objectToTest) {
+        // Is this the same object?
+        if (objectToTest == this) {
+            return true;
+        }
+        // Is this a QName?
+        if (objectToTest instanceof QName) {
+            QName qName = (QName) objectToTest;
+            return localPart.equals(qName.localPart) && namespaceURI.equals(qName.namespaceURI);
+        }
+        return false;
+    }
+
+    /**
+     * <p>Generate the hash code for this <code>QName</code>.</p>
+     *
+     * <p>The hash code is calculated using both the Namespace URI and
+     * the local part of the <code>QName</code>.  The prefix is
+     * <strong><em>NOT</em></strong> used to calculate the hash
+     * code.</p>
+     *
+     * <p>This method satisfies the general contract of {@link
+     * java.lang.Object#hashCode() Object.hashCode()}.</p>
+     *
+     * @return hash code for this <code>QName</code> <code>Object</code>
+     */
+    public final int hashCode() {
+        return namespaceURI.hashCode() ^ localPart.hashCode();
+    }
+
+    /**
+     * <p><code>String</code> representation of this
+     * <code>QName</code>.</p>
+     *
+     * <p>The commonly accepted way of representing a <code>QName</code>
+     * as a <code>String</code> was <a href="http://jclark.com/xml/xmlns.htm">defined</a>
+     * by James Clark.  Although this is not a <em>standard</em>
+     * specification, it is in common use,  e.g. {@link javax.xml.transform.Transformer#setParameter(String name, Object value)}.
+     * This implementation represents a <code>QName</code> as:
+     * "{" + Namespace URI + "}" + local part.  If the Namespace URI
+     * <code>.equals(XMLConstants.NULL_NS_URI)</code>, only the
+     * local part is returned.  An appropriate use of this method is
+     * for debugging or logging for human consumption.</p>
+     *
+     * <p>Note the prefix value is <strong><em>NOT</em></strong>
+     * returned as part of the <code>String</code> representation.</p>
+     *
+     * <p>This method satisfies the general contract of {@link
+     * java.lang.Object#toString() Object.toString()}.</p>
+     *
+     * @return <code>String</code> representation of this <code>QName</code>
+     */
+    public String toString() {
+        String _qNameAsString = qNameAsString;
+        if (_qNameAsString == null) {
+            final int nsLength = namespaceURI.length();
+            if (nsLength == 0) {
+                _qNameAsString = localPart;
+            }
+            else {
+                StringBuilder buffer = new StringBuilder(nsLength + localPart.length() + 2);
+                buffer.append('{');
+                buffer.append(namespaceURI);
+                buffer.append('}');
+                buffer.append(localPart);
+                _qNameAsString = buffer.toString();
+            }
+            qNameAsString = _qNameAsString;
+        }
+        return _qNameAsString;
+    }
+
+    /**
+     * <p><code>QName</code> derived from parsing the formatted
+     * <code>String</code>.</p>
+     *
+     * <p>If the <code>String</code> is <code>null</code> or does not conform to
+     * {@link #toString() QName.toString()} formatting, an
+     * <code>IllegalArgumentException</code> is thrown.</p>
+     *
+     * <p><em>The <code>String</code> <strong>MUST</strong> be in the
+     * form returned by {@link #toString() QName.toString()}.</em></p>
+     *
+     * <p>The commonly accepted way of representing a <code>QName</code>
+     * as a <code>String</code> was <a href="http://jclark.com/xml/xmlns.htm">defined</a>
+     * by James Clark.  Although this is not a <em>standard</em>
+     * specification, it is in common use,  e.g. {@link javax.xml.transform.Transformer#setParameter(String name, Object value)}.
+     * This implementation parses a <code>String</code> formatted
+     * as: "{" + Namespace URI + "}" + local part.  If the Namespace
+     * URI <code>.equals(XMLConstants.NULL_NS_URI)</code>, only the
+     * local part should be provided.</p>
+     *
+     * <p>The prefix value <strong><em>CANNOT</em></strong> be
+     * represented in the <code>String</code> and will be set to
+     * {@link javax.xml.XMLConstants#DEFAULT_NS_PREFIX
+     * XMLConstants.DEFAULT_NS_PREFIX}.</p>
+     *
+     * <p>This method does not do full validation of the resulting
+     * <code>QName</code>.
+     * <p>The Namespace URI is not validated as a
+     * <a href="http://www.ietf.org/rfc/rfc2396.txt">URI reference</a>.
+     * The local part is not validated as a
+     * <a href="http://www.w3.org/TR/REC-xml-names/#NT-NCName">NCName</a>
+     * as specified in
+     * <a href="http://www.w3.org/TR/REC-xml-names/">Namespaces in XML</a>.</p>
+     *
+     * @param qNameAsString <code>String</code> representation
+     * of the <code>QName</code>
+     * @return <code>QName</code> corresponding to the given <code>String</code>
+     * @see #toString() QName.toString()
+     */
+    public static QName valueOf(String qNameAsString) {
+
+        // null is not valid
+        if (qNameAsString == null) {
+            throw new IllegalArgumentException("cannot create QName from \"null\" or \"\" String");
+        }
+
+        // "" local part is valid to preserve compatible behavior with QName 1.0
+        if (qNameAsString.length() == 0) {
+            return new QName(
+                XMLConstants.NULL_NS_URI,
+                qNameAsString,
+                XMLConstants.DEFAULT_NS_PREFIX);
+        }
+
+        // local part only?
+        if (qNameAsString.charAt(0) != '{') {
+            return new QName(
+                XMLConstants.NULL_NS_URI,
+                qNameAsString,
+                XMLConstants.DEFAULT_NS_PREFIX);
+        }
+
+        // Namespace URI improperly specified?
+        if (qNameAsString.startsWith("{" + XMLConstants.NULL_NS_URI + "}")) {
+            throw new IllegalArgumentException(
+                "Namespace URI .equals(XMLConstants.NULL_NS_URI), "
+                + ".equals(\"" + XMLConstants.NULL_NS_URI + "\"), "
+                + "only the local part, "
+                + "\"" + qNameAsString.substring(2 + XMLConstants.NULL_NS_URI.length()) + "\", "
+                + "should be provided.");
+        }
+
+        // Namespace URI and local part specified
+        int endOfNamespaceURI = qNameAsString.indexOf('}');
+        if (endOfNamespaceURI == -1) {
+            throw new IllegalArgumentException(
+                "cannot create QName from \""
+                    + qNameAsString
+                    + "\", missing closing \"}\"");
+        }
+        return new QName(
+            qNameAsString.substring(1, endOfNamespaceURI),
+            qNameAsString.substring(endOfNamespaceURI + 1),
+            XMLConstants.DEFAULT_NS_PREFIX);
+    }
+
+    /*
+     * For old versions of QName which didn't have a prefix field,
+     * <code>ObjectInputStream.defaultReadObject()</code> will initialize
+     * the prefix to <code>null</code> instead of the empty string. This
+     * method fixes up the prefix field if it didn't exist in the serialized
+     * object.
+     */
+    private void readObject(ObjectInputStream in)
+        throws IOException, ClassNotFoundException {
+        in.defaultReadObject();
+        if (prefix == null) {
+            prefix = XMLConstants.DEFAULT_NS_PREFIX;
+        }
+    }
+}
diff --git a/javax/xml/parsers/DocumentBuilder.java b/javax/xml/parsers/DocumentBuilder.java
new file mode 100644
index 0000000..96c191f
--- /dev/null
+++ b/javax/xml/parsers/DocumentBuilder.java
@@ -0,0 +1,316 @@
+/*
+ * 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.
+ */
+
+// $Id: DocumentBuilder.java 584483 2007-10-14 02:54:48Z mrglavas $
+
+package javax.xml.parsers;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import javax.xml.validation.Schema;
+import org.w3c.dom.DOMImplementation;
+import org.w3c.dom.Document;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+/**
+ * Defines the API to obtain DOM Document instances from an XML
+ * document. Using this class, an application programmer can obtain a
+ * {@link Document} from XML.<p>
+ *
+ * An instance of this class can be obtained from the
+ * {@link DocumentBuilderFactory#newDocumentBuilder()} method. Once
+ * an instance of this class is obtained, XML can be parsed from a
+ * variety of input sources. These input sources are InputStreams,
+ * Files, URLs, and SAX InputSources.<p>
+ *
+ * Note that this class reuses several classes from the SAX API. This
+ * does not require that the implementor of the underlying DOM
+ * implementation use a SAX parser to parse XML document into a
+ * <code>Document</code>. It merely requires that the implementation
+ * communicate with the application using these existing APIs.
+ *
+ * @author <a href="mailto:[email protected]">Jeff Suttor</a>
+ * @version $Revision: 584483 $, $Date: 2007-10-13 19:54:48 -0700 (Sat, 13 Oct 2007) $
+ */
+
+public abstract class DocumentBuilder {
+
+    private static final boolean DEBUG = false;
+
+    /** Protected constructor */
+    protected DocumentBuilder () {
+    }
+
+    /**
+      * <p>Reset this <code>DocumentBuilder</code> to its original configuration.</p>
+      *
+      * <p><code>DocumentBuilder</code> is reset to the same state as when it was created with
+      * {@link DocumentBuilderFactory#newDocumentBuilder()}.
+      * <code>reset()</code> is designed to allow the reuse of existing <code>DocumentBuilder</code>s
+      * thus saving resources associated with the creation of new <code>DocumentBuilder</code>s.</p>
+      *
+      * <p>The reset <code>DocumentBuilder</code> is not guaranteed to have the same {@link EntityResolver} or {@link ErrorHandler}
+      * <code>Object</code>s, e.g. {@link Object#equals(Object obj)}.  It is guaranteed to have a functionally equal
+      * <code>EntityResolver</code> and <code>ErrorHandler</code>.</p>
+      *
+      * @since 1.5
+      */
+    public void reset() {
+
+        // implementors should override this method
+        throw new UnsupportedOperationException(
+            "This DocumentBuilder, \"" + this.getClass().getName() + "\", does not support the reset functionality."
+            + "  Specification \"" + this.getClass().getPackage().getSpecificationTitle() + "\""
+            + " version \"" + this.getClass().getPackage().getSpecificationVersion() + "\""
+            );
+    }
+
+    /**
+     * Parse the content of the given <code>InputStream</code> as an XML
+     * document and return a new DOM {@link Document} object.
+     * An <code>IllegalArgumentException</code> is thrown if the
+     * <code>InputStream</code> is null.
+     *
+     * @param is InputStream containing the content to be parsed.
+     * @return <code>Document</code> result of parsing the
+     *  <code>InputStream</code>
+     * @exception IOException If any IO errors occur.
+     * @exception SAXException If any parse errors occur.
+     * @see org.xml.sax.DocumentHandler
+     */
+
+    public Document parse(InputStream is)
+        throws SAXException, IOException {
+        if (is == null) {
+            throw new IllegalArgumentException("InputStream cannot be null");
+        }
+
+        InputSource in = new InputSource(is);
+        return parse(in);
+    }
+
+    /**
+     * Parse the content of the given <code>InputStream</code> as an
+     * XML document and return a new DOM {@link Document} object.
+     * An <code>IllegalArgumentException</code> is thrown if the
+     * <code>InputStream</code> is null.
+     *
+     * @param is InputStream containing the content to be parsed.
+     * @param systemId Provide a base for resolving relative URIs.
+     * @return A new DOM Document object.
+     * @exception IOException If any IO errors occur.
+     * @exception SAXException If any parse errors occur.
+     * @see org.xml.sax.DocumentHandler
+     */
+
+    public Document parse(InputStream is, String systemId)
+        throws SAXException, IOException {
+        if (is == null) {
+            throw new IllegalArgumentException("InputStream cannot be null");
+        }
+
+        InputSource in = new InputSource(is);
+        in.setSystemId(systemId);
+        return parse(in);
+    }
+
+    /**
+     * Parse the content of the given URI as an XML document
+     * and return a new DOM {@link Document} object.
+     * An <code>IllegalArgumentException</code> is thrown if the
+     * URI is <code>null</code> null.
+     *
+     * @param uri The location of the content to be parsed.
+     * @return A new DOM Document object.
+     * @exception IOException If any IO errors occur.
+     * @exception SAXException If any parse errors occur.
+     * @see org.xml.sax.DocumentHandler
+     */
+
+    public Document parse(String uri)
+        throws SAXException, IOException {
+        if (uri == null) {
+            throw new IllegalArgumentException("URI cannot be null");
+        }
+
+        InputSource in = new InputSource(uri);
+        return parse(in);
+    }
+
+    /**
+     * Parse the content of the given file as an XML document
+     * and return a new DOM {@link Document} object.
+     * An <code>IllegalArgumentException</code> is thrown if the
+     * <code>File</code> is <code>null</code> null.
+     *
+     * @param f The file containing the XML to parse.
+     * @exception IOException If any IO errors occur.
+     * @exception SAXException If any parse errors occur.
+     * @see org.xml.sax.DocumentHandler
+     * @return A new DOM Document object.
+     */
+
+    public Document parse(File f) throws SAXException, IOException {
+        if (f == null) {
+            throw new IllegalArgumentException("File cannot be null");
+        }
+
+        String escapedURI = FilePathToURI.filepath2URI(f.getAbsolutePath());
+
+        if (DEBUG) {
+            System.out.println("Escaped URI = " + escapedURI);
+        }
+
+        InputSource in = new InputSource(escapedURI);
+        return parse(in);
+    }
+
+    /**
+     * Parse the content of the given input source as an XML document
+     * and return a new DOM {@link Document} object.
+     * An <code>IllegalArgumentException</code> is thrown if the
+     * <code>InputSource</code> is <code>null</code> null.
+     *
+     * @param is InputSource containing the content to be parsed.
+     * @exception IOException If any IO errors occur.
+     * @exception SAXException If any parse errors occur.
+     * @see org.xml.sax.DocumentHandler
+     * @return A new DOM Document object.
+     */
+
+    public abstract Document parse(InputSource is)
+        throws  SAXException, IOException;
+
+
+    /**
+     * Indicates whether or not this parser is configured to
+     * understand namespaces.
+     *
+     * @return true if this parser is configured to understand
+     *         namespaces; false otherwise.
+     */
+
+    public abstract boolean isNamespaceAware();
+
+    /**
+     * Indicates whether or not this parser is configured to
+     * validate XML documents.
+     *
+     * @return true if this parser is configured to validate
+     *         XML documents; false otherwise.
+     */
+
+    public abstract boolean isValidating();
+
+    /**
+     * Specify the {@link EntityResolver} to be used to resolve
+     * entities present in the XML document to be parsed. Setting
+     * this to <code>null</code> will result in the underlying
+     * implementation using it's own default implementation and
+     * behavior.
+     *
+     * @param er The <code>EntityResolver</code> to be used to resolve entities
+     *           present in the XML document to be parsed.
+     */
+
+    public abstract void setEntityResolver(EntityResolver er);
+
+    /**
+     * Specify the {@link ErrorHandler} to be used by the parser.
+     * Setting this to <code>null</code> will result in the underlying
+     * implementation using it's own default implementation and
+     * behavior.
+     *
+     * @param eh The <code>ErrorHandler</code> to be used by the parser.
+     */
+
+    public abstract void setErrorHandler(ErrorHandler eh);
+
+    /**
+     * Obtain a new instance of a DOM {@link Document} object
+     * to build a DOM tree with.
+     *
+     * @return A new instance of a DOM Document object.
+     */
+
+    public abstract Document newDocument();
+
+    /**
+     * Obtain an instance of a {@link DOMImplementation} object.
+     *
+     * @return A new instance of a <code>DOMImplementation</code>.
+     */
+
+    public abstract DOMImplementation getDOMImplementation();
+
+    /** <p>Get a reference to the the {@link Schema} being used by
+     * the XML processor.</p>
+     *
+     * <p>If no schema is being used, <code>null</code> is returned.</p>
+     *
+     * @return {@link Schema} being used or <code>null</code>
+     *  if none in use
+     *
+     * @throws UnsupportedOperationException
+     *      For backward compatibility, when implementations for
+     *      earlier versions of JAXP is used, this exception will be
+     *      thrown.
+     *
+     * @since 1.5
+     */
+    public Schema getSchema() {
+        throw new UnsupportedOperationException(
+            "This parser does not support specification \""
+            + this.getClass().getPackage().getSpecificationTitle()
+            + "\" version \""
+            + this.getClass().getPackage().getSpecificationVersion()
+            + "\""
+            );
+    }
+
+
+    /**
+     * <p>Get the XInclude processing mode for this parser.</p>
+     *
+     * @return
+     *      the return value of
+     *      the {@link DocumentBuilderFactory#isXIncludeAware()}
+     *      when this parser was created from factory.
+     *
+     * @throws UnsupportedOperationException
+     *      For backward compatibility, when implementations for
+     *      earlier versions of JAXP is used, this exception will be
+     *      thrown.
+     *
+     * @since 1.5
+     *
+     * @see DocumentBuilderFactory#setXIncludeAware(boolean)
+     */
+    public boolean isXIncludeAware() {
+        throw new UnsupportedOperationException(
+            "This parser does not support specification \""
+            + this.getClass().getPackage().getSpecificationTitle()
+            + "\" version \""
+            + this.getClass().getPackage().getSpecificationVersion()
+            + "\""
+            );
+    }
+}
diff --git a/javax/xml/parsers/DocumentBuilderFactory.java b/javax/xml/parsers/DocumentBuilderFactory.java
new file mode 100644
index 0000000..a1982a1
--- /dev/null
+++ b/javax/xml/parsers/DocumentBuilderFactory.java
@@ -0,0 +1,501 @@
+/*
+ * 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.
+ */
+
+// $Id: DocumentBuilderFactory.java 884950 2009-11-27 18:46:18Z mrglavas $
+
+package javax.xml.parsers;
+
+import javax.xml.validation.Schema;
+import org.apache.harmony.xml.parsers.DocumentBuilderFactoryImpl;
+
+/**
+ * Defines a factory API that enables applications to obtain a
+ * parser that produces DOM object trees from XML documents.
+ *
+ * @author <a href="[email protected]">Jeff Suttor</a>
+ * @version $Revision: 884950 $, $Date: 2009-11-27 10:46:18 -0800 (Fri, 27 Nov 2009) $
+ */
+
+public abstract class DocumentBuilderFactory {
+
+    private boolean validating = false;
+    private boolean namespaceAware = false;
+    private boolean whitespace = false;
+    private boolean expandEntityRef = true;
+    private boolean ignoreComments = false;
+    private boolean coalescing = false;
+
+    protected DocumentBuilderFactory () {
+    }
+
+    /**
+     * Returns Android's implementation of {@code DocumentBuilderFactory}.
+     * Unlike other Java implementations, this method does not consult system
+     * properties, property files, or the services API.
+     *
+     * @return a new DocumentBuilderFactory.
+     */
+    public static DocumentBuilderFactory newInstance() {
+        // instantiate the class directly rather than using reflection
+        return new DocumentBuilderFactoryImpl();
+    }
+
+    /**
+     * Returns an instance of the named implementation of {@code DocumentBuilderFactory}.
+     *
+     * @throws FactoryConfigurationError if {@code factoryClassName} is not available or cannot be
+     *     instantiated.
+     * @since 1.6
+     */
+    public static DocumentBuilderFactory newInstance(String factoryClassName,
+            ClassLoader classLoader) {
+        if (factoryClassName == null) {
+            throw new FactoryConfigurationError("factoryClassName == null");
+        }
+        if (classLoader == null) {
+            classLoader = Thread.currentThread().getContextClassLoader();
+        }
+        try {
+            Class<?> type = classLoader != null
+                    ? classLoader.loadClass(factoryClassName)
+                    : Class.forName(factoryClassName);
+            return (DocumentBuilderFactory) type.newInstance();
+        } catch (ClassNotFoundException e) {
+            throw new FactoryConfigurationError(e);
+        } catch (InstantiationException e) {
+            throw new FactoryConfigurationError(e);
+        } catch (IllegalAccessException e) {
+            throw new FactoryConfigurationError(e);
+        }
+    }
+
+    /**
+     * Creates a new instance of a {@link javax.xml.parsers.DocumentBuilder}
+     * using the currently configured parameters.
+     *
+     * @exception ParserConfigurationException if a DocumentBuilder
+     * cannot be created which satisfies the configuration requested.
+     * @return A new instance of a DocumentBuilder.
+     */
+
+    public abstract DocumentBuilder newDocumentBuilder()
+        throws ParserConfigurationException;
+
+
+    /**
+     * Specifies that the parser produced by this code will
+     * provide support for XML namespaces. By default the value of this is set
+     * to <code>false</code>
+     *
+     * @param awareness true if the parser produced will provide support
+     *                  for XML namespaces; false otherwise.
+     */
+
+    public void setNamespaceAware(boolean awareness) {
+        this.namespaceAware = awareness;
+    }
+
+    /**
+     * Specifies that the parser produced by this code will
+     * validate documents as they are parsed. By default the value of this
+     * is set to <code>false</code>.
+     *
+     * <p>
+     * Note that "the validation" here means
+     * <a href="http://www.w3.org/TR/REC-xml#proc-types">a validating
+     * parser</a> as defined in the XML recommendation.
+     * In other words, it essentially just controls the DTD validation.
+     * (except the legacy two properties defined in JAXP 1.2.
+     * See <a href="#validationCompatibility">here</a> for more details.)
+     * </p>
+     *
+     * <p>
+     * To use modern schema languages such as W3C XML Schema or
+     * RELAX NG instead of DTD, you can configure your parser to be
+     * a non-validating parser by leaving the {@link #setValidating(boolean)}
+     * method <tt>false</tt>, then use the {@link #setSchema(Schema)}
+     * method to associate a schema to a parser.
+     * </p>
+     *
+     * @param validating true if the parser produced will validate documents
+     *                   as they are parsed; false otherwise.
+     */
+
+    public void setValidating(boolean validating) {
+        this.validating = validating;
+    }
+
+    /**
+     * Specifies that the parsers created by this  factory must eliminate
+     * whitespace in element content (sometimes known loosely as
+     * 'ignorable whitespace') when parsing XML documents (see XML Rec
+     * 2.10). Note that only whitespace which is directly contained within
+     * element content that has an element only content model (see XML
+     * Rec 3.2.1) will be eliminated. Due to reliance on the content model
+     * this setting requires the parser to be in validating mode. By default
+     * the value of this is set to <code>false</code>.
+     *
+     * @param whitespace true if the parser created must eliminate whitespace
+     *                   in the element content when parsing XML documents;
+     *                   false otherwise.
+     */
+
+    public void setIgnoringElementContentWhitespace(boolean whitespace) {
+        this.whitespace = whitespace;
+    }
+
+    /**
+     * Specifies that the parser produced by this code will
+     * expand entity reference nodes. By default the value of this is set to
+     * <code>true</code>
+     *
+     * @param expandEntityRef true if the parser produced will expand entity
+     *                        reference nodes; false otherwise.
+     */
+
+    public void setExpandEntityReferences(boolean expandEntityRef) {
+        this.expandEntityRef = expandEntityRef;
+    }
+
+    /**
+     * <p>Specifies that the parser produced by this code will
+     * ignore comments. By default the value of this is set to <code>false
+     * </code>.</p>
+     *
+     * @param ignoreComments <code>boolean</code> value to ignore comments during processing
+     */
+
+    public void setIgnoringComments(boolean ignoreComments) {
+        this.ignoreComments = ignoreComments;
+    }
+
+    /**
+     * Specifies that the parser produced by this code will
+     * convert CDATA nodes to Text nodes and append it to the
+     * adjacent (if any) text node. By default the value of this is set to
+     * <code>false</code>
+     *
+     * @param coalescing  true if the parser produced will convert CDATA nodes
+     *                    to Text nodes and append it to the adjacent (if any)
+     *                    text node; false otherwise.
+     */
+
+    public void setCoalescing(boolean coalescing) {
+        this.coalescing = coalescing;
+    }
+
+    /**
+     * Indicates whether or not the factory is configured to produce
+     * parsers which are namespace aware.
+     *
+     * @return  true if the factory is configured to produce parsers which
+     *          are namespace aware; false otherwise.
+     */
+
+    public boolean isNamespaceAware() {
+        return namespaceAware;
+    }
+
+    /**
+     * Indicates whether or not the factory is configured to produce
+     * parsers which validate the XML content during parse.
+     *
+     * @return  true if the factory is configured to produce parsers
+     *          which validate the XML content during parse; false otherwise.
+     */
+
+    public boolean isValidating() {
+        return validating;
+    }
+
+    /**
+     * Indicates whether or not the factory is configured to produce
+     * parsers which ignore ignorable whitespace in element content.
+     *
+     * @return  true if the factory is configured to produce parsers
+     *          which ignore ignorable whitespace in element content;
+     *          false otherwise.
+     */
+
+    public boolean isIgnoringElementContentWhitespace() {
+        return whitespace;
+    }
+
+    /**
+     * Indicates whether or not the factory is configured to produce
+     * parsers which expand entity reference nodes.
+     *
+     * @return  true if the factory is configured to produce parsers
+     *          which expand entity reference nodes; false otherwise.
+     */
+
+    public boolean isExpandEntityReferences() {
+        return expandEntityRef;
+    }
+
+    /**
+     * Indicates whether or not the factory is configured to produce
+     * parsers which ignores comments.
+     *
+     * @return  true if the factory is configured to produce parsers
+     *          which ignores comments; false otherwise.
+     */
+
+    public boolean isIgnoringComments() {
+        return ignoreComments;
+    }
+
+    /**
+     * Indicates whether or not the factory is configured to produce
+     * parsers which converts CDATA nodes to Text nodes and appends it to
+     * the adjacent (if any) Text node.
+     *
+     * @return  true if the factory is configured to produce parsers
+     *          which converts CDATA nodes to Text nodes and appends it to
+     *          the adjacent (if any) Text node; false otherwise.
+     */
+
+    public boolean isCoalescing() {
+        return coalescing;
+    }
+
+    /**
+     * Allows the user to set specific attributes on the underlying
+     * implementation.
+     * @param name The name of the attribute.
+     * @param value The value of the attribute.
+     * @exception IllegalArgumentException thrown if the underlying
+     * implementation doesn't recognize the attribute.
+     */
+    public abstract void setAttribute(String name, Object value)
+                throws IllegalArgumentException;
+
+    /**
+     * Allows the user to retrieve specific attributes on the underlying
+     * implementation.
+     * @param name The name of the attribute.
+     * @return value The value of the attribute.
+     * @exception IllegalArgumentException thrown if the underlying
+     * implementation doesn't recognize the attribute.
+     */
+    public abstract Object getAttribute(String name)
+                throws IllegalArgumentException;
+
+    /**
+     * <p>Set a feature for this <code>DocumentBuilderFactory</code> and <code>DocumentBuilder</code>s created by this factory.</p>
+     *
+     * <p>
+     * Feature names are fully qualified {@link java.net.URI}s.
+     * Implementations may define their own features.
+     * An {@link ParserConfigurationException} is thrown if this <code>DocumentBuilderFactory</code> or the
+     * <code>DocumentBuilder</code>s it creates cannot support the feature.
+     * It is possible for an <code>DocumentBuilderFactory</code> to expose a feature value but be unable to change its state.
+     * </p>
+     *
+     * <p>
+     * All implementations are required to support the {@link javax.xml.XMLConstants#FEATURE_SECURE_PROCESSING} feature.
+     * When the feature is:</p>
+     * <ul>
+     *   <li>
+     *     <code>true</code>: the implementation will limit XML processing to conform to implementation limits.
+     *     Examples include entity expansion limits and XML Schema constructs that would consume large amounts of resources.
+     *     If XML processing is limited for security reasons, it will be reported via a call to the registered
+     *    {@link org.xml.sax.ErrorHandler#fatalError(SAXParseException exception)}.
+     *     See {@link  DocumentBuilder#setErrorHandler(org.xml.sax.ErrorHandler errorHandler)}.
+     *   </li>
+     *   <li>
+     *     <code>false</code>: the implementation will processing XML according to the XML specifications without
+     *     regard to possible implementation limits.
+     *   </li>
+     * </ul>
+     *
+     * @param name Feature name.
+     * @param value Is feature state <code>true</code> or <code>false</code>.
+     *
+     * @throws ParserConfigurationException if this <code>DocumentBuilderFactory</code> or the <code>DocumentBuilder</code>s
+     *   it creates cannot support this feature.
+     * @throws NullPointerException If the <code>name</code> parameter is null.
+     */
+    public abstract void setFeature(String name, boolean value)
+        throws ParserConfigurationException;
+
+    /**
+     * <p>Get the state of the named feature.</p>
+     *
+     * <p>
+     * Feature names are fully qualified {@link java.net.URI}s.
+     * Implementations may define their own features.
+     * An {@link ParserConfigurationException} is thrown if this <code>DocumentBuilderFactory</code> or the
+     * <code>DocumentBuilder</code>s it creates cannot support the feature.
+     * It is possible for an <code>DocumentBuilderFactory</code> to expose a feature value but be unable to change its state.
+     * </p>
+     *
+     * @param name Feature name.
+     *
+     * @return State of the named feature.
+     *
+     * @throws ParserConfigurationException if this <code>DocumentBuilderFactory</code>
+     *   or the <code>DocumentBuilder</code>s it creates cannot support this feature.
+     */
+    public abstract boolean getFeature(String name)
+        throws ParserConfigurationException;
+
+    /**
+     * Gets the {@link Schema} object specified through
+     * the {@link #setSchema(Schema schema)} method.
+     *
+     *
+     * @throws UnsupportedOperationException
+     *      For backward compatibility, when implementations for
+     *      earlier versions of JAXP is used, this exception will be
+     *      thrown.
+     *
+     * @return
+     *      the {@link Schema} object that was last set through
+     *      the {@link #setSchema(Schema)} method, or null
+     *      if the method was not invoked since a {@link DocumentBuilderFactory}
+     *      is created.
+     *
+     * @since 1.5
+     */
+    public Schema getSchema() {
+        throw new UnsupportedOperationException(
+            "This parser does not support specification \""
+            + this.getClass().getPackage().getSpecificationTitle()
+            + "\" version \""
+            + this.getClass().getPackage().getSpecificationVersion()
+            + "\""
+            );
+
+    }
+
+    /**
+     * <p>Set the {@link Schema} to be used by parsers created
+     * from this factory.
+     *
+     * <p>
+     * When a {@link Schema} is non-null, a parser will use a validator
+     * created from it to validate documents before it passes information
+     * down to the application.
+     *
+     * <p>When errors are found by the validator, the parser is responsible
+     * to report them to the user-specified {@link org.xml.sax.ErrorHandler}
+     * (or if the error handler is not set, ignore them or throw them), just
+     * like any other errors found by the parser itself.
+     * In other words, if the user-specified {@link org.xml.sax.ErrorHandler}
+     * is set, it must receive those errors, and if not, they must be
+     * treated according to the implementation specific
+     * default error handling rules.
+     *
+     * <p>
+     * A validator may modify the outcome of a parse (for example by
+     * adding default values that were missing in documents), and a parser
+     * is responsible to make sure that the application will receive
+     * modified DOM trees.
+     *
+     * <p>
+     * Initially, null is set as the {@link Schema}.
+     *
+     * <p>
+     * This processing will take effect even if
+     * the {@link #isValidating()} method returns <tt>false</tt>.
+     *
+     * <p>It is an error to use
+     * the <code>http://java.sun.com/xml/jaxp/properties/schemaSource</code>
+     * property and/or the <code>http://java.sun.com/xml/jaxp/properties/schemaLanguage</code>
+     * property in conjunction with a {@link Schema} object.
+     * Such configuration will cause a {@link ParserConfigurationException}
+     * exception when the {@link #newDocumentBuilder()} is invoked.</p>
+     *
+     *
+     * <h4>Note for implementors</h4>
+     * <p>
+     * A parser must be able to work with any {@link Schema}
+     * implementation. However, parsers and schemas are allowed
+     * to use implementation-specific custom mechanisms
+     * as long as they yield the result described in the specification.
+     *
+     * @param schema <code>Schema</code> to use or <code>null</code> to remove a schema.
+     *
+     * @throws UnsupportedOperationException
+     *      For backward compatibility, when implementations for
+     *      earlier versions of JAXP is used, this exception will be
+     *      thrown.
+     *
+     * @since 1.5
+     */
+    public void setSchema(Schema schema) {
+        throw new UnsupportedOperationException(
+            "This parser does not support specification \""
+            + this.getClass().getPackage().getSpecificationTitle()
+            + "\" version \""
+            + this.getClass().getPackage().getSpecificationVersion()
+            + "\""
+            );
+    }
+
+    /**
+     * <p>Set state of XInclude processing.</p>
+     *
+     * <p>If XInclude markup is found in the document instance, should it be
+     * processed as specified in <a href="http://www.w3.org/TR/xinclude/">
+     * XML Inclusions (XInclude) Version 1.0</a>.</p>
+     *
+     * <p>XInclude processing defaults to <code>false</code>.</p>
+     *
+     * @param state Set XInclude processing to <code>true</code> or
+     *   <code>false</code>
+     *
+     * @throws UnsupportedOperationException
+     *      For backward compatibility, when implementations for
+     *      earlier versions of JAXP is used, this exception will be
+     *      thrown.
+     *
+     * @since 1.5
+     */
+    public void setXIncludeAware(final boolean state) {
+        throw new UnsupportedOperationException(
+            "This parser does not support specification \""
+            + this.getClass().getPackage().getSpecificationTitle()
+            + "\" version \""
+            + this.getClass().getPackage().getSpecificationVersion()
+            + "\""
+            );
+    }
+
+    /**
+     * <p>Get state of XInclude processing.</p>
+     *
+     * @return current state of XInclude processing
+     *
+     * @throws UnsupportedOperationException
+     *      For backward compatibility, when implementations for
+     *      earlier versions of JAXP is used, this exception will be
+     *      thrown.
+     *
+     * @since 1.5
+     */
+    public boolean isXIncludeAware() {
+        throw new UnsupportedOperationException(
+            "This parser does not support specification \""
+            + this.getClass().getPackage().getSpecificationTitle()
+            + "\" version \""
+            + this.getClass().getPackage().getSpecificationVersion()
+            + "\""
+            );
+    }
+}
diff --git a/javax/xml/parsers/FactoryConfigurationError.java b/javax/xml/parsers/FactoryConfigurationError.java
new file mode 100644
index 0000000..745559a
--- /dev/null
+++ b/javax/xml/parsers/FactoryConfigurationError.java
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ */
+
+// $Id: FactoryConfigurationError.java 569980 2007-08-27 03:58:15Z mrglavas $
+
+package javax.xml.parsers;
+
+/**
+ * Thrown when a problem with configuration with the Parser Factories
+ * exists. This error will typically be thrown when the class of a
+ * parser factory specified in the system properties cannot be found
+ * or instantiated.
+ *
+ * @author <a href="mailto:[email protected]">Jeff Suttor</a>
+ * @version $Revision: 569980 $, $Date: 2007-08-26 20:58:15 -0700 (Sun, 26 Aug 2007) $
+ */
+
+public class FactoryConfigurationError extends Error {
+
+    /**
+     *<code>Exception</code> that represents the error.
+     */
+    private Exception exception;
+
+    /**
+     * Create a new <code>FactoryConfigurationError</code> with no
+     * detail message.
+     */
+
+    public FactoryConfigurationError() {
+        this.exception = null;
+    }
+
+    /**
+     * Create a new <code>FactoryConfigurationError</code> with
+     * the <code>String </code> specified as an error message.
+     *
+     * @param msg The error message for the exception.
+     */
+
+    public FactoryConfigurationError(String msg) {
+        super(msg);
+        this.exception = null;
+    }
+
+
+    /**
+     * Create a new <code>FactoryConfigurationError</code> with a
+     * given <code>Exception</code> base cause of the error.
+     *
+     * @param e The exception to be encapsulated in a
+     * FactoryConfigurationError.
+     */
+
+    public FactoryConfigurationError(Exception e) {
+        super(e.toString());
+        this.exception = e;
+    }
+
+    /**
+     * Create a new <code>FactoryConfigurationError</code> with the
+     * given <code>Exception</code> base cause and detail message.
+     *
+     * @param e The exception to be encapsulated in a
+     * FactoryConfigurationError
+     * @param msg The detail message.
+     */
+
+    public FactoryConfigurationError(Exception e, String msg) {
+        super(msg);
+        this.exception = e;
+    }
+
+
+    /**
+     * Return the message (if any) for this error . If there is no
+     * message for the exception and there is an encapsulated
+     * exception then the message of that exception, if it exists will be
+     * returned. Else the name of the encapsulated exception will be
+     * returned.
+     *
+     * @return The error message.
+     */
+
+    public String getMessage () {
+        String message = super.getMessage ();
+
+        if (message == null && exception != null) {
+            return exception.getMessage();
+        }
+
+        return message;
+    }
+
+    /**
+     * Return the actual exception (if any) that caused this exception to
+     * be raised.
+     *
+     * @return The encapsulated exception, or null if there is none.
+     */
+
+    public Exception getException () {
+        return exception;
+    }
+}
diff --git a/javax/xml/parsers/FilePathToURI.java b/javax/xml/parsers/FilePathToURI.java
new file mode 100644
index 0000000..3ff38c1
--- /dev/null
+++ b/javax/xml/parsers/FilePathToURI.java
@@ -0,0 +1,129 @@
+/*
+ * 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 javax.xml.parsers;
+
+class FilePathToURI {
+
+    // which ASCII characters need to be escaped
+    private static boolean gNeedEscaping[] = new boolean[128];
+    // the first hex character if a character needs to be escaped
+    private static char[] gAfterEscaping1 = new char[128];
+    // the second hex character if a character needs to be escaped
+    private static char[] gAfterEscaping2 = new char[128];
+    private static char[] gHexChs = {'0', '1', '2', '3', '4', '5', '6', '7',
+                                     '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+    // initialize the above 3 arrays
+    static {
+        for (int i = 0; i <= 0x1f; i++) {
+            gNeedEscaping[i] = true;
+            gAfterEscaping1[i] = gHexChs[i >> 4];
+            gAfterEscaping2[i] = gHexChs[i & 0xf];
+        }
+        gNeedEscaping[0x7f] = true;
+        gAfterEscaping1[0x7f] = '7';
+        gAfterEscaping2[0x7f] = 'F';
+        char[] escChs = {' ', '<', '>', '#', '%', '"', '{', '}',
+                         '|', '\\', '^', '~', '[', ']', '`'};
+        int len = escChs.length;
+        char ch;
+        for (int i = 0; i < len; i++) {
+            ch = escChs[i];
+            gNeedEscaping[ch] = true;
+            gAfterEscaping1[ch] = gHexChs[ch >> 4];
+            gAfterEscaping2[ch] = gHexChs[ch & 0xf];
+        }
+    }
+
+    // To escape a file path to a URI, by using %HH to represent
+    // special ASCII characters: 0x00~0x1F, 0x7F, ' ', '<', '>', '#', '%'
+    // and '"' and non-ASCII characters (whose value >= 128).
+    public static String filepath2URI(String path){
+        // return null if path is null.
+        if (path == null)
+            return null;
+
+        char separator = java.io.File.separatorChar;
+        path = path.replace(separator, '/');
+
+        int len = path.length(), ch;
+        StringBuilder buffer = new StringBuilder(len*3);
+        buffer.append("file://");
+        // change C:/blah to /C:/blah
+        if (len >= 2 && path.charAt(1) == ':') {
+            ch = Character.toUpperCase(path.charAt(0));
+            if (ch >= 'A' && ch <= 'Z') {
+                buffer.append('/');
+            }
+        }
+
+        // for each character in the path
+        int i = 0;
+        for (; i < len; i++) {
+            ch = path.charAt(i);
+            // if it's not an ASCII character, break here, and use UTF-8 encoding
+            if (ch >= 128)
+                break;
+            if (gNeedEscaping[ch]) {
+                buffer.append('%');
+                buffer.append(gAfterEscaping1[ch]);
+                buffer.append(gAfterEscaping2[ch]);
+                // record the fact that it's escaped
+            }
+            else {
+                buffer.append((char)ch);
+            }
+        }
+
+        // we saw some non-ascii character
+        if (i < len) {
+            // get UTF-8 bytes for the remaining sub-string
+            byte[] bytes = null;
+            byte b;
+            try {
+                bytes = path.substring(i).getBytes("UTF-8");
+            } catch (java.io.UnsupportedEncodingException e) {
+                // should never happen
+                return path;
+            }
+            len = bytes.length;
+
+            // for each byte
+            for (i = 0; i < len; i++) {
+                b = bytes[i];
+                // for non-ascii character: make it positive, then escape
+                if (b < 0) {
+                    ch = b + 256;
+                    buffer.append('%');
+                    buffer.append(gHexChs[ch >> 4]);
+                    buffer.append(gHexChs[ch & 0xf]);
+                }
+                else if (gNeedEscaping[b]) {
+                    buffer.append('%');
+                    buffer.append(gAfterEscaping1[b]);
+                    buffer.append(gAfterEscaping2[b]);
+                }
+                else {
+                    buffer.append((char)b);
+                }
+            }
+        }
+
+        return buffer.toString();
+    }
+
+}//FilePathToURI
diff --git a/javax/xml/parsers/ParserConfigurationException.java b/javax/xml/parsers/ParserConfigurationException.java
new file mode 100644
index 0000000..6929ab7
--- /dev/null
+++ b/javax/xml/parsers/ParserConfigurationException.java
@@ -0,0 +1,51 @@
+
+/*
+ * 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.
+ */
+
+// $Id: ParserConfigurationException.java 569981 2007-08-27 03:59:07Z mrglavas $
+
+package javax.xml.parsers;
+
+/**
+ * Indicates a serious configuration error.
+ *
+ * @author <a href="mailto:[email protected]">Jeff Suttor</a>
+ * @version $Revision: 569981 $, $Date: 2007-08-26 20:59:07 -0700 (Sun, 26 Aug 2007) $
+ */
+
+public class ParserConfigurationException extends Exception {
+
+    /**
+     * Create a new <code>ParserConfigurationException</code> with no
+     * detail message.
+     */
+
+    public ParserConfigurationException() {
+    }
+
+    /**
+     * Create a new <code>ParserConfigurationException</code> with
+     * the <code>String</code> specified as an error message.
+     *
+     * @param msg The error message for the exception.
+     */
+
+    public ParserConfigurationException(String msg) {
+        super(msg);
+    }
+
+}
diff --git a/javax/xml/parsers/SAXParser.java b/javax/xml/parsers/SAXParser.java
new file mode 100644
index 0000000..d94301f
--- /dev/null
+++ b/javax/xml/parsers/SAXParser.java
@@ -0,0 +1,524 @@
+/*
+ * 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.
+ */
+
+// $Id: SAXParser.java 584483 2007-10-14 02:54:48Z mrglavas $
+
+package javax.xml.parsers;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import javax.xml.validation.Schema;
+import org.xml.sax.HandlerBase;
+import org.xml.sax.InputSource;
+import org.xml.sax.Parser;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXNotRecognizedException;
+import org.xml.sax.SAXNotSupportedException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.DefaultHandler;
+
+
+/**
+ * Defines the API that wraps an {@link org.xml.sax.XMLReader}
+ * implementation class. In JAXP 1.0, this class wrapped the
+ * {@link org.xml.sax.Parser} interface, however this interface was
+ * replaced by the {@link org.xml.sax.XMLReader}. For ease
+ * of transition, this class continues to support the same name
+ * and interface as well as supporting new methods.
+ *
+ * An instance of this class can be obtained from the
+ * {@link javax.xml.parsers.SAXParserFactory#newSAXParser()} method.
+ * Once an instance of this class is obtained, XML can be parsed from
+ * a variety of input sources. These input sources are InputStreams,
+ * Files, URLs, and SAX InputSources.<p>
+ *
+ * This static method creates a new factory instance based
+ * on a system property setting or uses the platform default
+ * if no property has been defined.<p>
+ *
+ * The system property that controls which Factory implementation
+ * to create is named <code>&quot;javax.xml.parsers.SAXParserFactory&quot;</code>.
+ * This property names a class that is a concrete subclass of this
+ * abstract class. If no property is defined, a platform default
+ * will be used.</p>
+ *
+ * As the content is parsed by the underlying parser, methods of the
+ * given {@link org.xml.sax.HandlerBase} or the
+ * {@link org.xml.sax.helpers.DefaultHandler} are called.<p>
+ *
+ * Implementations of this class which wrap an underlying implementation
+ * can consider using the {@link org.xml.sax.helpers.ParserAdapter}
+ * class to initially adapt their SAX1 implementation to work under
+ * this revised class.
+ *
+ * @author <a href="mailto:[email protected]">Jeff Suttor</a>
+ * @version $Revision: 584483 $, $Date: 2007-10-13 19:54:48 -0700 (Sat, 13 Oct 2007) $
+ */
+public abstract class SAXParser {
+
+    private static final boolean DEBUG = false;
+
+    /**
+     * <p>Protected constructor to prevent instantiation.
+     * Use {@link javax.xml.parsers.SAXParserFactory#newSAXParser()}.</p>
+     */
+    protected SAXParser () {
+
+    }
+
+    /**
+     * <p>Reset this <code>SAXParser</code> to its original configuration.</p>
+     *
+     * <p><code>SAXParser</code> is reset to the same state as when it was created with
+     * {@link SAXParserFactory#newSAXParser()}.
+     * <code>reset()</code> is designed to allow the reuse of existing <code>SAXParser</code>s
+     * thus saving resources associated with the creation of new <code>SAXParser</code>s.</p>
+     *
+     * <p>The reset <code>SAXParser</code> is not guaranteed to have the same {@link Schema}
+     * <code>Object</code>, e.g. {@link Object#equals(Object obj)}.  It is guaranteed to have a functionally equal
+     * <code>Schema</code>.</p>
+     *
+     * @since 1.5
+     */
+    public void reset() {
+
+        // implementors should override this method
+        throw new UnsupportedOperationException(
+            "This SAXParser, \"" + this.getClass().getName() + "\", does not support the reset functionality."
+            + "  Specification \"" + this.getClass().getPackage().getSpecificationTitle() + "\""
+            + " version \"" + this.getClass().getPackage().getSpecificationVersion() + "\""
+            );
+    }
+
+    /**
+     * <p>Parse the content of the given {@link java.io.InputStream}
+     * instance as XML using the specified {@link org.xml.sax.HandlerBase}.
+     * <i> Use of the DefaultHandler version of this method is recommended as
+     * the HandlerBase class has been deprecated in SAX 2.0</i>.</p>
+     *
+     * @param is InputStream containing the content to be parsed.
+     * @param hb The SAX HandlerBase to use.
+     *
+     * @throws IllegalArgumentException If the given InputStream is null.
+     * @throws SAXException If parse produces a SAX error.
+     * @throws IOException If an IO error occurs interacting with the
+     *   <code>InputStream</code>.
+     *
+     * @see org.xml.sax.DocumentHandler
+     */
+    public void parse(InputStream is, HandlerBase hb)
+        throws SAXException, IOException {
+        if (is == null) {
+            throw new IllegalArgumentException("InputStream cannot be null");
+        }
+
+        InputSource input = new InputSource(is);
+        this.parse(input, hb);
+    }
+
+    /**
+     * <p>Parse the content of the given {@link java.io.InputStream}
+     * instance as XML using the specified {@link org.xml.sax.HandlerBase}.
+     * <i> Use of the DefaultHandler version of this method is recommended as
+     * the HandlerBase class has been deprecated in SAX 2.0</i>.</p>
+     *
+     * @param is InputStream containing the content to be parsed.
+     * @param hb The SAX HandlerBase to use.
+     * @param systemId The systemId which is needed for resolving relative URIs.
+     *
+     * @throws IllegalArgumentException If the given <code>InputStream</code> is
+     *   <code>null</code>.
+     * @throws IOException If any IO error occurs interacting with the
+     *   <code>InputStream</code>.
+     * @throws SAXException If any SAX errors occur during processing.
+     *
+     * @see org.xml.sax.DocumentHandler version of this method instead.
+     */
+    public void parse(
+        InputStream is,
+        HandlerBase hb,
+        String systemId)
+        throws SAXException, IOException {
+        if (is == null) {
+            throw new IllegalArgumentException("InputStream cannot be null");
+        }
+
+        InputSource input = new InputSource(is);
+        input.setSystemId(systemId);
+        this.parse(input, hb);
+    }
+
+    /**
+     * Parse the content of the given {@link java.io.InputStream}
+     * instance as XML using the specified
+     * {@link org.xml.sax.helpers.DefaultHandler}.
+     *
+     * @param is InputStream containing the content to be parsed.
+     * @param dh The SAX DefaultHandler to use.
+     *
+     * @throws IllegalArgumentException If the given InputStream is null.
+     * @throws IOException If any IO errors occur.
+     * @throws SAXException If any SAX errors occur during processing.
+     *
+     * @see org.xml.sax.DocumentHandler
+     */
+    public void parse(InputStream is, DefaultHandler dh)
+        throws SAXException, IOException {
+        if (is == null) {
+            throw new IllegalArgumentException("InputStream cannot be null");
+        }
+
+        InputSource input = new InputSource(is);
+        this.parse(input, dh);
+    }
+
+    /**
+     * Parse the content of the given {@link java.io.InputStream}
+     * instance as XML using the specified
+     * {@link org.xml.sax.helpers.DefaultHandler}.
+     *
+     * @param is InputStream containing the content to be parsed.
+     * @param dh The SAX DefaultHandler to use.
+     * @param systemId The systemId which is needed for resolving relative URIs.
+     *
+     * @throws IllegalArgumentException If the given InputStream is null.
+     * @throws IOException If any IO errors occur.
+     * @throws SAXException If any SAX errors occur during processing.
+     *
+     * @see org.xml.sax.DocumentHandler version of this method instead.
+     */
+    public void parse(
+        InputStream is,
+        DefaultHandler dh,
+        String systemId)
+        throws SAXException, IOException {
+        if (is == null) {
+            throw new IllegalArgumentException("InputStream cannot be null");
+        }
+
+        InputSource input = new InputSource(is);
+        input.setSystemId(systemId);
+        this.parse(input, dh);
+    }
+
+    /**
+     * Parse the content described by the giving Uniform Resource
+     * Identifier (URI) as XML using the specified
+     * {@link org.xml.sax.HandlerBase}.
+     * <i> Use of the DefaultHandler version of this method is recommended as
+     * the <code>HandlerBase</code> class has been deprecated in SAX 2.0</i>
+     *
+     * @param uri The location of the content to be parsed.
+     * @param hb The SAX HandlerBase to use.
+     *
+     * @throws IllegalArgumentException If the uri is null.
+     * @throws IOException If any IO errors occur.
+     * @throws SAXException If any SAX errors occur during processing.
+     *
+     * @see org.xml.sax.DocumentHandler
+     */
+    public void parse(String uri, HandlerBase hb)
+        throws SAXException, IOException {
+        if (uri == null) {
+            throw new IllegalArgumentException("uri cannot be null");
+        }
+
+        InputSource input = new InputSource(uri);
+        this.parse(input, hb);
+    }
+
+    /**
+     * Parse the content described by the giving Uniform Resource
+     * Identifier (URI) as XML using the specified
+     * {@link org.xml.sax.helpers.DefaultHandler}.
+     *
+     * @param uri The location of the content to be parsed.
+     * @param dh The SAX DefaultHandler to use.
+     *
+     * @throws IllegalArgumentException If the uri is null.
+     * @throws IOException If any IO errors occur.
+     * @throws SAXException If any SAX errors occur during processing.
+     *
+     * @see org.xml.sax.DocumentHandler
+     */
+    public void parse(String uri, DefaultHandler dh)
+        throws SAXException, IOException {
+        if (uri == null) {
+            throw new IllegalArgumentException("uri cannot be null");
+        }
+
+        InputSource input = new InputSource(uri);
+        this.parse(input, dh);
+    }
+
+    /**
+     * Parse the content of the file specified as XML using the
+     * specified {@link org.xml.sax.HandlerBase}.
+     * <i> Use of the DefaultHandler version of this method is recommended as
+     * the HandlerBase class has been deprecated in SAX 2.0</i>
+     *
+     * @param f The file containing the XML to parse
+     * @param hb The SAX HandlerBase to use.
+     *
+     * @throws IllegalArgumentException If the File object is null.
+     * @throws IOException If any IO errors occur.
+     * @throws SAXException If any SAX errors occur during processing.
+     *
+     * @see org.xml.sax.DocumentHandler
+     */
+    public void parse(File f, HandlerBase hb)
+        throws SAXException, IOException {
+        if (f == null) {
+            throw new IllegalArgumentException("File cannot be null");
+        }
+
+        String escapedURI = FilePathToURI.filepath2URI(f.getAbsolutePath());
+
+        if (DEBUG) {
+            System.out.println("Escaped URI = " + escapedURI);
+        }
+
+        InputSource input = new InputSource(escapedURI);
+        this.parse(input, hb);
+    }
+
+    /**
+     * Parse the content of the file specified as XML using the
+     * specified {@link org.xml.sax.helpers.DefaultHandler}.
+     *
+     * @param f The file containing the XML to parse
+     * @param dh The SAX DefaultHandler to use.
+     *
+     * @throws IllegalArgumentException If the File object is null.
+     * @throws IOException If any IO errors occur.
+     * @throws SAXException If any SAX errors occur during processing.
+     *
+     * @see org.xml.sax.DocumentHandler
+     */
+    public void parse(File f, DefaultHandler dh)
+        throws SAXException, IOException {
+        if (f == null) {
+            throw new IllegalArgumentException("File cannot be null");
+        }
+
+        String escapedURI = FilePathToURI.filepath2URI(f.getAbsolutePath());
+
+        if (DEBUG) {
+            System.out.println("Escaped URI = " + escapedURI);
+        }
+
+        InputSource input = new InputSource(escapedURI);
+        this.parse(input, dh);
+    }
+
+    /**
+     * Parse the content given {@link org.xml.sax.InputSource}
+     * as XML using the specified
+     * {@link org.xml.sax.HandlerBase}.
+     * <i> Use of the DefaultHandler version of this method is recommended as
+     * the HandlerBase class has been deprecated in SAX 2.0</i>
+     *
+     * @param is The InputSource containing the content to be parsed.
+     * @param hb The SAX HandlerBase to use.
+     *
+     * @throws IllegalArgumentException If the <code>InputSource</code> object
+     *   is <code>null</code>.
+     * @throws IOException If any IO errors occur.
+     * @throws SAXException If any SAX errors occur during processing.
+     *
+     * @see org.xml.sax.DocumentHandler
+     */
+    public void parse(InputSource is, HandlerBase hb)
+        throws SAXException, IOException {
+        if (is == null) {
+            throw new IllegalArgumentException("InputSource cannot be null");
+        }
+
+        Parser parser = this.getParser();
+        if (hb != null) {
+            parser.setDocumentHandler(hb);
+            parser.setEntityResolver(hb);
+            parser.setErrorHandler(hb);
+            parser.setDTDHandler(hb);
+        }
+        parser.parse(is);
+    }
+
+    /**
+     * Parse the content given {@link org.xml.sax.InputSource}
+     * as XML using the specified
+     * {@link org.xml.sax.helpers.DefaultHandler}.
+     *
+     * @param is The InputSource containing the content to be parsed.
+     * @param dh The SAX DefaultHandler to use.
+     *
+     * @throws IllegalArgumentException If the <code>InputSource</code> object
+     *   is <code>null</code>.
+     * @throws IOException If any IO errors occur.
+     * @throws SAXException If any SAX errors occur during processing.
+     *
+     * @see org.xml.sax.DocumentHandler
+     */
+    public void parse(InputSource is, DefaultHandler dh)
+        throws SAXException, IOException {
+        if (is == null) {
+            throw new IllegalArgumentException("InputSource cannot be null");
+        }
+
+        XMLReader reader = this.getXMLReader();
+        if (dh != null) {
+            reader.setContentHandler(dh);
+            reader.setEntityResolver(dh);
+            reader.setErrorHandler(dh);
+            reader.setDTDHandler(dh);
+        }
+        reader.parse(is);
+    }
+
+    /**
+     * Returns the SAX parser that is encapsulated by the
+     * implementation of this class.
+     *
+     * @return The SAX parser that is encapsulated by the
+     *         implementation of this class.
+     *
+     * @throws SAXException If any SAX errors occur during processing.
+     */
+    public abstract org.xml.sax.Parser getParser() throws SAXException;
+
+    /**
+     * Returns the {@link org.xml.sax.XMLReader} that is encapsulated by the
+     * implementation of this class.
+     *
+     * @return The XMLReader that is encapsulated by the
+     *         implementation of this class.
+     *
+     * @throws SAXException If any SAX errors occur during processing.
+     */
+
+    public abstract org.xml.sax.XMLReader getXMLReader() throws SAXException;
+
+    /**
+     * Indicates whether or not this parser is configured to
+     * understand namespaces.
+     *
+     * @return true if this parser is configured to
+     *         understand namespaces; false otherwise.
+     */
+
+    public abstract boolean isNamespaceAware();
+
+    /**
+     * Indicates whether or not this parser is configured to
+     * validate XML documents.
+     *
+     * @return true if this parser is configured to
+     *         validate XML documents; false otherwise.
+     */
+
+    public abstract boolean isValidating();
+
+    /**
+     * <p>Sets the particular property in the underlying implementation of
+     * {@link org.xml.sax.XMLReader}.
+     * A list of the core features and properties can be found at
+     * <a href="http://sax.sourceforge.net/?selected=get-set">
+     * http://sax.sourceforge.net/?selected=get-set</a>.</p>
+     *
+     * @param name The name of the property to be set.
+     * @param value The value of the property to be set.
+     *
+     * @throws SAXNotRecognizedException When the underlying XMLReader does
+     *   not recognize the property name.
+     * @throws SAXNotSupportedException When the underlying XMLReader
+     *  recognizes the property name but doesn't support the property.
+     *
+     * @see org.xml.sax.XMLReader#setProperty
+     */
+    public abstract void setProperty(String name, Object value)
+        throws SAXNotRecognizedException, SAXNotSupportedException;
+
+    /**
+     * <p>Returns the particular property requested for in the underlying
+     * implementation of {@link org.xml.sax.XMLReader}.</p>
+     *
+     * @param name The name of the property to be retrieved.
+     * @return Value of the requested property.
+     *
+     * @throws SAXNotRecognizedException When the underlying XMLReader does
+     *    not recognize the property name.
+     * @throws SAXNotSupportedException When the underlying XMLReader
+     *  recognizes the property name but doesn't support the property.
+     *
+     * @see org.xml.sax.XMLReader#getProperty
+     */
+    public abstract Object getProperty(String name)
+        throws SAXNotRecognizedException, SAXNotSupportedException;
+
+    /** <p>Get a reference to the the {@link Schema} being used by
+     * the XML processor.</p>
+     *
+     * <p>If no schema is being used, <code>null</code> is returned.</p>
+     *
+     * @return {@link Schema} being used or <code>null</code>
+     *  if none in use
+     *
+     * @throws UnsupportedOperationException
+     *      For backward compatibility, when implementations for
+     *      earlier versions of JAXP is used, this exception will be
+     *      thrown.
+     *
+     * @since 1.5
+     */
+    public Schema getSchema() {
+        throw new UnsupportedOperationException(
+            "This parser does not support specification \""
+            + this.getClass().getPackage().getSpecificationTitle()
+            + "\" version \""
+            + this.getClass().getPackage().getSpecificationVersion()
+            + "\""
+            );
+    }
+
+    /**
+     * <p>Get the XInclude processing mode for this parser.</p>
+     *
+     * @return
+     *      the return value of
+     *      the {@link SAXParserFactory#isXIncludeAware()}
+     *      when this parser was created from factory.
+     *
+     * @throws UnsupportedOperationException
+     *      For backward compatibility, when implementations for
+     *      earlier versions of JAXP is used, this exception will be
+     *      thrown.
+     *
+     * @since 1.5
+     *
+     * @see SAXParserFactory#setXIncludeAware(boolean)
+     */
+    public boolean isXIncludeAware() {
+        throw new UnsupportedOperationException(
+            "This parser does not support specification \""
+            + this.getClass().getPackage().getSpecificationTitle()
+            + "\" version \""
+            + this.getClass().getPackage().getSpecificationVersion()
+            + "\""
+            );
+    }
+}
diff --git a/javax/xml/parsers/SAXParserFactory.java b/javax/xml/parsers/SAXParserFactory.java
new file mode 100644
index 0000000..eb44033
--- /dev/null
+++ b/javax/xml/parsers/SAXParserFactory.java
@@ -0,0 +1,378 @@
+/*
+ * 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.
+ */
+
+// $Id: SAXParserFactory.java 884950 2009-11-27 18:46:18Z mrglavas $
+
+package javax.xml.parsers;
+
+import javax.xml.validation.Schema;
+import org.apache.harmony.xml.parsers.SAXParserFactoryImpl;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXNotRecognizedException;
+import org.xml.sax.SAXNotSupportedException;
+
+/**
+ * Defines a factory API that enables applications to configure and
+ * obtain a SAX based parser to parse XML documents.
+ *
+ * @author <a href="[email protected]">Jeff Suttor</a>
+ * @version $Revision: 884950 $, $Date: 2009-11-27 10:46:18 -0800 (Fri, 27 Nov 2009) $
+ */
+public abstract class SAXParserFactory {
+
+    /**
+     * <p>Should Parsers be validating?</p>
+     */
+    private boolean validating = false;
+
+    /**
+     * <p>Should Parsers be namespace aware?</p>
+     */
+    private boolean namespaceAware = false;
+
+    /**
+     * <p>Protected constructor to force use of {@link #newInstance()}.</p>
+     */
+    protected SAXParserFactory () {
+
+    }
+
+    /**
+     * Returns Android's implementation of {@code SAXParserFactory}. Unlike
+     * other Java implementations, this method does not consult system
+     * properties, property files, or the services API.
+     *
+     * @return a new SAXParserFactory.
+     *
+     * @exception FactoryConfigurationError never. Included for API
+     *     compatibility with other Java implementations.
+     */
+    public static SAXParserFactory newInstance() {
+        // instantiate the class directly rather than using reflection
+        return new SAXParserFactoryImpl();
+    }
+
+    /**
+     * Returns an instance of the named implementation of {@code SAXParserFactory}.
+     *
+     * @throws FactoryConfigurationError if {@code factoryClassName} is not available or cannot be
+     *     instantiated.
+     * @since 1.6
+     */
+    public static SAXParserFactory newInstance(String factoryClassName,
+            ClassLoader classLoader) {
+        if (factoryClassName == null) {
+            throw new FactoryConfigurationError("factoryClassName == null");
+        }
+        if (classLoader == null) {
+            classLoader = Thread.currentThread().getContextClassLoader();
+        }
+        try {
+            Class<?> type = classLoader != null
+                    ? classLoader.loadClass(factoryClassName)
+                    : Class.forName(factoryClassName);
+            return (SAXParserFactory) type.newInstance();
+        } catch (ClassNotFoundException e) {
+            throw new FactoryConfigurationError(e);
+        } catch (InstantiationException e) {
+            throw new FactoryConfigurationError(e);
+        } catch (IllegalAccessException e) {
+            throw new FactoryConfigurationError(e);
+        }
+    }
+
+    /**
+     * <p>Creates a new instance of a SAXParser using the currently
+     * configured factory parameters.</p>
+     *
+     * @return A new instance of a SAXParser.
+     *
+     * @exception ParserConfigurationException if a parser cannot
+     *   be created which satisfies the requested configuration.
+     * @exception SAXException for SAX errors.
+     */
+
+    public abstract SAXParser newSAXParser()
+        throws ParserConfigurationException, SAXException;
+
+
+    /**
+     * Specifies that the parser produced by this code will
+     * provide support for XML namespaces. By default the value of this is set
+     * to <code>false</code>.
+     *
+     * @param awareness true if the parser produced by this code will
+     *                  provide support for XML namespaces; false otherwise.
+     */
+
+    public void setNamespaceAware(boolean awareness) {
+        this.namespaceAware = awareness;
+    }
+
+    /**
+     * Specifies that the parser produced by this code will
+     * validate documents as they are parsed. By default the value of this is
+     * set to <code>false</code>.
+     *
+     * <p>
+     * Note that "the validation" here means
+     * <a href="http://www.w3.org/TR/REC-xml#proc-types">a validating
+     * parser</a> as defined in the XML recommendation.
+     * In other words, it essentially just controls the DTD validation.
+     * (except the legacy two properties defined in JAXP 1.2.
+     * See <a href="#validationCompatibility">here</a> for more details.)
+     * </p>
+     *
+     * <p>
+     * To use modern schema languages such as W3C XML Schema or
+     * RELAX NG instead of DTD, you can configure your parser to be
+     * a non-validating parser by leaving the {@link #setValidating(boolean)}
+     * method <tt>false</tt>, then use the {@link #setSchema(Schema)}
+     * method to associate a schema to a parser.
+     * </p>
+     *
+     * @param validating true if the parser produced by this code will
+     *                   validate documents as they are parsed; false otherwise.
+     */
+
+    public void setValidating(boolean validating) {
+        this.validating = validating;
+    }
+
+    /**
+     * Indicates whether or not the factory is configured to produce
+     * parsers which are namespace aware.
+     *
+     * @return true if the factory is configured to produce
+     *         parsers which are namespace aware; false otherwise.
+     */
+
+    public boolean isNamespaceAware() {
+        return namespaceAware;
+    }
+
+    /**
+     * Indicates whether or not the factory is configured to produce
+     * parsers which validate the XML content during parse.
+     *
+     * @return true if the factory is configured to produce parsers which validate
+     *         the XML content during parse; false otherwise.
+     */
+
+    public boolean isValidating() {
+        return validating;
+    }
+
+    /**
+     *
+     * <p>Sets the particular feature in the underlying implementation of
+     * org.xml.sax.XMLReader.
+     * A list of the core features and properties can be found at
+     * <a href="http://www.saxproject.org/">http://www.saxproject.org/</a></p>
+     *
+     * <p>All implementations are required to support the {@link javax.xml.XMLConstants#FEATURE_SECURE_PROCESSING} feature.
+     * When the feature is</p>
+     * <ul>
+     *   <li>
+     *     <code>true</code>: the implementation will limit XML processing to conform to implementation limits.
+     *     Examples include entity expansion limits and XML Schema constructs that would consume large amounts of resources.
+     *     If XML processing is limited for security reasons, it will be reported via a call to the registered
+     *     {@link org.xml.sax.ErrorHandler#fatalError(SAXParseException exception)}.
+     *     See {@link SAXParser} <code>parse</code> methods for handler specification.
+     *   </li>
+     *   <li>
+     *     When the feature is <code>false</code>, the implementation will processing XML according to the XML specifications without
+     *     regard to possible implementation limits.
+     *   </li>
+     * </ul>
+     *
+     * @param name The name of the feature to be set.
+     * @param value The value of the feature to be set.
+     *
+     * @exception ParserConfigurationException if a parser cannot
+     *     be created which satisfies the requested configuration.
+     * @exception SAXNotRecognizedException When the underlying XMLReader does
+     *            not recognize the property name.
+     * @exception SAXNotSupportedException When the underlying XMLReader
+     *            recognizes the property name but doesn't support the
+     *            property.
+     * @throws NullPointerException If the <code>name</code> parameter is null.
+     *
+     * @see org.xml.sax.XMLReader#setFeature
+     */
+    public abstract void setFeature(String name, boolean value)
+        throws ParserConfigurationException, SAXNotRecognizedException,
+                SAXNotSupportedException;
+
+    /**
+     *
+     * <p>Returns the particular property requested for in the underlying
+     * implementation of org.xml.sax.XMLReader.</p>
+     *
+     * @param name The name of the property to be retrieved.
+     *
+     * @return Value of the requested property.
+     *
+     * @exception ParserConfigurationException if a parser cannot be created which satisfies the requested configuration.
+     * @exception SAXNotRecognizedException When the underlying XMLReader does not recognize the property name.
+     * @exception SAXNotSupportedException When the underlying XMLReader recognizes the property name but doesn't support the property.
+     *
+     * @see org.xml.sax.XMLReader#getProperty
+     */
+    public abstract boolean getFeature(String name)
+        throws ParserConfigurationException, SAXNotRecognizedException,
+                SAXNotSupportedException;
+
+    /**
+     * Gets the {@link Schema} object specified through
+     * the {@link #setSchema(Schema schema)} method.
+     *
+     *
+     * @throws UnsupportedOperationException
+     *      For backward compatibility, when implementations for
+     *      earlier versions of JAXP is used, this exception will be
+     *      thrown.
+     *
+     * @return
+     *      the {@link Schema} object that was last set through
+     *      the {@link #setSchema(Schema)} method, or null
+     *      if the method was not invoked since a {@link SAXParserFactory}
+     *      is created.
+     *
+     * @since 1.5
+     */
+    public Schema getSchema() {
+        throw new UnsupportedOperationException(
+            "This parser does not support specification \""
+            + this.getClass().getPackage().getSpecificationTitle()
+            + "\" version \""
+            + this.getClass().getPackage().getSpecificationVersion()
+            + "\""
+            );
+    }
+
+    /**
+     * <p>Set the {@link Schema} to be used by parsers created
+     * from this factory.</p>
+     *
+     * <p>When a {@link Schema} is non-null, a parser will use a validator
+     * created from it to validate documents before it passes information
+     * down to the application.</p>
+     *
+     * <p>When warnings/errors/fatal errors are found by the validator, the parser must
+     * handle them as if those errors were found by the parser itself.
+     * In other words, if the user-specified {@link org.xml.sax.ErrorHandler}
+     * is set, it must receive those errors, and if not, they must be
+     * treated according to the implementation specific
+     * default error handling rules.
+     *
+     * <p>A validator may modify the SAX event stream (for example by
+     * adding default values that were missing in documents), and a parser
+     * is responsible to make sure that the application will receive
+     * those modified event stream.</p>
+     *
+     * <p>Initially, <code>null</code> is set as the {@link Schema}.</p>
+     *
+     * <p>This processing will take effect even if
+     * the {@link #isValidating()} method returns <code>false</code>.
+     *
+     * <p>It is an error to use
+     * the <code>http://java.sun.com/xml/jaxp/properties/schemaSource</code>
+     * property and/or the <code>http://java.sun.com/xml/jaxp/properties/schemaLanguage</code>
+     * property in conjunction with a non-null {@link Schema} object.
+     * Such configuration will cause a {@link SAXException}
+     * exception when those properties are set on a {@link SAXParser}.</p>
+     *
+     * <h4>Note for implementors</h4>
+     * <p>
+     * A parser must be able to work with any {@link Schema}
+     * implementation. However, parsers and schemas are allowed
+     * to use implementation-specific custom mechanisms
+     * as long as they yield the result described in the specification.
+     * </p>
+     *
+     * @param schema <code>Schema</code> to use, <code>null</code> to remove a schema.
+     *
+     * @throws UnsupportedOperationException
+     *      For backward compatibility, when implementations for
+     *      earlier versions of JAXP is used, this exception will be
+     *      thrown.
+     *
+     * @since 1.5
+     */
+    public void setSchema(Schema schema) {
+        throw new UnsupportedOperationException(
+            "This parser does not support specification \""
+            + this.getClass().getPackage().getSpecificationTitle()
+            + "\" version \""
+            + this.getClass().getPackage().getSpecificationVersion()
+            + "\""
+            );
+    }
+
+    /**
+     * <p>Set state of XInclude processing.</p>
+     *
+     * <p>If XInclude markup is found in the document instance, should it be
+     * processed as specified in <a href="http://www.w3.org/TR/xinclude/">
+     * XML Inclusions (XInclude) Version 1.0</a>.</p>
+     *
+     * <p>XInclude processing defaults to <code>false</code>.</p>
+     *
+     * @param state Set XInclude processing to <code>true</code> or
+     *   <code>false</code>
+     *
+     * @throws UnsupportedOperationException
+     *      For backward compatibility, when implementations for
+     *      earlier versions of JAXP is used, this exception will be
+     *      thrown.
+     *
+     * @since 1.5
+     */
+    public void setXIncludeAware(final boolean state) {
+        throw new UnsupportedOperationException(
+            "This parser does not support specification \""
+            + this.getClass().getPackage().getSpecificationTitle()
+            + "\" version \""
+            + this.getClass().getPackage().getSpecificationVersion()
+            + "\""
+            );
+    }
+
+    /**
+     * <p>Get state of XInclude processing.</p>
+     *
+     * @return current state of XInclude processing
+     *
+     * @throws UnsupportedOperationException
+     *      For backward compatibility, when implementations for
+     *      earlier versions of JAXP is used, this exception will be
+     *      thrown.
+     *
+     * @since 1.5
+     */
+    public boolean isXIncludeAware() {
+        throw new UnsupportedOperationException(
+            "This parser does not support specification \""
+            + this.getClass().getPackage().getSpecificationTitle()
+            + "\" version \""
+            + this.getClass().getPackage().getSpecificationVersion()
+            + "\""
+            );
+    }
+}
+
diff --git a/javax/xml/transform/ErrorListener.java b/javax/xml/transform/ErrorListener.java
new file mode 100644
index 0000000..321c5fe
--- /dev/null
+++ b/javax/xml/transform/ErrorListener.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.
+ */
+
+// $Id: ErrorListener.java 569994 2007-08-27 04:28:57Z mrglavas $
+
+package javax.xml.transform;
+
+/**
+ * <p>To provide customized error handling, implement this interface and
+ * use the <code>setErrorListener</code> method to register an instance of the
+ * implementation with the {@link javax.xml.transform.Transformer}.  The
+ * <code>Transformer</code> then reports all errors and warnings through this
+ * interface.</p>
+ *
+ * <p>If an application does <em>not</em> register its own custom
+ * <code>ErrorListener</code>, the default <code>ErrorListener</code>
+ * is used which reports all warnings and errors to <code>System.err</code>
+ * and does not throw any <code>Exception</code>s.
+ * Applications are <em>strongly</em> encouraged to register and use
+ * <code>ErrorListener</code>s that insure proper behavior for warnings and
+ * errors.</p>
+ *
+ * <p>For transformation errors, a <code>Transformer</code> must use this
+ * interface instead of throwing an <code>Exception</code>: it is up to the
+ * application to decide whether to throw an <code>Exception</code> for
+ * different types of errors and warnings.  Note however that the
+ * <code>Transformer</code> is not required to continue with the transformation
+ * after a call to {@link #fatalError(TransformerException exception)}.</p>
+ *
+ * <p><code>Transformer</code>s may use this mechanism to report XML parsing
+ * errors as well as transformation errors.</p>
+ */
+public interface ErrorListener {
+
+    /**
+     * Receive notification of a warning.
+     *
+     * <p>{@link javax.xml.transform.Transformer} can use this method to report
+     * conditions that are not errors or fatal errors.  The default behavior
+     * is to take no action.</p>
+     *
+     * <p>After invoking this method, the Transformer must continue with
+     * the transformation. It should still be possible for the
+     * application to process the document through to the end.</p>
+     *
+     * @param exception The warning information encapsulated in a
+     *                  transformer exception.
+     *
+     * @throws javax.xml.transform.TransformerException if the application
+     * chooses to discontinue the transformation.
+     *
+     * @see javax.xml.transform.TransformerException
+     */
+    public abstract void warning(TransformerException exception)
+        throws TransformerException;
+
+    /**
+     * Receive notification of a recoverable error.
+     *
+     * <p>The transformer must continue to try and provide normal transformation
+     * after invoking this method.  It should still be possible for the
+     * application to process the document through to the end if no other errors
+     * are encountered.</p>
+     *
+     * @param exception The error information encapsulated in a
+     *                  transformer exception.
+     *
+     * @throws javax.xml.transform.TransformerException if the application
+     * chooses to discontinue the transformation.
+     *
+     * @see javax.xml.transform.TransformerException
+     */
+    public abstract void error(TransformerException exception)
+        throws TransformerException;
+
+    /**
+     * <p>Receive notification of a non-recoverable error.</p>
+     *
+     * <p>The <code>Transformer</code> must continue to try and provide normal
+     * transformation after invoking this method.  It should still be possible for the
+     * application to process the document through to the end if no other errors
+     * are encountered, but there is no guarantee that the output will be
+     * useable.</p>
+     *
+     * @param exception The error information encapsulated in a
+     *    <code>TransformerException</code>.
+     *
+     * @throws javax.xml.transform.TransformerException if the application
+     * chooses to discontinue the transformation.
+     *
+     * @see javax.xml.transform.TransformerException
+     */
+    public abstract void fatalError(TransformerException exception)
+        throws TransformerException;
+}
diff --git a/javax/xml/transform/OutputKeys.java b/javax/xml/transform/OutputKeys.java
new file mode 100644
index 0000000..8383cdb
--- /dev/null
+++ b/javax/xml/transform/OutputKeys.java
@@ -0,0 +1,193 @@
+/*
+ * 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.
+ */
+
+// $Id: OutputKeys.java 569994 2007-08-27 04:28:57Z mrglavas $
+
+package javax.xml.transform;
+
+/**
+ * Provides string constants that can be used to set
+ * output properties for a Transformer, or to retrieve
+ * output properties from a Transformer or Templates object.
+ * <p>All the fields in this class are read-only.</p>
+ *
+ * @see <a href="http://www.w3.org/TR/xslt#output">
+ *  section 16 of the XSL Transformations (XSLT) W3C Recommendation</a>
+ */
+public class OutputKeys {
+
+    /**
+     * Default constructor is private on purpose.  This class is
+     * only for static variable access, and should never be constructed.
+     */
+    private OutputKeys() { }
+
+    /**
+     * method = "xml" | "html" | "text" | <var>expanded name</var>.
+     *
+     * <p>The value of the method property identifies the overall method that
+     * should be used for outputting the result tree.  Other non-namespaced
+     * values may be used, such as "xhtml", but, if accepted, the handling
+     * of such values is implementation defined.  If any of the method values
+     * are not accepted and are not namespace qualified,
+     * then {@link javax.xml.transform.Transformer#setOutputProperty}
+     * or {@link javax.xml.transform.Transformer#setOutputProperties} will
+     * throw a {@link java.lang.IllegalArgumentException}.</p>
+     *
+     * @see <a href="http://www.w3.org/TR/xslt#output">
+     *  section 16 of the XSL Transformations (XSLT) W3C Recommendation</a>
+     */
+    public static final String METHOD = "method";
+
+    /**
+     * version = <var>nmtoken</var>.
+     *
+     * <p><code>version</code> specifies the version of the output
+     * method.</p>
+     * <p>When the output method is "xml", the version value specifies the
+     * version of XML to be used for outputting the result tree. The default
+     * value for the xml output method is 1.0. When the output method is
+     * "html", the version value indicates the version of the HTML.
+     * The default value for the xml output method is 4.0, which specifies
+     * that the result should be output as HTML conforming to the HTML 4.0
+     * Recommendation [HTML].  If the output method is "text", the version
+     * property is ignored.</p>
+     * @see <a href="http://www.w3.org/TR/xslt#output">
+     *  section 16 of the XSL Transformations (XSLT) W3C Recommendation</a>
+     */
+    public static final String VERSION = "version";
+
+    /**
+     * encoding = <var>string</var>.
+     *
+     * <p><code>encoding</code> specifies the preferred character
+     * encoding that the Transformer should use to encode sequences of
+     * characters as sequences of bytes. The value of the encoding property should be
+     * treated case-insensitively. The value must only contain characters in
+     * the range #x21 to #x7E (i.e., printable ASCII characters). The value
+     * should either be a <code>charset</code> registered with the Internet
+     * Assigned Numbers Authority <a href="#IANA">[IANA]</a>,
+     * <a href="#RFC2278">[RFC2278]</a> or start with <code>X-</code>.</p>
+     * @see <a href="http://www.w3.org/TR/xslt#output">
+     * section 16 of the XSL Transformations (XSLT) W3C Recommendation</a>
+     */
+    public static final String ENCODING = "encoding";
+
+    /**
+     * omit-xml-declaration = "yes" | "no".
+     *
+     * <p><code>omit-xml-declaration</code> specifies whether the XSLT
+     * processor should output an XML declaration; the value must be
+     * <code>yes</code> or <code>no</code>.</p>
+     * @see <a href="http://www.w3.org/TR/xslt#output">
+     *  section 16 of the XSL Transformations (XSLT) W3C Recommendation</a>
+     */
+    public static final String OMIT_XML_DECLARATION = "omit-xml-declaration";
+
+    /**
+     * standalone = "yes" | "no".
+     *
+     * <p><code>standalone</code> specifies whether the Transformer
+     * should output a standalone document declaration; the value must be
+     * <code>yes</code> or <code>no</code>.</p>
+     * @see <a href="http://www.w3.org/TR/xslt#output">
+     *  section 16 of the XSL Transformations (XSLT) W3C Recommendation</a>
+     */
+    public static final String STANDALONE = "standalone";
+
+    /**
+     * doctype-public = <var>string</var>.
+     * <p>See the documentation for the {@link #DOCTYPE_SYSTEM} property
+     * for a description of what the value of the key should be.</p>
+     *
+     * @see <a href="http://www.w3.org/TR/xslt#output">
+     *  section 16 of the XSL Transformations (XSLT) W3C Recommendation</a>
+     */
+    public static final String DOCTYPE_PUBLIC = "doctype-public";
+
+    /**
+     * doctype-system = <var>string</var>.
+     * <p><code>doctype-system</code> specifies the system identifier
+     * to be used in the document type declaration.</p>
+     * <p>If the doctype-system property is specified, the xml output method
+     * should output a document type declaration immediately before the first
+     * element. The name following &lt;!DOCTYPE should be the name of the first
+     * element. If doctype-public property is also specified, then the xml
+     * output method should output PUBLIC followed by the public identifier
+     * and then the system identifier; otherwise, it should output SYSTEM
+     * followed by the system identifier. The internal subset should be empty.
+     * The value of the doctype-public property should be ignored unless the doctype-system
+     * property is specified.</p>
+     * <p>If the doctype-public or doctype-system properties are specified,
+     * then the html output method should output a document type declaration
+     * immediately before the first element. The name following &lt;!DOCTYPE
+     * should be HTML or html. If the doctype-public property is specified,
+     * then the output method should output PUBLIC followed by the specified
+     * public identifier; if the doctype-system property is also specified,
+     * it should also output the specified system identifier following the
+     * public identifier. If the doctype-system property is specified but
+     * the doctype-public property is not specified, then the output method
+     * should output SYSTEM followed by the specified system identifier.</p>
+     *
+     * <p><code>doctype-system</code> specifies the system identifier
+     * to be used in the document type declaration.</p>
+     * @see <a href="http://www.w3.org/TR/xslt#output">
+     *  section 16 of the XSL Transformations (XSLT) W3C Recommendation</a>
+     */
+    public static final String DOCTYPE_SYSTEM = "doctype-system";
+
+    /**
+     * cdata-section-elements = <var>expanded names</var>.
+     *
+     * <p><code>cdata-section-elements</code> specifies a whitespace delimited
+     * list of the names of elements whose text node children should be output
+     * using CDATA sections. Note that these names must use the format
+     * described in the section Qualfied Name Representation in
+     * {@link javax.xml.transform}.</p>
+     *
+     * @see <a href="http://www.w3.org/TR/xslt#output">
+     *  section 16 of the XSL Transformations (XSLT) W3C Recommendation.</a>
+     */
+    public static final String CDATA_SECTION_ELEMENTS =
+        "cdata-section-elements";
+
+    /**
+     * indent = "yes" | "no".
+     *
+     * <p><code>indent</code> specifies whether the Transformer may
+     * add additional whitespace when outputting the result tree; the value
+     * must be <code>yes</code> or <code>no</code>.  </p>
+     * @see <a href="http://www.w3.org/TR/xslt#output">
+     *  section 16 of the XSL Transformations (XSLT) W3C Recommendation</a>
+     */
+    public static final String INDENT = "indent";
+
+    /**
+     * media-type = <var>string</var>.
+     *
+     * <p><code>media-type</code> specifies the media type (MIME
+     * content type) of the data that results from outputting the result
+     * tree. The <code>charset</code> parameter should not be specified
+     * explicitly; instead, when the top-level media type is
+     * <code>text</code>, a <code>charset</code> parameter should be added
+     * according to the character encoding actually used by the output
+     * method.  </p>
+     * @see <a href="http://www.w3.org/TR/xslt#output">
+     *  section 16 of the XSL Transformations (XSLT) W3C Recommendation</a>
+     */
+    public static final String MEDIA_TYPE = "media-type";
+}
diff --git a/javax/xml/transform/Result.java b/javax/xml/transform/Result.java
new file mode 100644
index 0000000..6e4c285
--- /dev/null
+++ b/javax/xml/transform/Result.java
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+//  $Id: Result.java 446598 2006-09-15 12:55:40Z jeremias $
+
+package javax.xml.transform;
+
+/**
+ * <p>An object that implements this interface contains the information
+ * needed to build a transformation result tree.</p>
+ *
+ * @author <a href="[email protected]">Jeff Suttor</a>
+ */
+public interface Result {
+
+    /**
+     * The name of the processing instruction that is sent if the
+     * result tree disables output escaping.
+     *
+     * <p>Normally, result tree serialization escapes & and < (and
+     * possibly other characters) when outputting text nodes.
+     * This ensures that the output is well-formed XML. However,
+     * it is sometimes convenient to be able to produce output that is
+     * almost, but not quite well-formed XML; for example,
+     * the output may include ill-formed sections that will
+     * be transformed into well-formed XML by a subsequent non-XML aware
+     * process. If a processing instruction is sent with this name,
+     * serialization should be output without any escaping. </p>
+     *
+     * <p>Result DOM trees may also have PI_DISABLE_OUTPUT_ESCAPING and
+     * PI_ENABLE_OUTPUT_ESCAPING inserted into the tree.</p>
+     *
+     * @see <a href="http://www.w3.org/TR/xslt#disable-output-escaping">disable-output-escaping in XSLT Specification</a>
+     */
+    public static final String PI_DISABLE_OUTPUT_ESCAPING =
+        "javax.xml.transform.disable-output-escaping";
+
+    /**
+     * The name of the processing instruction that is sent
+     * if the result tree enables output escaping at some point after having
+     * received a PI_DISABLE_OUTPUT_ESCAPING processing instruction.
+     *
+     * @see <a href="http://www.w3.org/TR/xslt#disable-output-escaping">disable-output-escaping in XSLT Specification</a>
+     */
+    public static final String PI_ENABLE_OUTPUT_ESCAPING =
+        "javax.xml.transform.enable-output-escaping";
+
+    /**
+     * Set the system identifier for this Result.
+     *
+     * <p>If the Result is not to be written to a file, the system identifier is optional.
+     * The application may still want to provide one, however, for use in error messages
+     * and warnings, or to resolve relative output identifiers.</p>
+     *
+     * @param systemId The system identifier as a URI string.
+     */
+    public void setSystemId(String systemId);
+
+    /**
+     * Get the system identifier that was set with setSystemId.
+     *
+     * @return The system identifier that was set with setSystemId,
+     * or null if setSystemId was not called.
+     */
+    public String getSystemId();
+}
diff --git a/javax/xml/transform/Source.java b/javax/xml/transform/Source.java
new file mode 100644
index 0000000..44cbf24
--- /dev/null
+++ b/javax/xml/transform/Source.java
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+// $Id: Source.java 446598 2006-09-15 12:55:40Z jeremias $
+
+package javax.xml.transform;
+
+/**
+ * An object that implements this interface contains the information
+ * needed to act as source input (XML source or transformation instructions).
+ */
+public interface Source {
+
+    /**
+     * Set the system identifier for this Source.
+     *
+     * <p>The system identifier is optional if the source does not
+     * get its data from a URL, but it may still be useful to provide one.
+     * The application can use a system identifier, for example, to resolve
+     * relative URIs and to include in error messages and warnings.</p>
+     *
+     * @param systemId The system identifier as a URL string.
+     */
+    public void setSystemId(String systemId);
+
+    /**
+     * Get the system identifier that was set with setSystemId.
+     *
+     * @return The system identifier that was set with setSystemId, or null
+     * if setSystemId was not called.
+     */
+    public String getSystemId();
+}
diff --git a/javax/xml/transform/SourceLocator.java b/javax/xml/transform/SourceLocator.java
new file mode 100644
index 0000000..632eee8
--- /dev/null
+++ b/javax/xml/transform/SourceLocator.java
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ */
+
+// $Id: SourceLocator.java 446598 2006-09-15 12:55:40Z jeremias $
+
+package javax.xml.transform;
+
+/**
+ * This interface is primarily for the purposes of reporting where
+ * an error occurred in the XML source or transformation instructions.
+ */
+public interface SourceLocator {
+
+    /**
+     * Return the public identifier for the current document event.
+     *
+     * <p>The return value is the public identifier of the document
+     * entity or of the external parsed entity in which the markup that
+     * triggered the event appears.</p>
+     *
+     * @return A string containing the public identifier, or
+     *         null if none is available.
+     * @see #getSystemId
+     */
+    public String getPublicId();
+
+    /**
+     * Return the system identifier for the current document event.
+     *
+     * <p>The return value is the system identifier of the document
+     * entity or of the external parsed entity in which the markup that
+     * triggered the event appears.</p>
+     *
+     * <p>If the system identifier is a URL, the parser must resolve it
+     * fully before passing it to the application.</p>
+     *
+     * @return A string containing the system identifier, or null
+     *         if none is available.
+     * @see #getPublicId
+     */
+    public String getSystemId();
+
+    /**
+     * Return the line number where the current document event ends.
+     *
+     * <p><strong>Warning:</strong> The return value from the method
+     * is intended only as an approximation for the sake of error
+     * reporting; it is not intended to provide sufficient information
+     * to edit the character content of the original XML document.</p>
+     *
+     * <p>The return value is an approximation of the line number
+     * in the document entity or external parsed entity where the
+     * markup that triggered the event appears.</p>
+     *
+     * @return The line number, or -1 if none is available.
+     * @see #getColumnNumber
+     */
+    public int getLineNumber();
+
+    /**
+     * Return the character position where the current document event ends.
+     *
+     * <p><strong>Warning:</strong> The return value from the method
+     * is intended only as an approximation for the sake of error
+     * reporting; it is not intended to provide sufficient information
+     * to edit the character content of the original XML document.</p>
+     *
+     * <p>The return value is an approximation of the column number
+     * in the document entity or external parsed entity where the
+     * markup that triggered the event appears.</p>
+     *
+     * @return The column number, or -1 if none is available.
+     * @see #getLineNumber
+     */
+    public int getColumnNumber();
+}
diff --git a/javax/xml/transform/Templates.java b/javax/xml/transform/Templates.java
new file mode 100644
index 0000000..1d6f46a
--- /dev/null
+++ b/javax/xml/transform/Templates.java
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+// $Id: Templates.java 570103 2007-08-27 13:24:55Z mrglavas $
+
+package javax.xml.transform;
+
+import java.util.Properties;
+
+/**
+ * An object that implements this interface is the runtime representation of processed
+ * transformation instructions.
+ *
+ * <p>Templates must be thread-safe for a given instance
+ * over multiple threads running concurrently, and may
+ * be used multiple times in a given session.</p>
+ */
+public interface Templates {
+
+    /**
+     * Create a new transformation context for this Templates object.
+     *
+     * @return A valid non-null instance of a Transformer.
+     *
+     * @throws TransformerConfigurationException if a Transformer can not be created.
+     */
+    Transformer newTransformer() throws TransformerConfigurationException;
+
+    /**
+     * Get the properties corresponding to the effective xsl:output element.
+     * The object returned will
+     * be a clone of the internal values. Accordingly, it can be mutated
+     * without mutating the Templates object, and then handed in to
+     * {@link javax.xml.transform.Transformer#setOutputProperties}.
+     *
+     * <p>The properties returned should contain properties set by the stylesheet,
+     * and these properties are "defaulted" by default properties specified by
+     * <a href="http://www.w3.org/TR/xslt#output">section 16 of the
+     * XSL Transformations (XSLT) W3C Recommendation</a>.  The properties that
+     * were specifically set by the stylesheet should be in the base
+     * Properties list, while the XSLT default properties that were not
+     * specifically set should be in the "default" Properties list.  Thus,
+     * getOutputProperties().getProperty(String key) will obtain any
+     * property in that was set by the stylesheet, <em>or</em> the default
+     * properties, while
+     * getOutputProperties().get(String key) will only retrieve properties
+     * that were explicitly set in the stylesheet.</p>
+     *
+     * <p>For XSLT,
+     * <a href="http://www.w3.org/TR/xslt#attribute-value-templates">Attribute
+     * Value Templates</a> attribute values will
+     * be returned unexpanded (since there is no context at this point).  The
+     * namespace prefixes inside Attribute Value Templates will be unexpanded,
+     * so that they remain valid XPath values.</p>
+     *
+     * @return A Properties object, never null.
+     */
+    Properties getOutputProperties();
+}
diff --git a/javax/xml/transform/Transformer.java b/javax/xml/transform/Transformer.java
new file mode 100644
index 0000000..c94a9ef
--- /dev/null
+++ b/javax/xml/transform/Transformer.java
@@ -0,0 +1,321 @@
+/*
+ * 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.
+ */
+
+// $Id: Transformer.java 570103 2007-08-27 13:24:55Z mrglavas $
+
+package javax.xml.transform;
+
+import java.util.Properties;
+
+/**
+ * An instance of this abstract class can transform a
+ * source tree into a result tree.
+ *
+ * <p>An instance of this class can be obtained with the
+ * {@link TransformerFactory#newTransformer TransformerFactory.newTransformer}
+ * method. This instance may then be used to process XML from a
+ * variety of sources and write the transformation output to a
+ * variety of sinks.</p>
+ *
+ * <p>An object of this class may not be used in multiple threads
+ * running concurrently.  Different Transformers may be used
+ * concurrently by different threads.</p>
+ *
+ * <p>A <code>Transformer</code> may be used multiple times.  Parameters and
+ * output properties are preserved across transformations.</p>
+ *
+ * @author <a href="[email protected]">Jeff Suttor</a>
+ * @version $Revision: 570103 $, $Date: 2007-08-27 06:24:55 -0700 (Mon, 27 Aug 2007) $
+ */
+public abstract class Transformer {
+
+    /**
+     * Default constructor is protected on purpose.
+     */
+    protected Transformer() { }
+
+    /**
+     * <p>Reset this <code>Transformer</code> to its original configuration.</p>
+     *
+     * <p><code>Transformer</code> is reset to the same state as when it was created with
+     * {@link TransformerFactory#newTransformer()},
+     * {@link TransformerFactory#newTransformer(Source source)} or
+     * {@link Templates#newTransformer()}.
+     * <code>reset()</code> is designed to allow the reuse of existing <code>Transformer</code>s
+     * thus saving resources associated with the creation of new <code>Transformer</code>s.</p>
+     *
+     * <p>The reset <code>Transformer</code> is not guaranteed to have the same {@link URIResolver}
+     * or {@link ErrorListener} <code>Object</code>s, e.g. {@link Object#equals(Object obj)}.
+     * It is guaranteed to have a functionally equal <code>URIResolver</code>
+     * and <code>ErrorListener</code>.</p>
+     *
+     * @since 1.5
+     */
+    public void reset() {
+
+        // implementors should override this method
+        throw new UnsupportedOperationException(
+            "This Transformer, \"" + this.getClass().getName() + "\", does not support the reset functionality."
+            + "  Specification \"" + this.getClass().getPackage().getSpecificationTitle() + "\""
+            + " version \"" + this.getClass().getPackage().getSpecificationVersion() + "\""
+            );
+    }
+
+    /**
+     * <p>Transform the XML <code>Source</code> to a <code>Result</code>.
+     * Specific transformation behavior is determined by the settings of the
+     * <code>TransformerFactory</code> in effect when the
+     * <code>Transformer</code> was instantiated and any modifications made to
+     * the <code>Transformer</code> instance.</p>
+     *
+     * <p>An empty <code>Source</code> is represented as an empty document
+     * as constructed by {@link javax.xml.parsers.DocumentBuilder#newDocument()}.
+     * The result of transforming an empty <code>Source</code> depends on
+     * the transformation behavior; it is not always an empty
+     * <code>Result</code>.</p>
+     *
+     * @param xmlSource The XML input to transform.
+     * @param outputTarget The <code>Result</code> of transforming the
+     *   <code>xmlSource</code>.
+     *
+     * @throws TransformerException If an unrecoverable error occurs
+     *   during the course of the transformation.
+     */
+    public abstract void transform(Source xmlSource, Result outputTarget)
+        throws TransformerException;
+
+    /**
+     * Add a parameter for the transformation.
+     *
+     * <p>Pass a qualified name as a two-part string, the namespace URI
+     * enclosed in curly braces ({}), followed by the local name. If the
+     * name has a null URL, the String only contain the local name. An
+     * application can safely check for a non-null URI by testing to see if the
+     * first character of the name is a '{' character.</p>
+     * <p>For example, if a URI and local name were obtained from an element
+     * defined with &lt;xyz:foo
+     * xmlns:xyz="http://xyz.foo.com/yada/baz.html"/&gt;,
+     * then the qualified name would be "{http://xyz.foo.com/yada/baz.html}foo".
+     * Note that no prefix is used.</p>
+     *
+     * @param name The name of the parameter, which may begin with a
+     * namespace URI in curly braces ({}).
+     * @param value The value object.  This can be any valid Java object. It is
+     * up to the processor to provide the proper object coercion or to simply
+     * pass the object on for use in an extension.
+     *
+     * @throws NullPointerException If value is null.
+     */
+     public abstract void setParameter(String name, Object value);
+
+    /**
+     * Get a parameter that was explicitly set with setParameter.
+     *
+     * <p>This method does not return a default parameter value, which
+     * cannot be determined until the node context is evaluated during
+     * the transformation process.
+     *
+     * @param name of <code>Object</code> to get
+     * @return A parameter that has been set with setParameter.
+     */
+    public abstract Object getParameter(String name);
+
+    /**
+     * <p>Set a list of parameters.</p>
+     *
+     * <p>Note that the list of parameters is specified as a
+     * <code>Properties</code> <code>Object</code> which limits the parameter
+     * values to <code>String</code>s.  Multiple calls to
+     * {@link #setParameter(String name, Object value)} should be used when the
+     * desired values are non-<code>String</code> <code>Object</code>s.
+     * The parameter names should conform as specified in
+     * {@link #setParameter(String name, Object value)}.
+     * An <code>IllegalArgumentException</code> is thrown if any names do not
+     * conform.</p>
+     *
+     * <p>New parameters in the list are added to any existing parameters.
+     * If the name of a new parameter is equal to the name of an existing
+     * parameter as determined by {@link java.lang.Object#equals(Object obj)},
+     *  the existing parameter is set to the new value.</p>
+     *
+     * @param params Parameters to set.
+     *
+     * @throws IllegalArgumentException If any parameter names do not conform
+     *   to the naming rules.
+     */
+
+    /**
+     * Clear all parameters set with setParameter.
+     */
+    public abstract void clearParameters();
+
+    /**
+     * Set an object that will be used to resolve URIs used in
+     * document().
+     *
+     * <p>If the resolver argument is null, the URIResolver value will
+     * be cleared and the transformer will no longer have a resolver.</p>
+     *
+     * @param resolver An object that implements the URIResolver interface,
+     * or null.
+     */
+    public abstract void setURIResolver(URIResolver resolver);
+
+    /**
+     * Get an object that will be used to resolve URIs used in
+     * document().
+     *
+     * @return An object that implements the URIResolver interface,
+     * or null.
+     */
+    public abstract URIResolver getURIResolver();
+
+    /**
+     * Set the output properties for the transformation.  These
+     * properties will override properties set in the Templates
+     * with xsl:output.
+     *
+     * <p>If argument to this function is null, any properties
+     * previously set are removed, and the value will revert to the value
+     * defined in the templates object.</p>
+     *
+     * <p>Pass a qualified property key name as a two-part string, the namespace
+     * URI enclosed in curly braces ({}), followed by the local name. If the
+     * name has a null URL, the String only contain the local name. An
+     * application can safely check for a non-null URI by testing to see if the
+     * first character of the name is a '{' character.</p>
+     * <p>For example, if a URI and local name were obtained from an element
+     * defined with &lt;xyz:foo
+     * xmlns:xyz="http://xyz.foo.com/yada/baz.html"/&gt;,
+     * then the qualified name would be "{http://xyz.foo.com/yada/baz.html}foo".
+     * Note that no prefix is used.</p>
+     * An <code>IllegalArgumentException</code> is thrown  if any of the
+     * argument keys are not recognized and are not namespace qualified.
+     *
+     * @param oformat A set of output properties that will be
+     * used to override any of the same properties in affect
+     * for the transformation.
+     *
+     * @see javax.xml.transform.OutputKeys
+     * @see java.util.Properties
+     *
+     */
+    public abstract void setOutputProperties(Properties oformat);
+
+    /**
+     * <p>Get a copy of the output properties for the transformation.</p>
+     *
+     * <p>The properties returned should contain properties set by the user,
+     * and properties set by the stylesheet, and these properties
+     * are "defaulted" by default properties specified by
+     * <a href="http://www.w3.org/TR/xslt#output">section 16 of the
+     * XSL Transformations (XSLT) W3C Recommendation</a>.  The properties that
+     * were specifically set by the user or the stylesheet should be in the base
+     * Properties list, while the XSLT default properties that were not
+     * specifically set should be the default Properties list.  Thus,
+     * getOutputProperties().getProperty(String key) will obtain any
+     * property in that was set by {@link #setOutputProperty},
+     * {@link #setOutputProperties}, in the stylesheet, <em>or</em> the default
+     * properties, while
+     * getOutputProperties().get(String key) will only retrieve properties
+     * that were explicitly set by {@link #setOutputProperty},
+     * {@link #setOutputProperties}, or in the stylesheet.</p>
+     *
+     * <p>Note that mutation of the Properties object returned will not
+     * effect the properties that the transformer contains.</p>
+     *
+     * <p>If any of the argument keys are not recognized and are not
+     * namespace qualified, the property will be ignored and not returned.
+     * In other words the behavior is not orthogonal with
+     * {@link #setOutputProperties setOutputProperties}.</p>
+     *
+     * @return A copy of the set of output properties in effect for
+     *   the next transformation.
+     *
+     * @see javax.xml.transform.OutputKeys
+     * @see java.util.Properties
+     * @see <a href="http://www.w3.org/TR/xslt#output">
+     *   XSL Transformations (XSLT) Version 1.0</a>
+     */
+    public abstract Properties getOutputProperties();
+
+    /**
+     * Set an output property that will be in effect for the
+     * transformation.
+     *
+     * <p>Pass a qualified property name as a two-part string, the namespace URI
+     * enclosed in curly braces ({}), followed by the local name. If the
+     * name has a null URL, the String only contain the local name. An
+     * application can safely check for a non-null URI by testing to see if the
+     * first character of the name is a '{' character.</p>
+     * <p>For example, if a URI and local name were obtained from an element
+     * defined with &lt;xyz:foo
+     * xmlns:xyz="http://xyz.foo.com/yada/baz.html"/&gt;,
+     * then the qualified name would be "{http://xyz.foo.com/yada/baz.html}foo".
+     * Note that no prefix is used.</p>
+     *
+     * <p>The Properties object that was passed to {@link #setOutputProperties}
+     * won't be effected by calling this method.</p>
+     *
+     * @param name A non-null String that specifies an output
+     * property name, which may be namespace qualified.
+     * @param value The non-null string value of the output property.
+     *
+     * @throws IllegalArgumentException If the property is not supported, and is
+     * not qualified with a namespace.
+     *
+     * @see javax.xml.transform.OutputKeys
+     */
+    public abstract void setOutputProperty(String name, String value)
+        throws IllegalArgumentException;
+
+    /**
+     * Get an output property that is in effect for the
+     * transformer.  The property specified may be a property
+     * that was set with setOutputProperty, or it may be a
+     * property specified in the stylesheet.
+     *
+     * @param name A non-null String that specifies an output
+     * property name, which may be namespace qualified.
+     *
+     * @return The string value of the output property, or null
+     * if no property was found.
+     *
+     * @throws IllegalArgumentException If the property is not supported.
+     *
+     * @see javax.xml.transform.OutputKeys
+     */
+    public abstract String getOutputProperty(String name)
+        throws IllegalArgumentException;
+
+    /**
+     * Set the error event listener in effect for the transformation.
+     *
+     * @param listener The new error listener.
+     * @throws IllegalArgumentException if listener is null.
+     */
+    public abstract void setErrorListener(ErrorListener listener)
+        throws IllegalArgumentException;
+
+    /**
+     * Get the error event handler in effect for the transformation.
+     * Implementations must provide a default error listener.
+     *
+     * @return The current error handler, which should never be null.
+     */
+    public abstract ErrorListener getErrorListener();
+}
diff --git a/javax/xml/transform/TransformerConfigurationException.java b/javax/xml/transform/TransformerConfigurationException.java
new file mode 100644
index 0000000..50fe50d
--- /dev/null
+++ b/javax/xml/transform/TransformerConfigurationException.java
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ */
+
+// $Id: TransformerConfigurationException.java 569994 2007-08-27 04:28:57Z mrglavas $
+
+package javax.xml.transform;
+
+/**
+ * Indicates a serious configuration error.
+ */
+public class TransformerConfigurationException extends TransformerException {
+
+    /**
+     * Create a new <code>TransformerConfigurationException</code> with no
+     * detail message.
+     */
+    public TransformerConfigurationException() {
+        super("Configuration Error");
+    }
+
+    /**
+     * Create a new <code>TransformerConfigurationException</code> with
+     * the <code>String </code> specified as an error message.
+     *
+     * @param msg The error message for the exception.
+     */
+    public TransformerConfigurationException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Create a new <code>TransformerConfigurationException</code> with a
+     * given <code>Exception</code> base cause of the error.
+     *
+     * @param e The exception to be encapsulated in a
+     * TransformerConfigurationException.
+     */
+    public TransformerConfigurationException(Throwable e) {
+        super(e);
+    }
+
+    /**
+     * Create a new <code>TransformerConfigurationException</code> with the
+     * given <code>Exception</code> base cause and detail message.
+     *
+     * @param e The exception to be encapsulated in a
+     *      TransformerConfigurationException
+     * @param msg The detail message.
+     */
+    public TransformerConfigurationException(String msg, Throwable e) {
+        super(msg, e);
+    }
+
+    /**
+     * Create a new TransformerConfigurationException from a message and a Locator.
+     *
+     * <p>This constructor is especially useful when an application is
+     * creating its own exception from within a DocumentHandler
+     * callback.</p>
+     *
+     * @param message The error or warning message.
+     * @param locator The locator object for the error or warning.
+     */
+    public TransformerConfigurationException(String message,
+                                             SourceLocator locator) {
+        super(message, locator);
+    }
+
+    /**
+     * Wrap an existing exception in a TransformerConfigurationException.
+     *
+     * @param message The error or warning message, or null to
+     *                use the message from the embedded exception.
+     * @param locator The locator object for the error or warning.
+     * @param e Any exception.
+     */
+    public TransformerConfigurationException(String message,
+                                             SourceLocator locator,
+                                             Throwable e) {
+        super(message, locator, e);
+    }
+}
diff --git a/javax/xml/transform/TransformerException.java b/javax/xml/transform/TransformerException.java
new file mode 100644
index 0000000..74312b8
--- /dev/null
+++ b/javax/xml/transform/TransformerException.java
@@ -0,0 +1,316 @@
+/*
+ * 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.
+ */
+
+// $Id: TransformerException.java 569994 2007-08-27 04:28:57Z mrglavas $
+
+package javax.xml.transform;
+
+/**
+ * This class specifies an exceptional condition that occurred
+ * during the transformation process.
+ */
+public class TransformerException extends Exception {
+
+    // Added serialVersionUID to preserve binary compatibility
+    private static final long serialVersionUID = 975798773772956428L;
+
+    /** Field locator specifies where the error occurred */
+    SourceLocator locator;
+
+    /**
+     * Method getLocator retrieves an instance of a SourceLocator
+     * object that specifies where an error occurred.
+     *
+     * @return A SourceLocator object, or null if none was specified.
+     */
+    public SourceLocator getLocator() {
+        return locator;
+    }
+
+    /**
+     * Method setLocator sets an instance of a SourceLocator
+     * object that specifies where an error occurred.
+     *
+     * @param location A SourceLocator object, or null to clear the location.
+     */
+    public void setLocator(SourceLocator location) {
+        locator = location;
+    }
+
+    /** Field containedException specifies a wrapped exception.  May be null. */
+    Throwable containedException;
+
+    /**
+     * This method retrieves an exception that this exception wraps.
+     *
+     * @return An Throwable object, or null.
+     * @see #getCause
+     */
+    public Throwable getException() {
+        return containedException;
+    }
+
+    /**
+     * Returns the cause of this throwable or <code>null</code> if the
+     * cause is nonexistent or unknown.  (The cause is the throwable that
+     * caused this throwable to get thrown.)
+     */
+    public Throwable getCause() {
+
+        return ((containedException == this)
+                ? null
+                : containedException);
+    }
+
+    /**
+     * 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 #TransformerException(Throwable)} or
+     * {@link #TransformerException(String,Throwable)}, this method cannot be called
+     * even once.
+     *
+     * @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.)
+     * @return  a reference to this <code>Throwable</code> instance.
+     * @throws IllegalArgumentException if <code>cause</code> is this
+     *         throwable.  (A throwable cannot
+     *         be its own cause.)
+     * @throws IllegalStateException if this throwable was
+     *         created with {@link #TransformerException(Throwable)} or
+     *         {@link #TransformerException(String,Throwable)}, or this method has already
+     *         been called on this throwable.
+     */
+    public synchronized Throwable initCause(Throwable cause) {
+
+        if (this.containedException != null) {
+            throw new IllegalStateException("Can't overwrite cause");
+        }
+
+        if (cause == this) {
+            throw new IllegalArgumentException(
+                "Self-causation not permitted");
+        }
+
+        this.containedException = cause;
+
+        return this;
+    }
+
+    /**
+     * Create a new TransformerException.
+     *
+     * @param message The error or warning message.
+     */
+    public TransformerException(String message) {
+
+        super(message);
+
+        this.containedException = null;
+        this.locator            = null;
+    }
+
+    /**
+     * Create a new TransformerException wrapping an existing exception.
+     *
+     * @param e The exception to be wrapped.
+     */
+    public TransformerException(Throwable e) {
+
+        super(e.toString());
+
+        this.containedException = e;
+        this.locator            = null;
+    }
+
+    /**
+     * Wrap an existing exception in a TransformerException.
+     *
+     * <p>This is used for throwing processor exceptions before
+     * the processing has started.</p>
+     *
+     * @param message The error or warning message, or null to
+     *                use the message from the embedded exception.
+     * @param e Any exception
+     */
+    public TransformerException(String message, Throwable e) {
+
+        super(((message == null) || (message.length() == 0))
+              ? e.toString()
+              : message);
+
+        this.containedException = e;
+        this.locator            = null;
+    }
+
+    /**
+     * Create a new TransformerException from a message and a Locator.
+     *
+     * <p>This constructor is especially useful when an application is
+     * creating its own exception from within a DocumentHandler
+     * callback.</p>
+     *
+     * @param message The error or warning message.
+     * @param locator The locator object for the error or warning.
+     */
+    public TransformerException(String message, SourceLocator locator) {
+
+        super(message);
+
+        this.containedException = null;
+        this.locator            = locator;
+    }
+
+    /**
+     * Wrap an existing exception in a TransformerException.
+     *
+     * @param message The error or warning message, or null to
+     *                use the message from the embedded exception.
+     * @param locator The locator object for the error or warning.
+     * @param e Any exception
+     */
+    public TransformerException(String message, SourceLocator locator,
+                                Throwable e) {
+
+        super(message);
+
+        this.containedException = e;
+        this.locator            = locator;
+    }
+
+    /**
+     * Get the error message with location information
+     * appended.
+     *
+     * @return A <code>String</code> representing the error message with
+     *         location information appended.
+     */
+    public String getMessageAndLocation() {
+
+        StringBuilder sbuffer = new StringBuilder();
+        String       message = super.getMessage();
+
+        if (null != message) {
+            sbuffer.append(message);
+        }
+
+        if (null != locator) {
+            String systemID = locator.getSystemId();
+            int    line     = locator.getLineNumber();
+            int    column   = locator.getColumnNumber();
+
+            if (null != systemID) {
+                sbuffer.append("; SystemID: ");
+                sbuffer.append(systemID);
+            }
+
+            if (0 != line) {
+                sbuffer.append("; Line#: ");
+                sbuffer.append(line);
+            }
+
+            if (0 != column) {
+                sbuffer.append("; Column#: ");
+                sbuffer.append(column);
+            }
+        }
+
+        return sbuffer.toString();
+    }
+
+    /**
+     * Get the location information as a string.
+     *
+     * @return A string with location info, or null
+     * if there is no location information.
+     */
+    public String getLocationAsString() {
+
+        if (null != locator) {
+            StringBuilder sbuffer  = new StringBuilder();
+            String       systemID = locator.getSystemId();
+            int          line     = locator.getLineNumber();
+            int          column   = locator.getColumnNumber();
+
+            if (null != systemID) {
+                sbuffer.append("; SystemID: ");
+                sbuffer.append(systemID);
+            }
+
+            if (0 != line) {
+                sbuffer.append("; Line#: ");
+                sbuffer.append(line);
+            }
+
+            if (0 != column) {
+                sbuffer.append("; Column#: ");
+                sbuffer.append(column);
+            }
+
+            return sbuffer.toString();
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Print the the trace of methods from where the error
+     * originated.  This will trace all nested exception
+     * objects, as well as this object.
+     */
+    public void printStackTrace() {
+        printStackTrace(new java.io.PrintWriter(System.err, true));
+    }
+
+    /**
+     * Print the the trace of methods from where the error
+     * originated.  This will trace all nested exception
+     * objects, as well as this object.
+     * @param s The stream where the dump will be sent to.
+     */
+    public void printStackTrace(java.io.PrintStream s) {
+        printStackTrace(new java.io.PrintWriter(s));
+    }
+
+    /**
+     * Print the the trace of methods from where the error
+     * originated.  This will trace all nested exception
+     * objects, as well as this object.
+     * @param s The writer where the dump will be sent to.
+     */
+    public void printStackTrace(java.io.PrintWriter s) {
+
+        if (s == null) {
+            s = new java.io.PrintWriter(System.err, true);
+        }
+
+        try {
+            String locInfo = getLocationAsString();
+
+            if (null != locInfo) {
+                s.println(locInfo);
+            }
+
+            super.printStackTrace(s);
+        } catch (Throwable e) {}
+    }
+}
diff --git a/javax/xml/transform/TransformerFactory.java b/javax/xml/transform/TransformerFactory.java
new file mode 100644
index 0000000..c6c92ce
--- /dev/null
+++ b/javax/xml/transform/TransformerFactory.java
@@ -0,0 +1,328 @@
+/*
+ * 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.
+ */
+
+// $Id: TransformerFactory.java 884963 2009-11-27 19:11:59Z mrglavas $
+
+package javax.xml.transform;
+
+/**
+ * <p>A TransformerFactory instance can be used to create
+ * {@link javax.xml.transform.Transformer} and
+ * {@link javax.xml.transform.Templates} objects.</p>
+ *
+ * <p>The system property that determines which Factory implementation
+ * to create is named <code>"javax.xml.transform.TransformerFactory"</code>.
+ * This property names a concrete subclass of the
+ * <code>TransformerFactory</code> abstract class. If the property is not
+ * defined, a platform default is be used.</p>
+ *
+ * @author <a href="mailto:[email protected]">Jeff Suttor</a>
+ */
+public abstract class TransformerFactory {
+
+    /**
+     * Default constructor is protected on purpose.
+     */
+    protected TransformerFactory() { }
+
+
+    /**
+     * <p>Get current state of canonicalization.</p>
+     *
+     * @return current state canonicalization control
+     */
+    /*
+    public boolean getCanonicalization() {
+        return canonicalState;
+    }
+    */
+
+    /**
+     * <p>Set canonicalization control to <code>true</code> or
+     * </code>false</code>.</p>
+     *
+     * @param state of canonicalization
+     */
+    /*
+    public void setCanonicalization(boolean state) {
+        canonicalState = state;
+    }
+    */
+
+    /**
+     * Returns Android's implementation of {@code TransformerFactory}. Unlike
+     * other Java implementations, this method does not consult system
+     * properties, properties files, or the services API.
+     *
+     * @throws TransformerFactoryConfigurationError never. Included for API
+     *     compatibility with other Java implementations.
+     */
+    public static TransformerFactory newInstance()
+            throws TransformerFactoryConfigurationError {
+        String className = "org.apache.xalan.processor.TransformerFactoryImpl";
+        try {
+            return (TransformerFactory) Class.forName(className).newInstance();
+        } catch (Exception e) {
+            throw new NoClassDefFoundError(className);
+        }
+    }
+
+    /**
+     * Returns an instance of the named implementation of {@code TransformerFactory}.
+     *
+     * @throws TransformerFactoryConfigurationError if {@code factoryClassName} is not available or
+     *     cannot be instantiated.
+     * @since 1.6
+     */
+    public static TransformerFactory newInstance(String factoryClassName, ClassLoader classLoader)
+            throws TransformerFactoryConfigurationError {
+        if (factoryClassName == null) {
+            throw new TransformerFactoryConfigurationError("factoryClassName == null");
+        }
+        if (classLoader == null) {
+            classLoader = Thread.currentThread().getContextClassLoader();
+        }
+        try {
+            Class<?> type = classLoader != null
+                    ? classLoader.loadClass(factoryClassName)
+                    : Class.forName(factoryClassName);
+            return (TransformerFactory) type.newInstance();
+        } catch (ClassNotFoundException e) {
+            throw new TransformerFactoryConfigurationError(e);
+        } catch (InstantiationException e) {
+            throw new TransformerFactoryConfigurationError(e);
+        } catch (IllegalAccessException e) {
+            throw new TransformerFactoryConfigurationError(e);
+        }
+    }
+
+    /**
+     * <p>Process the <code>Source</code> into a <code>Transformer</code>
+     * <code>Object</code>.  The <code>Source</code> is an XSLT document that
+     * conforms to <a href="http://www.w3.org/TR/xslt">
+     * XSL Transformations (XSLT) Version 1.0</a>.  Care must
+     * be taken not to use this <code>Transformer</code> in multiple
+     * <code>Thread</code>s running concurrently.
+     * Different <code>TransformerFactories</code> can be used concurrently by
+     * different <code>Thread</code>s.</p>
+     *
+     * @param source <code>Source </code> of XSLT document used to create
+     *   <code>Transformer</code>.
+     *   Examples of XML <code>Source</code>s include
+     *   {@link javax.xml.transform.stream.StreamSource StreamSource},
+     *   {@link javax.xml.transform.sax.SAXSource SAXSource} and
+     *   {@link javax.xml.transform.dom.DOMSource DOMSource}.
+     *
+     * @return A <code>Transformer</code> object that may be used to perform
+     *   a transformation in a single <code>Thread</code>, never
+     *   <code>null</code>.
+     *
+     * @throws TransformerConfigurationException Thrown if there are errors when
+     *    parsing the <code>Source</code> or it is not possible to create a
+     *   <code>Transformer</code> instance.
+     *
+     * @see <a href="http://www.w3.org/TR/xslt">
+     *   XSL Transformations (XSLT) Version 1.0</a>
+     */
+    public abstract Transformer newTransformer(Source source)
+        throws TransformerConfigurationException;
+
+    /**
+     * <p>Create a new <code>Transformer</code> that performs a copy
+     * of the <code>Source</code> to the <code>Result</code>.
+     * i.e. the "<em>identity transform</em>".</p>
+     *
+     * @return A Transformer object that may be used to perform a transformation
+     * in a single thread, never null.
+     *
+     * @exception TransformerConfigurationException Thrown if it is not
+     *   possible to create a <code>Transformer</code> instance.
+     */
+    public abstract Transformer newTransformer()
+        throws TransformerConfigurationException;
+
+    /**
+     * Process the Source into a Templates object, which is a
+     * a compiled representation of the source. This Templates object
+     * may then be used concurrently across multiple threads.  Creating
+     * a Templates object allows the TransformerFactory to do detailed
+     * performance optimization of transformation instructions, without
+     * penalizing runtime transformation.
+     *
+     * @param source An object that holds a URL, input stream, etc.
+     *
+     * @return A Templates object capable of being used for transformation
+     * purposes, never null.
+     *
+     * @exception TransformerConfigurationException May throw this during the
+     * parse when it is constructing the Templates object and fails.
+     */
+    public abstract Templates newTemplates(Source source)
+        throws TransformerConfigurationException;
+
+    /**
+     * <p>Get the stylesheet specification(s) associated with the
+     * XML <code>Source</code> document via the
+     * <a href="http://www.w3.org/TR/xml-stylesheet/">
+     * xml-stylesheet processing instruction</a> that match the given criteria.
+     * Note that it is possible to return several stylesheets, in which case
+     * they are applied as if they were a list of imports or cascades in a
+     * single stylesheet.</p>
+     *
+     * @param source The XML source document.
+     * @param media The media attribute to be matched.  May be null, in which
+     *      case the preferred templates will be used (i.e. alternate = no).
+     * @param title The value of the title attribute to match.  May be null.
+     * @param charset The value of the charset attribute to match.  May be null.
+     *
+     * @return A <code>Source</code> <code>Object</code> suitable for passing
+     *   to the <code>TransformerFactory</code>.
+     *
+     * @throws TransformerConfigurationException An <code>Exception</code>
+     *   is thrown if an error occurs during parsing of the
+     *   <code>source</code>.
+     *
+     * @see <a href="http://www.w3.org/TR/xml-stylesheet/">
+     *   Associating Style Sheets with XML documents Version 1.0</a>
+     */
+    public abstract Source getAssociatedStylesheet(
+        Source source,
+        String media,
+        String title,
+        String charset)
+        throws TransformerConfigurationException;
+
+    /**
+     * Set an object that is used by default during the transformation
+     * to resolve URIs used in document(), xsl:import, or xsl:include.
+     *
+     * @param resolver An object that implements the URIResolver interface,
+     * or null.
+     */
+    public abstract void setURIResolver(URIResolver resolver);
+
+    /**
+     * Get the object that is used by default during the transformation
+     * to resolve URIs used in document(), xsl:import, or xsl:include.
+     *
+     * @return The URIResolver that was set with setURIResolver.
+     */
+    public abstract URIResolver getURIResolver();
+
+    //======= CONFIGURATION METHODS =======
+
+    /**
+     * <p>Set a feature for this <code>TransformerFactory</code> and <code>Transformer</code>s
+     * or <code>Template</code>s created by this factory.</p>
+     *
+     * <p>
+     * Feature names are fully qualified {@link java.net.URI}s.
+     * Implementations may define their own features.
+     * An {@link TransformerConfigurationException} is thrown if this <code>TransformerFactory</code> or the
+     * <code>Transformer</code>s or <code>Template</code>s it creates cannot support the feature.
+     * It is possible for an <code>TransformerFactory</code> to expose a feature value but be unable to change its state.
+     * </p>
+     *
+     * <p>All implementations are required to support the {@link javax.xml.XMLConstants#FEATURE_SECURE_PROCESSING} feature.
+     * When the feature is:</p>
+     * <ul>
+     *   <li>
+     *     <code>true</code>: the implementation will limit XML processing to conform to implementation limits
+     *     and behave in a secure fashion as defined by the implementation.
+     *     Examples include resolving user defined style sheets and functions.
+     *     If XML processing is limited for security reasons, it will be reported via a call to the registered
+     *     {@link ErrorListener#fatalError(TransformerException exception)}.
+     *     See {@link  #setErrorListener(ErrorListener listener)}.
+     *   </li>
+     *   <li>
+     *     <code>false</code>: the implementation will processing XML according to the XML specifications without
+     *     regard to possible implementation limits.
+     *   </li>
+     * </ul>
+     *
+     * @param name Feature name.
+     * @param value Is feature state <code>true</code> or <code>false</code>.
+     *
+     * @throws TransformerConfigurationException if this <code>TransformerFactory</code>
+     *   or the <code>Transformer</code>s or <code>Template</code>s it creates cannot support this feature.
+     * @throws NullPointerException If the <code>name</code> parameter is null.
+     */
+    public abstract void setFeature(String name, boolean value)
+        throws TransformerConfigurationException;
+
+    /**
+     * Look up the value of a feature.
+     *
+     * <p>
+     * Feature names are fully qualified {@link java.net.URI}s.
+     * Implementations may define their own features.
+     * <code>false</code> is returned if this <code>TransformerFactory</code> or the
+     * <code>Transformer</code>s or <code>Template</code>s it creates cannot support the feature.
+     * It is possible for an <code>TransformerFactory</code> to expose a feature value but be unable to change its state.
+     * </p>
+     *
+     * @param name Feature name.
+     *
+     * @return The current state of the feature, <code>true</code> or <code>false</code>.
+     *
+     * @throws NullPointerException If the <code>name</code> parameter is null.
+     */
+    public abstract boolean getFeature(String name);
+
+    /**
+     * Allows the user to set specific attributes on the underlying
+     * implementation.  An attribute in this context is defined to
+     * be an option that the implementation provides.
+     * An <code>IllegalArgumentException</code> is thrown if the underlying
+     * implementation doesn't recognize the attribute.
+     *
+     * @param name The name of the attribute.
+     * @param value The value of the attribute.
+     */
+    public abstract void setAttribute(String name, Object value);
+
+    /**
+     * Allows the user to retrieve specific attributes on the underlying
+     * implementation.
+     * An <code>IllegalArgumentException</code> is thrown if the underlying
+     * implementation doesn't recognize the attribute.
+     *
+     * @param name The name of the attribute.
+     * @return value The value of the attribute.
+     */
+    public abstract Object getAttribute(String name);
+
+    /**
+     * Set the error event listener for the TransformerFactory, which
+     * is used for the processing of transformation instructions,
+     * and not for the transformation itself.
+     * An <code>IllegalArgumentException</code> is thrown if the
+     * <code>ErrorListener</code> listener is <code>null</code>.
+     *
+     * @param listener The new error listener.
+     */
+    public abstract void setErrorListener(ErrorListener listener);
+
+    /**
+     * Get the error event handler for the TransformerFactory.
+     *
+     * @return The current error handler, which should never be null.
+     */
+    public abstract ErrorListener getErrorListener();
+
+}
+
diff --git a/javax/xml/transform/TransformerFactoryConfigurationError.java b/javax/xml/transform/TransformerFactoryConfigurationError.java
new file mode 100644
index 0000000..8a4fee6
--- /dev/null
+++ b/javax/xml/transform/TransformerFactoryConfigurationError.java
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+// $Id: TransformerFactoryConfigurationError.java 569994 2007-08-27 04:28:57Z mrglavas $
+
+package javax.xml.transform;
+
+/**
+ * Thrown when a problem with configuration with the Transformer Factories
+ * exists. This error will typically be thrown when the class of a
+ * transformation factory specified in the system properties cannot be found
+ * or instantiated.
+ */
+public class TransformerFactoryConfigurationError extends Error {
+
+    /**
+     * <code>Exception</code> for the
+     *  <code>TransformerFactoryConfigurationError</code>.
+     */
+    private Exception exception;
+
+    /**
+     * Create a new <code>TransformerFactoryConfigurationError</code> with no
+     * detail message.
+     */
+    public TransformerFactoryConfigurationError() {
+        this.exception = null;
+    }
+
+    /**
+     * Create a new <code>TransformerFactoryConfigurationError</code> with
+     * the <code>String</code> specified as an error message.
+     *
+     * @param msg The error message for the exception.
+     */
+    public TransformerFactoryConfigurationError(String msg) {
+
+        super(msg);
+
+        this.exception = null;
+    }
+
+    /**
+     * Create a new <code>TransformerFactoryConfigurationError</code> with a
+     * given <code>Exception</code> base cause of the error.
+     *
+     * @param e The exception to be encapsulated in a
+     * TransformerFactoryConfigurationError.
+     */
+    public TransformerFactoryConfigurationError(Exception e) {
+
+        super(e.toString());
+
+        this.exception = e;
+    }
+
+    /**
+     * Create a new <code>TransformerFactoryConfigurationError</code> with the
+     * given <code>Exception</code> base cause and detail message.
+     *
+     * @param e The exception to be encapsulated in a
+     * TransformerFactoryConfigurationError
+     * @param msg The detail message.
+     */
+    public TransformerFactoryConfigurationError(Exception e, String msg) {
+
+        super(msg);
+
+        this.exception = e;
+    }
+
+    /**
+     * Return the message (if any) for this error . If there is no
+     * message for the exception and there is an encapsulated
+     * exception then the message of that exception will be returned.
+     *
+     * @return The error message.
+     */
+    public String getMessage() {
+
+        String message = super.getMessage();
+
+        if ((message == null) && (exception != null)) {
+            return exception.getMessage();
+        }
+
+        return message;
+    }
+
+    /**
+     * Return the actual exception (if any) that caused this exception to
+     * be raised.
+     *
+     * @return The encapsulated exception, or null if there is none.
+     */
+    public Exception getException() {
+        return exception;
+    }
+}
diff --git a/javax/xml/transform/URIResolver.java b/javax/xml/transform/URIResolver.java
new file mode 100644
index 0000000..f8ab601
--- /dev/null
+++ b/javax/xml/transform/URIResolver.java
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+// $Id: URIResolver.java 446598 2006-09-15 12:55:40Z jeremias $
+
+package javax.xml.transform;
+
+/**
+ * <p>An object that implements this interface that can be called by the processor
+ * to turn a URI used in document(), xsl:import, or xsl:include into a Source object.
+ */
+public interface URIResolver {
+
+    /**
+     * Called by the processor when it encounters
+     * an xsl:include, xsl:import, or document() function.
+     *
+     * @param href An href attribute, which may be relative or absolute.
+     * @param base The base URI against which the first argument will be made
+     * absolute if the absolute URI is required.
+     *
+     * @return A Source object, or null if the href cannot be resolved,
+     * and the processor should try to resolve the URI itself.
+     *
+     * @throws TransformerException if an error occurs when trying to
+     * resolve the URI.
+     */
+    public Source resolve(String href, String base)
+        throws TransformerException;
+}
diff --git a/javax/xml/transform/dom/DOMLocator.java b/javax/xml/transform/dom/DOMLocator.java
new file mode 100644
index 0000000..3aacb57
--- /dev/null
+++ b/javax/xml/transform/dom/DOMLocator.java
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+// $Id: DOMLocator.java 446598 2006-09-15 12:55:40Z jeremias $
+
+package javax.xml.transform.dom;
+
+import javax.xml.transform.SourceLocator;
+import org.w3c.dom.Node;
+
+
+/**
+ * Indicates the position of a node in a source DOM, intended
+ * primarily for error reporting.  To use a DOMLocator, the receiver of an
+ * error must downcast the {@link javax.xml.transform.SourceLocator}
+ * object returned by an exception. A {@link javax.xml.transform.Transformer}
+ * may use this object for purposes other than error reporting, for instance,
+ * to indicate the source node that originated a result node.
+ */
+public interface DOMLocator extends SourceLocator {
+
+    /**
+     * Return the node where the event occurred.
+     *
+     * @return The node that is the location for the event.
+     */
+    public Node getOriginatingNode();
+}
+
diff --git a/javax/xml/transform/dom/DOMResult.java b/javax/xml/transform/dom/DOMResult.java
new file mode 100644
index 0000000..0ce3ec5
--- /dev/null
+++ b/javax/xml/transform/dom/DOMResult.java
@@ -0,0 +1,350 @@
+/*
+ * 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.
+ */
+
+// $Id: DOMResult.java 569995 2007-08-27 04:31:06Z mrglavas $
+
+package javax.xml.transform.dom;
+
+import javax.xml.transform.Result;
+import org.w3c.dom.Node;
+
+/**
+ * <p>Acts as a holder for a transformation result tree in the form of a Document Object Model (DOM) tree.</p>
+ *
+ * <p>If no output DOM source is set, the transformation will create a Document node as the holder for the result of the transformation,
+ * which may be retrieved with {@link #getNode()}.</p>
+ *
+ * @author <a href="[email protected]">Jeff Suttor</a>
+ * @version $Revision: 569995 $, $Date: 2007-08-26 21:31:06 -0700 (Sun, 26 Aug 2007) $
+ */
+public class DOMResult implements Result {
+
+    /** <p>If {@link javax.xml.transform.TransformerFactory#getFeature}
+     * returns <code>true</code> when passed this value as an argument,
+     * the <code>Transformer</code> supports <code>Result</code> output of this type.</p>
+     */
+    public static final String FEATURE = "http://javax.xml.transform.dom.DOMResult/feature";
+
+    /**
+     * <p>Zero-argument default constructor.</p>
+     *
+     * <p><code>node</code>,
+     * <code>siblingNode</code> and
+     * <code>systemId</code>
+     * will be set to <code>null</code>.</p>
+     */
+    public DOMResult() {
+        setNode(null);
+        setNextSibling(null);
+        setSystemId(null);
+    }
+
+    /**
+     * <p>Use a DOM node to create a new output target.</p>
+     *
+     * <p>In practice, the node should be
+     * a {@link org.w3c.dom.Document} node,
+     * a {@link org.w3c.dom.DocumentFragment} node, or
+     * a {@link org.w3c.dom.Element} node.
+     * In other words, a node that accepts children.</p>
+     *
+     * <p><code>siblingNode</code> and
+     * <code>systemId</code>
+     * will be set to <code>null</code>.</p>
+     *
+     * @param node The DOM node that will contain the result tree.
+     */
+    public DOMResult(Node node) {
+        setNode(node);
+        setNextSibling(null);
+        setSystemId(null);
+    }
+
+    /**
+     * <p>Use a DOM node to create a new output target with the specified System ID.<p>
+     *
+     * <p>In practice, the node should be
+     * a {@link org.w3c.dom.Document} node,
+     * a {@link org.w3c.dom.DocumentFragment} node, or
+     * a {@link org.w3c.dom.Element} node.
+     * In other words, a node that accepts children.</p>
+     *
+     * <p><code>siblingNode</code> will be set to <code>null</code>.</p>
+     *
+     * @param node The DOM node that will contain the result tree.
+     * @param systemId The system identifier which may be used in association with this node.
+     */
+    public DOMResult(Node node, String systemId) {
+        setNode(node);
+        setNextSibling(null);
+        setSystemId(systemId);
+    }
+
+    /**
+     * <p>Use a DOM node to create a new output target specifying the child node where the result nodes should be inserted before.</p>
+     *
+     * <p>In practice, <code>node</code> and <code>nextSibling</code> should be
+     * a {@link org.w3c.dom.Document} node,
+     * a {@link org.w3c.dom.DocumentFragment} node, or
+     * a {@link org.w3c.dom.Element} node.
+     * In other words, a node that accepts children.</p>
+     *
+     * <p>Use <code>nextSibling</code> to specify the child node
+     * where the result nodes should be inserted before.
+     * If <code>nextSibling</code> is not a sibling of <code>node</code>,
+     * then an <code>IllegalArgumentException</code> is thrown.
+     * If <code>node</code> is <code>null</code> and <code>nextSibling</code> is not <code>null</code>,
+     * then an <code>IllegalArgumentException</code> is thrown.
+     * If <code>nextSibling</code> is <code>null</code>,
+     * then the behavior is the same as calling {@link #DOMResult(Node node)},
+     * i.e. append the result nodes as the last child of the specified <code>node</code>.</p>
+     *
+     * <p><code>systemId</code> will be set to <code>null</code>.</p>
+     *
+     * @param node The DOM node that will contain the result tree.
+     * @param nextSibling The child node where the result nodes should be inserted before.
+     *
+     * @throws IllegalArgumentException If <code>nextSibling</code> is not a sibling of <code>node</code>.
+     * @throws IllegalArgumentException If <code>node</code> is <code>null</code> and <code>nextSibling</code> is not <code>null</code>.
+     *
+     * @since 1.5
+     */
+    public DOMResult(Node node, Node nextSibling) {
+
+        // does the corrent parent/child relationship exist?
+        if (nextSibling != null) {
+            // cannot be a sibling of a null node
+            if (node == null) {
+                throw new IllegalArgumentException("Cannot create a DOMResult when the nextSibling is contained by the \"null\" node.");
+            }
+
+            // nextSibling contained by node?
+            if ((node.compareDocumentPosition(nextSibling)&Node.DOCUMENT_POSITION_CONTAINED_BY)==0) {
+                throw new IllegalArgumentException("Cannot create a DOMResult when the nextSibling is not contained by the node.");
+            }
+        }
+
+        setNode(node);
+        setNextSibling(nextSibling);
+        setSystemId(null);
+    }
+
+    /**
+     * <p>Use a DOM node to create a new output target specifying the child node where the result nodes should be inserted before and
+     * the specified System ID.</p>
+     *
+     * <p>In practice, <code>node</code> and <code>nextSibling</code> should be
+     * a {@link org.w3c.dom.Document} node,
+     * a {@link org.w3c.dom.DocumentFragment} node, or a
+     * {@link org.w3c.dom.Element} node.
+     * In other words, a node that accepts children.</p>
+     *
+     * <p>Use <code>nextSibling</code> to specify the child node
+     * where the result nodes should be inserted before.
+     * If <code>nextSibling</code> is not a sibling of <code>node</code>,
+     * then an <code>IllegalArgumentException</code> is thrown.
+     * If <code>node</code> is <code>null</code> and <code>nextSibling</code> is not <code>null</code>,
+     * then an <code>IllegalArgumentException</code> is thrown.
+     * If <code>nextSibling</code> is <code>null</code>,
+     * then the behavior is the same as calling {@link #DOMResult(Node node, String systemId)},
+     * i.e. append the result nodes as the last child of the specified node and use the specified System ID.</p>
+     *
+     * @param node The DOM node that will contain the result tree.
+     * @param nextSibling The child node where the result nodes should be inserted before.
+     * @param systemId The system identifier which may be used in association with this node.
+     *
+     * @throws IllegalArgumentException If <code>nextSibling</code> is not a sibling of <code>node</code>.
+     * @throws IllegalArgumentException If <code>node</code> is <code>null</code> and <code>nextSibling</code> is not <code>null</code>.
+     *
+     * @since 1.5
+     */
+    public DOMResult(Node node, Node nextSibling, String systemId) {
+
+        // does the current parent/child relationship exist?
+        if (nextSibling != null) {
+            // cannot be a sibling of a null node
+            if (node == null) {
+                throw new IllegalArgumentException("Cannot create a DOMResult when the nextSibling is contained by the \"null\" node.");
+            }
+
+            // nextSibling contained by node?
+            if ((node.compareDocumentPosition(nextSibling)&Node.DOCUMENT_POSITION_CONTAINED_BY)==0) {
+                throw new IllegalArgumentException("Cannot create a DOMResult when the nextSibling is not contained by the node.");
+            }
+        }
+
+        setNode(node);
+        setNextSibling(nextSibling);
+        setSystemId(systemId);
+    }
+
+    /**
+     * <p>Set the node that will contain the result DOM tree.<p>
+     *
+     * <p>In practice, the node should be
+     * a {@link org.w3c.dom.Document} node,
+     * a {@link org.w3c.dom.DocumentFragment} node, or
+     * a {@link org.w3c.dom.Element} node.
+     * In other words, a node that accepts children.</p>
+     *
+     * <p>An <code>IllegalStateException</code> is thrown if <code>nextSibling</code> is not <code>null</code> and
+     * <code>node</code> is not a parent of <code>nextSibling</code>.
+     * An <code>IllegalStateException</code> is thrown if <code>node</code> is <code>null</code> and
+     * <code>nextSibling</code> is not <code>null</code>.</p>
+     *
+     * @param node The node to which the transformation will be appended.
+     *
+     * @throws IllegalStateException If <code>nextSibling</code> is not <code>null</code> and
+     *   <code>nextSibling</code> is not a child of <code>node</code>.
+     * @throws IllegalStateException If <code>node</code> is <code>null</code> and
+     *   <code>nextSibling</code> is not <code>null</code>.
+     */
+    public void setNode(Node node) {
+        // does the corrent parent/child relationship exist?
+        if (nextSibling != null) {
+            // cannot be a sibling of a null node
+            if (node == null) {
+                throw new IllegalStateException("Cannot create a DOMResult when the nextSibling is contained by the \"null\" node.");
+            }
+
+            // nextSibling contained by node?
+            if ((node.compareDocumentPosition(nextSibling)&Node.DOCUMENT_POSITION_CONTAINED_BY)==0) {
+                throw new IllegalArgumentException("Cannot create a DOMResult when the nextSibling is not contained by the node.");
+            }
+        }
+
+        this.node = node;
+    }
+
+    /**
+     * <p>Get the node that will contain the result DOM tree.</p>
+     *
+     * <p>If no node was set via
+     * {@link #DOMResult(Node node)},
+     * {@link #DOMResult(Node node, String systeId)},
+     * {@link #DOMResult(Node node, Node nextSibling)},
+     * {@link #DOMResult(Node node, Node nextSibling, String systemId)} or
+     * {@link #setNode(Node node)},
+     * then the node will be set by the transformation, and may be obtained from this method once the transformation is complete.
+     * Calling this method before the transformation will return <code>null</code>.</p>
+     *
+     * @return The node to which the transformation will be appended.
+     */
+    public Node getNode() {
+        return node;
+    }
+
+    /**
+     * <p>Set the child node before which the result nodes will be inserted.</p>
+     *
+     * <p>Use <code>nextSibling</code> to specify the child node
+     * before which the result nodes should be inserted.
+     * If <code>nextSibling</code> is not a descendant of <code>node</code>,
+     * then an <code>IllegalArgumentException</code> is thrown.
+     * If <code>node</code> is <code>null</code> and <code>nextSibling</code> is not <code>null</code>,
+     * then an <code>IllegalStateException</code> is thrown.
+     * If <code>nextSibling</code> is <code>null</code>,
+     * then the behavior is the same as calling {@link #DOMResult(Node node)},
+     * i.e. append the result nodes as the last child of the specified <code>node</code>.</p>
+     *
+     * @param nextSibling The child node before which the result nodes will be inserted.
+     *
+     * @throws IllegalArgumentException If <code>nextSibling</code> is not a descendant of <code>node</code>.
+     * @throws IllegalStateException If <code>node</code> is <code>null</code> and <code>nextSibling</code> is not <code>null</code>.
+     *
+     * @since 1.5
+     */
+    public void setNextSibling(Node nextSibling) {
+
+        // does the corrent parent/child relationship exist?
+        if (nextSibling != null) {
+            // cannot be a sibling of a null node
+            if (node == null) {
+                throw new IllegalStateException("Cannot create a DOMResult when the nextSibling is contained by the \"null\" node.");
+            }
+
+            // nextSibling contained by node?
+            if ((node.compareDocumentPosition(nextSibling)&Node.DOCUMENT_POSITION_CONTAINED_BY)==0) {
+                throw new IllegalArgumentException("Cannot create a DOMResult when the nextSibling is not contained by the node.");
+            }
+        }
+
+        this.nextSibling = nextSibling;
+    }
+
+    /**
+     * <p>Get the child node before which the result nodes will be inserted.</p>
+     *
+     * <p>If no node was set via
+     * {@link #DOMResult(Node node, Node nextSibling)},
+     * {@link #DOMResult(Node node, Node nextSibling, String systemId)} or
+     * {@link #setNextSibling(Node nextSibling)},
+     * then <code>null</code> will be returned.</p>
+     *
+     * @return The child node before which the result nodes will be inserted.
+     *
+     * @since 1.5
+     */
+    public Node getNextSibling() {
+        return nextSibling;
+    }
+
+    /**
+     * <p>Set the systemId that may be used in association with the node.</p>
+     *
+     * @param systemId The system identifier as a URI string.
+     */
+    public void setSystemId(String systemId) {
+        this.systemId = systemId;
+    }
+
+    /**
+     * <p>Get the System Identifier.</p>
+     *
+     * <p>If no System ID was set via
+     * {@link #DOMResult(Node node, String systemId)},
+     * {@link #DOMResult(Node node, Node nextSibling, String systemId)} or
+     * {@link #setSystemId(String systemId)},
+     * then <code>null</code> will be returned.</p>
+     *
+     * @return The system identifier.
+     */
+    public String getSystemId() {
+        return systemId;
+    }
+
+    //////////////////////////////////////////////////////////////////////
+    // Internal state.
+    //////////////////////////////////////////////////////////////////////
+
+    /**
+     * <p>The node to which the transformation will be appended.</p>
+     */
+    private Node node = null;
+
+    /**
+     * <p>The child node before which the result nodes will be inserted.</p>
+     *
+     * @since 1.5
+     */
+    private Node nextSibling = null;
+
+    /**
+     * <p>The System ID that may be used in association with the node.</p>
+     */
+    private String systemId = null;
+}
diff --git a/javax/xml/transform/dom/DOMSource.java b/javax/xml/transform/dom/DOMSource.java
new file mode 100644
index 0000000..52f69ae
--- /dev/null
+++ b/javax/xml/transform/dom/DOMSource.java
@@ -0,0 +1,131 @@
+/*
+ * 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.
+ */
+
+// $Id: DOMSource.java 446598 2006-09-15 12:55:40Z jeremias $
+
+package javax.xml.transform.dom;
+
+import javax.xml.transform.Source;
+import org.w3c.dom.Node;
+
+/**
+ * <p>Acts as a holder for a transformation Source tree in the
+ * form of a Document Object Model (DOM) tree.</p>
+ *
+ * <p>Note that XSLT requires namespace support. Attempting to transform a DOM
+ * that was not contructed with a namespace-aware parser may result in errors.
+ * Parsers can be made namespace aware by calling
+ * {@link javax.xml.parsers.DocumentBuilderFactory#setNamespaceAware(boolean awareness)}.</p>
+ *
+ * @author <a href="[email protected]">Jeff Suttor</a>
+ * @version $Revision: 446598 $, $Date: 2006-09-15 05:55:40 -0700 (Fri, 15 Sep 2006) $
+ * @see <a href="http://www.w3.org/TR/DOM-Level-2">Document Object Model (DOM) Level 2 Specification</a>
+ */
+public class DOMSource implements Source {
+
+    /**
+     * <p><code>Node</code> to serve as DOM source.</p>
+     */
+    private Node node;
+
+    /**
+     * <p>The base ID (URL or system ID) from where URLs
+     * will be resolved.</p>
+     */
+    private String systemID;
+
+    /** If {@link javax.xml.transform.TransformerFactory#getFeature}
+     * returns true when passed this value as an argument,
+     * the Transformer supports Source input of this type.
+     */
+    public static final String FEATURE =
+        "http://javax.xml.transform.dom.DOMSource/feature";
+
+    /**
+     * <p>Zero-argument default constructor.  If this constructor is used, and
+     * no DOM source is set using {@link #setNode(Node node)} , then the
+     * <code>Transformer</code> will
+     * create an empty source {@link org.w3c.dom.Document} using
+     * {@link javax.xml.parsers.DocumentBuilder#newDocument()}.</p>
+     *
+     * @see javax.xml.transform.Transformer#transform(Source xmlSource, Result outputTarget)
+     */
+    public DOMSource() { }
+
+    /**
+     * Create a new input source with a DOM node.  The operation
+     * will be applied to the subtree rooted at this node.  In XSLT,
+     * a "/" pattern still means the root of the tree (not the subtree),
+     * and the evaluation of global variables and parameters is done
+     * from the root node also.
+     *
+     * @param n The DOM node that will contain the Source tree.
+     */
+    public DOMSource(Node n) {
+        setNode(n);
+    }
+
+    /**
+     * Create a new input source with a DOM node, and with the
+     * system ID also passed in as the base URI.
+     *
+     * @param node The DOM node that will contain the Source tree.
+     * @param systemID Specifies the base URI associated with node.
+     */
+    public DOMSource(Node node, String systemID) {
+        setNode(node);
+        setSystemId(systemID);
+    }
+
+    /**
+     * Set the node that will represents a Source DOM tree.
+     *
+     * @param node The node that is to be transformed.
+     */
+    public void setNode(Node node) {
+        this.node = node;
+    }
+
+    /**
+     * Get the node that represents a Source DOM tree.
+     *
+     * @return The node that is to be transformed.
+     */
+    public Node getNode() {
+        return node;
+    }
+
+    /**
+     * Set the base ID (URL or system ID) from where URLs
+     * will be resolved.
+     *
+     * @param systemID Base URL for this DOM tree.
+     */
+    public void setSystemId(String systemID) {
+        this.systemID = systemID;
+    }
+
+    /**
+     * Get the base ID (URL or system ID) from where URLs
+     * will be resolved.
+     *
+     * @return Base URL for this DOM tree.
+     */
+    public String getSystemId() {
+        return this.systemID;
+    }
+}
diff --git a/javax/xml/transform/sax/SAXResult.java b/javax/xml/transform/sax/SAXResult.java
new file mode 100644
index 0000000..dbb30bd
--- /dev/null
+++ b/javax/xml/transform/sax/SAXResult.java
@@ -0,0 +1,137 @@
+/*
+ * 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.
+ */
+
+// $Id: SAXResult.java 446598 2006-09-15 12:55:40Z jeremias $
+
+package javax.xml.transform.sax;
+
+import javax.xml.transform.Result;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.ext.LexicalHandler;
+
+/**
+ * <p>Acts as an holder for a transformation Result.</p>
+ *
+ * @author <a href="[email protected]">Jeff Suttor</a>
+ */
+public class SAXResult implements Result {
+
+    /**
+     * If {@link javax.xml.transform.TransformerFactory#getFeature}
+     * returns true when passed this value as an argument,
+     * the Transformer supports Result output of this type.
+     */
+    public static final String FEATURE =
+        "http://javax.xml.transform.sax.SAXResult/feature";
+
+    /**
+     * Zero-argument default constructor.
+     */
+    public SAXResult() {
+    }
+
+    /**
+     * Create a SAXResult that targets a SAX2 {@link org.xml.sax.ContentHandler}.
+     *
+     * @param handler Must be a non-null ContentHandler reference.
+     */
+    public SAXResult(ContentHandler handler) {
+        setHandler(handler);
+    }
+
+    /**
+     * Set the target to be a SAX2 {@link org.xml.sax.ContentHandler}.
+     *
+     * @param handler Must be a non-null ContentHandler reference.
+     */
+    public void setHandler(ContentHandler handler) {
+        this.handler = handler;
+    }
+
+    /**
+     * Get the {@link org.xml.sax.ContentHandler} that is the Result.
+     *
+     * @return The ContentHandler that is to be transformation output.
+     */
+    public ContentHandler getHandler() {
+        return handler;
+    }
+
+    /**
+     * Set the SAX2 {@link org.xml.sax.ext.LexicalHandler} for the output.
+     *
+     * <p>This is needed to handle XML comments and the like.  If the
+     * lexical handler is not set, an attempt should be made by the
+     * transformer to cast the {@link org.xml.sax.ContentHandler} to a
+     * <code>LexicalHandler</code>.</p>
+     *
+     * @param handler A non-null <code>LexicalHandler</code> for
+     * handling lexical parse events.
+     */
+    public void setLexicalHandler(LexicalHandler handler) {
+        this.lexhandler = handler;
+    }
+
+    /**
+     * Get a SAX2 {@link org.xml.sax.ext.LexicalHandler} for the output.
+     *
+     * @return A <code>LexicalHandler</code>, or null.
+     */
+    public LexicalHandler getLexicalHandler() {
+        return lexhandler;
+    }
+
+    /**
+     * Method setSystemId Set the systemID that may be used in association
+     * with the {@link org.xml.sax.ContentHandler}.
+     *
+     * @param systemId The system identifier as a URI string.
+     */
+    public void setSystemId(String systemId) {
+        this.systemId = systemId;
+    }
+
+    /**
+     * Get the system identifier that was set with setSystemId.
+     *
+     * @return The system identifier that was set with setSystemId, or null
+     * if setSystemId was not called.
+     */
+    public String getSystemId() {
+        return systemId;
+    }
+
+    //////////////////////////////////////////////////////////////////////
+    // Internal state.
+    //////////////////////////////////////////////////////////////////////
+
+    /**
+     * The handler for parse events.
+     */
+    private ContentHandler handler;
+
+    /**
+     * The handler for lexical events.
+     */
+    private LexicalHandler lexhandler;
+
+    /**
+     * The systemID that may be used in association
+     * with the node.
+     */
+    private String systemId;
+}
diff --git a/javax/xml/transform/sax/SAXSource.java b/javax/xml/transform/sax/SAXSource.java
new file mode 100644
index 0000000..c1c1995
--- /dev/null
+++ b/javax/xml/transform/sax/SAXSource.java
@@ -0,0 +1,204 @@
+/*
+ * 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.
+ */
+
+// $Id: SAXSource.java 446598 2006-09-15 12:55:40Z jeremias $
+
+package javax.xml.transform.sax;
+
+import javax.xml.transform.Source;
+import javax.xml.transform.stream.StreamSource;
+import org.xml.sax.InputSource;
+import org.xml.sax.XMLReader;
+
+/**
+ * <p>Acts as an holder for SAX-style Source.</p>
+ *
+ * <p>Note that XSLT requires namespace support. Attempting to transform an
+ * input source that is not
+ * generated with a namespace-aware parser may result in errors.
+ * Parsers can be made namespace aware by calling the
+ * {@link javax.xml.parsers.SAXParserFactory#setNamespaceAware(boolean awareness)} method.</p>
+ *
+ * @author <a href="mailto:[email protected]">Jeff Suttor</a>
+ * @version $Revision: 446598 $, $Date: 2006-09-15 05:55:40 -0700 (Fri, 15 Sep 2006) $
+ */
+public class SAXSource implements Source {
+
+    /**
+     * If {@link javax.xml.transform.TransformerFactory#getFeature}
+     * returns true when passed this value as an argument,
+     * the Transformer supports Source input of this type.
+     */
+    public static final String FEATURE =
+        "http://javax.xml.transform.sax.SAXSource/feature";
+
+    /**
+     * <p>Zero-argument default constructor.  If this constructor is used, and
+     * no SAX source is set using
+     * {@link #setInputSource(InputSource inputSource)} , then the
+     * <code>Transformer</code> will
+     * create an empty source {@link org.xml.sax.InputSource} using
+     * {@link org.xml.sax.InputSource#InputSource() new InputSource()}.</p>
+     *
+     * @see javax.xml.transform.Transformer#transform(Source xmlSource, Result outputTarget)
+     */
+    public SAXSource() { }
+
+    /**
+     * Create a <code>SAXSource</code>, using an {@link org.xml.sax.XMLReader}
+     * and a SAX InputSource. The {@link javax.xml.transform.Transformer}
+     * or {@link javax.xml.transform.sax.SAXTransformerFactory} will set itself
+     * to be the reader's {@link org.xml.sax.ContentHandler}, and then will call
+     * reader.parse(inputSource).
+     *
+     * @param reader An XMLReader to be used for the parse.
+     * @param inputSource A SAX input source reference that must be non-null
+     * and that will be passed to the reader parse method.
+     */
+    public SAXSource(XMLReader reader, InputSource inputSource) {
+        this.reader      = reader;
+        this.inputSource = inputSource;
+    }
+
+    /**
+     * Create a <code>SAXSource</code>, using a SAX <code>InputSource</code>.
+     * The {@link javax.xml.transform.Transformer} or
+     * {@link javax.xml.transform.sax.SAXTransformerFactory} creates a
+     * reader via {@link org.xml.sax.helpers.XMLReaderFactory}
+     * (if setXMLReader is not used), sets itself as
+     * the reader's {@link org.xml.sax.ContentHandler}, and calls
+     * reader.parse(inputSource).
+     *
+     * @param inputSource An input source reference that must be non-null
+     * and that will be passed to the parse method of the reader.
+     */
+    public SAXSource(InputSource inputSource) {
+        this.inputSource = inputSource;
+    }
+
+    /**
+     * Set the XMLReader to be used for the Source.
+     *
+     * @param reader A valid XMLReader or XMLFilter reference.
+     */
+    public void setXMLReader(XMLReader reader) {
+        this.reader = reader;
+    }
+
+    /**
+     * Get the XMLReader to be used for the Source.
+     *
+     * @return A valid XMLReader or XMLFilter reference, or null.
+     */
+    public XMLReader getXMLReader() {
+        return reader;
+    }
+
+    /**
+     * Set the SAX InputSource to be used for the Source.
+     *
+     * @param inputSource A valid InputSource reference.
+     */
+    public void setInputSource(InputSource inputSource) {
+        this.inputSource = inputSource;
+    }
+
+    /**
+     * Get the SAX InputSource to be used for the Source.
+     *
+     * @return A valid InputSource reference, or null.
+     */
+    public InputSource getInputSource() {
+        return inputSource;
+    }
+
+    /**
+     * Set the system identifier for this Source.  If an input source
+     * has already been set, it will set the system ID or that
+     * input source, otherwise it will create a new input source.
+     *
+     * <p>The system identifier is optional if there is a byte stream
+     * or a character stream, but it is still useful to provide one,
+     * since the application can use it to resolve relative URIs
+     * and can include it in error messages and warnings (the parser
+     * will attempt to open a connection to the URI only if
+     * no byte stream or character stream is specified).</p>
+     *
+     * @param systemId The system identifier as a URI string.
+     */
+    public void setSystemId(String systemId) {
+
+        if (null == inputSource) {
+            inputSource = new InputSource(systemId);
+        } else {
+            inputSource.setSystemId(systemId);
+        }
+    }
+
+    /**
+     * <p>Get the base ID (URI or system ID) from where URIs
+     * will be resolved.</p>
+     *
+     * @return Base URL for the <code>Source</code>, or <code>null</code>.
+     */
+    public String getSystemId() {
+
+        if (inputSource == null) {
+            return null;
+        } else {
+            return inputSource.getSystemId();
+        }
+    }
+
+    /**
+     * The XMLReader to be used for the source tree input. May be null.
+     */
+    private XMLReader reader;
+
+    /**
+     * <p>The SAX InputSource to be used for the source tree input.
+     * Should not be <code>null<code>.</p>
+     */
+    private InputSource inputSource;
+
+    /**
+     * Attempt to obtain a SAX InputSource object from a Source
+     * object.
+     *
+     * @param source Must be a non-null Source reference.
+     *
+     * @return An InputSource, or null if Source can not be converted.
+     */
+    public static InputSource sourceToInputSource(Source source) {
+
+        if (source instanceof SAXSource) {
+            return ((SAXSource) source).getInputSource();
+        } else if (source instanceof StreamSource) {
+            StreamSource ss      = (StreamSource) source;
+            InputSource  isource = new InputSource(ss.getSystemId());
+
+            isource.setByteStream(ss.getInputStream());
+            isource.setCharacterStream(ss.getReader());
+            isource.setPublicId(ss.getPublicId());
+
+            return isource;
+        } else {
+            return null;
+        }
+    }
+}
+
diff --git a/javax/xml/transform/sax/SAXTransformerFactory.java b/javax/xml/transform/sax/SAXTransformerFactory.java
new file mode 100644
index 0000000..ff62d3a
--- /dev/null
+++ b/javax/xml/transform/sax/SAXTransformerFactory.java
@@ -0,0 +1,146 @@
+/*
+ * 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.
+ */
+
+// $Id: SAXTransformerFactory.java 446598 2006-09-15 12:55:40Z jeremias $
+
+package javax.xml.transform.sax;
+
+import javax.xml.transform.Source;
+import javax.xml.transform.Templates;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerFactory;
+import org.xml.sax.XMLFilter;
+
+/**
+ * This class extends TransformerFactory to provide SAX-specific
+ * factory methods.  It provides two types of ContentHandlers,
+ * one for creating Transformers, the other for creating Templates
+ * objects.
+ *
+ * <p>If an application wants to set the ErrorHandler or EntityResolver
+ * for an XMLReader used during a transformation, it should use a URIResolver
+ * to return the SAXSource which provides (with getXMLReader) a reference to
+ * the XMLReader.</p>
+ */
+public abstract class SAXTransformerFactory extends TransformerFactory {
+
+    /** If {@link javax.xml.transform.TransformerFactory#getFeature}
+     * returns true when passed this value as an argument,
+     * the TransformerFactory returned from
+     * {@link javax.xml.transform.TransformerFactory#newInstance} may
+     * be safely cast to a SAXTransformerFactory.
+     */
+    public static final String FEATURE =
+        "http://javax.xml.transform.sax.SAXTransformerFactory/feature";
+
+    /** If {@link javax.xml.transform.TransformerFactory#getFeature}
+     * returns true when passed this value as an argument,
+     * the {@link #newXMLFilter(Source src)}
+     * and {@link #newXMLFilter(Templates templates)} methods are supported.
+     */
+    public static final String FEATURE_XMLFILTER =
+        "http://javax.xml.transform.sax.SAXTransformerFactory/feature/xmlfilter";
+
+    /**
+     * The default constructor is protected on purpose.
+     */
+    protected SAXTransformerFactory() {}
+
+    /**
+     * Get a TransformerHandler object that can process SAX
+     * ContentHandler events into a Result, based on the transformation
+     * instructions specified by the argument.
+     *
+     * @param src The Source of the transformation instructions.
+     *
+     * @return TransformerHandler ready to transform SAX events.
+     *
+     * @throws TransformerConfigurationException If for some reason the
+     * TransformerHandler can not be created.
+     */
+    public abstract TransformerHandler newTransformerHandler(Source src)
+        throws TransformerConfigurationException;
+
+    /**
+     * Get a TransformerHandler object that can process SAX
+     * ContentHandler events into a Result, based on the Templates argument.
+     *
+     * @param templates The compiled transformation instructions.
+     *
+     * @return TransformerHandler ready to transform SAX events.
+     *
+     * @throws TransformerConfigurationException If for some reason the
+     * TransformerHandler can not be created.
+     */
+    public abstract TransformerHandler newTransformerHandler(
+        Templates templates) throws TransformerConfigurationException;
+
+    /**
+     * Get a TransformerHandler object that can process SAX
+     * ContentHandler events into a Result. The transformation
+     * is defined as an identity (or copy) transformation, for example
+     * to copy a series of SAX parse events into a DOM tree.
+     *
+     * @return A non-null reference to a TransformerHandler, that may
+     * be used as a ContentHandler for SAX parse events.
+     *
+     * @throws TransformerConfigurationException If for some reason the
+     * TransformerHandler cannot be created.
+     */
+    public abstract TransformerHandler newTransformerHandler()
+        throws TransformerConfigurationException;
+
+    /**
+     * Get a TemplatesHandler object that can process SAX
+     * ContentHandler events into a Templates object.
+     *
+     * @return A non-null reference to a TransformerHandler, that may
+     * be used as a ContentHandler for SAX parse events.
+     *
+     * @throws TransformerConfigurationException If for some reason the
+     * TemplatesHandler cannot be created.
+     */
+    public abstract TemplatesHandler newTemplatesHandler()
+        throws TransformerConfigurationException;
+
+    /**
+     * Create an XMLFilter that uses the given Source as the
+     * transformation instructions.
+     *
+     * @param src The Source of the transformation instructions.
+     *
+     * @return An XMLFilter object, or null if this feature is not supported.
+     *
+     * @throws TransformerConfigurationException If for some reason the
+     * TemplatesHandler cannot be created.
+     */
+    public abstract XMLFilter newXMLFilter(Source src)
+        throws TransformerConfigurationException;
+
+    /**
+     * Create an XMLFilter, based on the Templates argument..
+     *
+     * @param templates The compiled transformation instructions.
+     *
+     * @return An XMLFilter object, or null if this feature is not supported.
+     *
+     * @throws TransformerConfigurationException If for some reason the
+     * TemplatesHandler cannot be created.
+     */
+    public abstract XMLFilter newXMLFilter(Templates templates)
+        throws TransformerConfigurationException;
+}
diff --git a/javax/xml/transform/sax/TemplatesHandler.java b/javax/xml/transform/sax/TemplatesHandler.java
new file mode 100644
index 0000000..f09ef6f
--- /dev/null
+++ b/javax/xml/transform/sax/TemplatesHandler.java
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+// $Id: TemplatesHandler.java 446598 2006-09-15 12:55:40Z jeremias $
+
+package javax.xml.transform.sax;
+
+import javax.xml.transform.Templates;
+import org.xml.sax.ContentHandler;
+
+/**
+ * A SAX ContentHandler that may be used to process SAX
+ * parse events (parsing transformation instructions) into a Templates object.
+ *
+ * <p>Note that TemplatesHandler does not need to implement LexicalHandler.</p>
+ */
+public interface TemplatesHandler extends ContentHandler {
+
+    /**
+     * When a TemplatesHandler object is used as a ContentHandler
+     * for the parsing of transformation instructions, it creates a Templates object,
+     * which the caller can get once the SAX events have been completed.
+     *
+     * @return The Templates object that was created during
+     * the SAX event process, or null if no Templates object has
+     * been created.
+     *
+     */
+    public Templates getTemplates();
+
+    /**
+     * Set the base ID (URI or system ID) for the Templates object
+     * created by this builder.  This must be set in order to
+     * resolve relative URIs in the stylesheet.  This must be
+     * called before the startDocument event.
+     *
+     * @param systemID Base URI for this stylesheet.
+     */
+    public void setSystemId(String systemID);
+
+    /**
+     * Get the base ID (URI or system ID) from where relative
+     * URLs will be resolved.
+     * @return The systemID that was set with {@link #setSystemId}.
+     */
+    public String getSystemId();
+}
diff --git a/javax/xml/transform/sax/TransformerHandler.java b/javax/xml/transform/sax/TransformerHandler.java
new file mode 100644
index 0000000..7843745
--- /dev/null
+++ b/javax/xml/transform/sax/TransformerHandler.java
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+// $Id: TransformerHandler.java 446598 2006-09-15 12:55:40Z jeremias $
+
+package javax.xml.transform.sax;
+
+import javax.xml.transform.Result;
+import javax.xml.transform.Transformer;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.DTDHandler;
+import org.xml.sax.ext.LexicalHandler;
+
+/**
+ * A TransformerHandler
+ * listens for SAX ContentHandler parse events and transforms
+ * them to a Result.
+ */
+public interface TransformerHandler
+    extends ContentHandler, LexicalHandler, DTDHandler {
+
+    /**
+     * <p>Set  the <code>Result</code> associated with this
+     * <code>TransformerHandler</code> to be used for the transformation.</p>
+     *
+     * @param result A <code>Result</code> instance, should not be
+     *   <code>null</code>.
+     *
+     * @throws IllegalArgumentException if result is invalid for some reason.
+     */
+    public void setResult(Result result) throws IllegalArgumentException;
+
+    /**
+     * Set the base ID (URI or system ID) from where relative
+     * URLs will be resolved.
+     * @param systemID Base URI for the source tree.
+     */
+    public void setSystemId(String systemID);
+
+    /**
+     * Get the base ID (URI or system ID) from where relative
+     * URLs will be resolved.
+     * @return The systemID that was set with {@link #setSystemId}.
+     */
+    public String getSystemId();
+
+    /**
+     * <p>Get the <code>Transformer</code> associated with this handler, which
+     * is needed in order to set parameters and output properties.</p>
+     *
+     * @return <code>Transformer</code> associated with this
+     *   <code>TransformerHandler</code>.
+     */
+    public Transformer getTransformer();
+}
diff --git a/javax/xml/transform/stream/FilePathToURI.java b/javax/xml/transform/stream/FilePathToURI.java
new file mode 100644
index 0000000..f92b8f2
--- /dev/null
+++ b/javax/xml/transform/stream/FilePathToURI.java
@@ -0,0 +1,129 @@
+/*
+ * 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 javax.xml.transform.stream;
+
+class FilePathToURI {
+
+    // which ASCII characters need to be escaped
+    private static boolean gNeedEscaping[] = new boolean[128];
+    // the first hex character if a character needs to be escaped
+    private static char[] gAfterEscaping1 = new char[128];
+    // the second hex character if a character needs to be escaped
+    private static char[] gAfterEscaping2 = new char[128];
+    private static char[] gHexChs = {'0', '1', '2', '3', '4', '5', '6', '7',
+                                     '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+    // initialize the above 3 arrays
+    static {
+        for (int i = 0; i <= 0x1f; i++) {
+            gNeedEscaping[i] = true;
+            gAfterEscaping1[i] = gHexChs[i >> 4];
+            gAfterEscaping2[i] = gHexChs[i & 0xf];
+        }
+        gNeedEscaping[0x7f] = true;
+        gAfterEscaping1[0x7f] = '7';
+        gAfterEscaping2[0x7f] = 'F';
+        char[] escChs = {' ', '<', '>', '#', '%', '"', '{', '}',
+                         '|', '\\', '^', '~', '[', ']', '`'};
+        int len = escChs.length;
+        char ch;
+        for (int i = 0; i < len; i++) {
+            ch = escChs[i];
+            gNeedEscaping[ch] = true;
+            gAfterEscaping1[ch] = gHexChs[ch >> 4];
+            gAfterEscaping2[ch] = gHexChs[ch & 0xf];
+        }
+    }
+
+    // To escape a file path to a URI, by using %HH to represent
+    // special ASCII characters: 0x00~0x1F, 0x7F, ' ', '<', '>', '#', '%'
+    // and '"' and non-ASCII characters (whose value >= 128).
+    public static String filepath2URI(String path){
+        // return null if path is null.
+        if (path == null)
+            return null;
+
+        char separator = java.io.File.separatorChar;
+        path = path.replace(separator, '/');
+
+        int len = path.length(), ch;
+        StringBuilder buffer = new StringBuilder(len*3);
+        buffer.append("file://");
+        // change C:/blah to /C:/blah
+        if (len >= 2 && path.charAt(1) == ':') {
+            ch = Character.toUpperCase(path.charAt(0));
+            if (ch >= 'A' && ch <= 'Z') {
+                buffer.append('/');
+            }
+        }
+
+        // for each character in the path
+        int i = 0;
+        for (; i < len; i++) {
+            ch = path.charAt(i);
+            // if it's not an ASCII character, break here, and use UTF-8 encoding
+            if (ch >= 128)
+                break;
+            if (gNeedEscaping[ch]) {
+                buffer.append('%');
+                buffer.append(gAfterEscaping1[ch]);
+                buffer.append(gAfterEscaping2[ch]);
+                // record the fact that it's escaped
+            }
+            else {
+                buffer.append((char)ch);
+            }
+        }
+
+        // we saw some non-ascii character
+        if (i < len) {
+            // get UTF-8 bytes for the remaining sub-string
+            byte[] bytes = null;
+            byte b;
+            try {
+                bytes = path.substring(i).getBytes("UTF-8");
+            } catch (java.io.UnsupportedEncodingException e) {
+                // should never happen
+                return path;
+            }
+            len = bytes.length;
+
+            // for each byte
+            for (i = 0; i < len; i++) {
+                b = bytes[i];
+                // for non-ascii character: make it positive, then escape
+                if (b < 0) {
+                    ch = b + 256;
+                    buffer.append('%');
+                    buffer.append(gHexChs[ch >> 4]);
+                    buffer.append(gHexChs[ch & 0xf]);
+                }
+                else if (gNeedEscaping[b]) {
+                    buffer.append('%');
+                    buffer.append(gAfterEscaping1[b]);
+                    buffer.append(gAfterEscaping2[b]);
+                }
+                else {
+                    buffer.append((char)b);
+                }
+            }
+        }
+
+        return buffer.toString();
+    }
+
+}//FilePathToURI
diff --git a/javax/xml/transform/stream/StreamResult.java b/javax/xml/transform/stream/StreamResult.java
new file mode 100644
index 0000000..58568aa
--- /dev/null
+++ b/javax/xml/transform/stream/StreamResult.java
@@ -0,0 +1,194 @@
+/*
+ * 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.
+ */
+
+// $Id: StreamResult.java 829970 2009-10-26 21:15:29Z mrglavas $
+
+package javax.xml.transform.stream;
+
+import java.io.File;
+import java.io.OutputStream;
+import java.io.Writer;
+import javax.xml.transform.Result;
+
+/**
+ * <p>Acts as an holder for a transformation result,
+ * which may be XML, plain Text, HTML, or some other form of markup.</p>
+ *
+ * @author <a href="[email protected]">Jeff Suttor</a>
+ */
+public class StreamResult implements Result {
+
+    /** If {@link javax.xml.transform.TransformerFactory#getFeature}
+     * returns true when passed this value as an argument,
+     * the Transformer supports Result output of this type.
+     */
+    public static final String FEATURE =
+        "http://javax.xml.transform.stream.StreamResult/feature";
+
+    /**
+     * Zero-argument default constructor.
+     */
+    public StreamResult() {
+    }
+
+    /**
+     * Construct a StreamResult from a byte stream.  Normally,
+     * a stream should be used rather than a reader, so that
+     * the transformer may use instructions contained in the
+     * transformation instructions to control the encoding.
+     *
+     * @param outputStream A valid OutputStream reference.
+     */
+    public StreamResult(OutputStream outputStream) {
+        setOutputStream(outputStream);
+    }
+
+    /**
+     * Construct a StreamResult from a character stream.  Normally,
+     * a stream should be used rather than a reader, so that
+     * the transformer may use instructions contained in the
+     * transformation instructions to control the encoding.  However,
+     * there are times when it is useful to write to a character
+     * stream, such as when using a StringWriter.
+     *
+     * @param writer  A valid Writer reference.
+     */
+    public StreamResult(Writer writer) {
+        setWriter(writer);
+    }
+
+    /**
+     * Construct a StreamResult from a URL.
+     *
+     * @param systemId Must be a String that conforms to the URI syntax.
+     */
+    public StreamResult(String systemId) {
+        this.systemId = systemId;
+    }
+
+    /**
+     * Construct a StreamResult from a File.
+     *
+     * @param f Must a non-null File reference.
+     */
+    public StreamResult(File f) {
+        setSystemId(f);
+    }
+
+    /**
+     * Set the ByteStream that is to be written to.  Normally,
+     * a stream should be used rather than a reader, so that
+     * the transformer may use instructions contained in the
+     * transformation instructions to control the encoding.
+     *
+     * @param outputStream A valid OutputStream reference.
+     */
+    public void setOutputStream(OutputStream outputStream) {
+        this.outputStream = outputStream;
+    }
+
+    /**
+     * Get the byte stream that was set with setOutputStream.
+     *
+     * @return The byte stream that was set with setOutputStream, or null
+     * if setOutputStream or the ByteStream constructor was not called.
+     */
+    public OutputStream getOutputStream() {
+        return outputStream;
+    }
+
+    /**
+     * Set the writer that is to receive the result.  Normally,
+     * a stream should be used rather than a writer, so that
+     * the transformer may use instructions contained in the
+     * transformation instructions to control the encoding.  However,
+     * there are times when it is useful to write to a writer,
+     * such as when using a StringWriter.
+     *
+     * @param writer  A valid Writer reference.
+     */
+    public void setWriter(Writer writer) {
+        this.writer = writer;
+    }
+
+    /**
+     * Get the character stream that was set with setWriter.
+     *
+     * @return The character stream that was set with setWriter, or null
+     * if setWriter or the Writer constructor was not called.
+     */
+    public Writer getWriter() {
+        return writer;
+    }
+
+    /**
+     * Set the systemID that may be used in association
+     * with the byte or character stream, or, if neither is set, use
+     * this value as a writeable URI (probably a file name).
+     *
+     * @param systemId The system identifier as a URI string.
+     */
+    public void setSystemId(String systemId) {
+        this.systemId = systemId;
+    }
+
+    /**
+     * <p>Set the system ID from a <code>File</code> reference.</p>
+     *
+     * <p>Note the use of {@link File#toURI()} and {@link File#toURL()}.
+     * <code>toURI()</code> is preferred and used if possible.
+     * To allow JAXP 1.3 to run on J2SE 1.3, <code>toURL()</code>
+     * is used if a {@link NoSuchMethodException} is thrown by the attempt
+     * to use <code>toURI()</code>.</p>
+     *
+     * @param f Must a non-null File reference.
+     */
+    public void setSystemId(File f) {
+        this.systemId = FilePathToURI.filepath2URI(f.getAbsolutePath());
+    }
+
+    /**
+     * Get the system identifier that was set with setSystemId.
+     *
+     * @return The system identifier that was set with setSystemId, or null
+     * if setSystemId was not called.
+     */
+    public String getSystemId() {
+        return systemId;
+    }
+
+    //////////////////////////////////////////////////////////////////////
+    // Internal state.
+    //////////////////////////////////////////////////////////////////////
+
+    /**
+     * The systemID that may be used in association
+     * with the byte or character stream, or, if neither is set, use
+     * this value as a writeable URI (probably a file name).
+     */
+    private String systemId;
+
+    /**
+     * The byte stream that is to be written to.
+     */
+    private OutputStream outputStream;
+
+    /**
+     * The character stream that is to be written to.
+     */
+    private Writer writer;
+}
diff --git a/javax/xml/transform/stream/StreamSource.java b/javax/xml/transform/stream/StreamSource.java
new file mode 100644
index 0000000..0d96cc0
--- /dev/null
+++ b/javax/xml/transform/stream/StreamSource.java
@@ -0,0 +1,272 @@
+/*
+ * 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.
+ */
+
+// $Id: StreamSource.java 829971 2009-10-26 21:15:39Z mrglavas $
+
+package javax.xml.transform.stream;
+
+import java.io.File;
+import java.io.InputStream;
+import java.io.Reader;
+import javax.xml.transform.Source;
+
+/**
+ * <p>Acts as an holder for a transformation Source in the form
+ * of a stream of XML markup.</p>
+ *
+ * <p><em>Note:</em> Due to their internal use of either a {@link Reader} or {@link InputStream} instance,
+ * <code>StreamSource</code> instances may only be used once.</p>
+ *
+ * @author <a href="[email protected]">Jeff Suttor</a>
+ * @version $Revision: 829971 $, $Date: 2009-10-26 14:15:39 -0700 (Mon, 26 Oct 2009) $
+ */
+public class StreamSource implements Source {
+
+    /** If {@link javax.xml.transform.TransformerFactory#getFeature}
+     * returns true when passed this value as an argument,
+     * the Transformer supports Source input of this type.
+     */
+    public static final String FEATURE =
+        "http://javax.xml.transform.stream.StreamSource/feature";
+
+    /**
+     * <p>Zero-argument default constructor.  If this constructor is used, and
+     * no Stream source is set using
+     * {@link #setInputStream(java.io.InputStream inputStream)} or
+     * {@link #setReader(java.io.Reader reader)}, then the
+     * <code>Transformer</code> will
+     * create an empty source {@link java.io.InputStream} using
+     * {@link java.io.InputStream#InputStream() new InputStream()}.</p>
+     *
+     * @see javax.xml.transform.Transformer#transform(Source xmlSource, Result outputTarget)
+     */
+    public StreamSource() { }
+
+    /**
+     * Construct a StreamSource from a byte stream.  Normally,
+     * a stream should be used rather than a reader, so
+     * the XML parser can resolve character encoding specified
+     * by the XML declaration.
+     *
+     * <p>If this constructor is used to process a stylesheet, normally
+     * setSystemId should also be called, so that relative URI references
+     * can be resolved.</p>
+     *
+     * @param inputStream A valid InputStream reference to an XML stream.
+     */
+    public StreamSource(InputStream inputStream) {
+        setInputStream(inputStream);
+    }
+
+    /**
+     * Construct a StreamSource from a byte stream.  Normally,
+     * a stream should be used rather than a reader, so that
+     * the XML parser can resolve character encoding specified
+     * by the XML declaration.
+     *
+     * <p>This constructor allows the systemID to be set in addition
+     * to the input stream, which allows relative URIs
+     * to be processed.</p>
+     *
+     * @param inputStream A valid InputStream reference to an XML stream.
+     * @param systemId Must be a String that conforms to the URI syntax.
+     */
+    public StreamSource(InputStream inputStream, String systemId) {
+        setInputStream(inputStream);
+        setSystemId(systemId);
+    }
+
+    /**
+     * Construct a StreamSource from a character reader.  Normally,
+     * a stream should be used rather than a reader, so that
+     * the XML parser can resolve character encoding specified
+     * by the XML declaration.  However, in many cases the encoding
+     * of the input stream is already resolved, as in the case of
+     * reading XML from a StringReader.
+     *
+     * @param reader A valid Reader reference to an XML character stream.
+     */
+    public StreamSource(Reader reader) {
+        setReader(reader);
+    }
+
+    /**
+     * Construct a StreamSource from a character reader.  Normally,
+     * a stream should be used rather than a reader, so that
+     * the XML parser may resolve character encoding specified
+     * by the XML declaration.  However, in many cases the encoding
+     * of the input stream is already resolved, as in the case of
+     * reading XML from a StringReader.
+     *
+     * @param reader A valid Reader reference to an XML character stream.
+     * @param systemId Must be a String that conforms to the URI syntax.
+     */
+    public StreamSource(Reader reader, String systemId) {
+        setReader(reader);
+        setSystemId(systemId);
+    }
+
+    /**
+     * Construct a StreamSource from a URL.
+     *
+     * @param systemId Must be a String that conforms to the URI syntax.
+     */
+    public StreamSource(String systemId) {
+        this.systemId = systemId;
+    }
+
+    /**
+     * Construct a StreamSource from a File.
+     *
+     * @param f Must a non-null File reference.
+     */
+    public StreamSource(File f) {
+        setSystemId(f);
+    }
+
+    /**
+     * Set the byte stream to be used as input.  Normally,
+     * a stream should be used rather than a reader, so that
+     * the XML parser can resolve character encoding specified
+     * by the XML declaration.
+     *
+     * <p>If this Source object is used to process a stylesheet, normally
+     * setSystemId should also be called, so that relative URL references
+     * can be resolved.</p>
+     *
+     * @param inputStream A valid InputStream reference to an XML stream.
+     */
+    public void setInputStream(InputStream inputStream) {
+        this.inputStream = inputStream;
+    }
+
+    /**
+     * Get the byte stream that was set with setByteStream.
+     *
+     * @return The byte stream that was set with setByteStream, or null
+     * if setByteStream or the ByteStream constructor was not called.
+     */
+    public InputStream getInputStream() {
+        return inputStream;
+    }
+
+    /**
+     * Set the input to be a character reader.  Normally,
+     * a stream should be used rather than a reader, so that
+     * the XML parser can resolve character encoding specified
+     * by the XML declaration.  However, in many cases the encoding
+     * of the input stream is already resolved, as in the case of
+     * reading XML from a StringReader.
+     *
+     * @param reader A valid Reader reference to an XML CharacterStream.
+     */
+    public void setReader(Reader reader) {
+        this.reader = reader;
+    }
+
+    /**
+     * Get the character stream that was set with setReader.
+     *
+     * @return The character stream that was set with setReader, or null
+     * if setReader or the Reader constructor was not called.
+     */
+    public Reader getReader() {
+        return reader;
+    }
+
+    /**
+     * Set the public identifier for this Source.
+     *
+     * <p>The public identifier is always optional: if the application
+     * writer includes one, it will be provided as part of the
+     * location information.</p>
+     *
+     * @param publicId The public identifier as a string.
+     */
+    public void setPublicId(String publicId) {
+        this.publicId = publicId;
+    }
+
+    /**
+     * Get the public identifier that was set with setPublicId.
+     *
+     * @return The public identifier that was set with setPublicId, or null
+     * if setPublicId was not called.
+     */
+    public String getPublicId() {
+        return publicId;
+    }
+
+    /**
+     * Set the system identifier for this Source.
+     *
+     * <p>The system identifier is optional if there is a byte stream
+     * or a character stream, but it is still useful to provide one,
+     * since the application can use it to resolve relative URIs
+     * and can include it in error messages and warnings (the parser
+     * will attempt to open a connection to the URI only if
+     * there is no byte stream or character stream specified).</p>
+     *
+     * @param systemId The system identifier as a URL string.
+     */
+    public void setSystemId(String systemId) {
+        this.systemId = systemId;
+    }
+
+    /**
+     * Get the system identifier that was set with setSystemId.
+     *
+     * @return The system identifier that was set with setSystemId, or null
+     * if setSystemId was not called.
+     */
+    public String getSystemId() {
+        return systemId;
+    }
+
+    /**
+     * Set the system ID from a File reference.
+     *
+     * @param f Must a non-null File reference.
+     */
+    public void setSystemId(File f) {
+        this.systemId = FilePathToURI.filepath2URI(f.getAbsolutePath());
+    }
+
+    //////////////////////////////////////////////////////////////////////
+    // Internal state.
+    //////////////////////////////////////////////////////////////////////
+
+    /**
+     * The public identifier for this input source, or null.
+     */
+    private String publicId;
+
+    /**
+     * The system identifier as a URL string, or null.
+     */
+    private String systemId;
+
+    /**
+     * The byte stream for this Source, or null.
+     */
+    private InputStream inputStream;
+
+    /**
+     * The character stream for this Source, or null.
+     */
+    private Reader reader;
+}
diff --git a/javax/xml/validation/Schema.java b/javax/xml/validation/Schema.java
new file mode 100644
index 0000000..3dd4ba4
--- /dev/null
+++ b/javax/xml/validation/Schema.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.
+ */
+
+// $Id: Schema.java 446598 2006-09-15 12:55:40Z jeremias $
+
+package javax.xml.validation;
+
+/**
+ * Immutable in-memory representation of grammar.
+ *
+ * <p>
+ * This object represents a set of constraints that can be checked/
+ * enforced against an XML document.
+ *
+ * <p>
+ * A {@link Schema} object is thread safe and applications are
+ * encouraged to share it across many parsers in many threads.
+ *
+ * <p>
+ * A {@link Schema} object is immutable in the sense that it shouldn't
+ * change the set of constraints once it is created. In other words,
+ * if an application validates the same document twice against the same
+ * {@link Schema}, it must always produce the same result.
+ *
+ * <p>
+ * A {@link Schema} object is usually created from {@link SchemaFactory}.
+ *
+ * <p>
+ * Two kinds of validators can be created from a {@link Schema} object.
+ * One is {@link Validator}, which provides highly-level validation
+ * operations that cover typical use cases. The other is
+ * {@link ValidatorHandler}, which works on top of SAX for better
+ * modularity.
+ *
+ * <p>
+ * This specification does not refine
+ * the {@link java.lang.Object#equals(java.lang.Object)} method.
+ * In other words, if you parse the same schema twice, you may
+ * still get <code>!schemaA.equals(schemaB)</code>.
+ *
+ * @author <a href="mailto:[email protected]">Kohsuke Kawaguchi</a>
+ * @version $Revision: 446598 $, $Date: 2006-09-15 05:55:40 -0700 (Fri, 15 Sep 2006) $
+ * @see <a href="http://www.w3.org/TR/xmlschema-1/">XML Schema Part 1: Structures</a>
+ * @see <a href="http://www.w3.org/TR/xml11/">Extensible Markup Language (XML) 1.1</a>
+ * @see <a href="http://www.w3.org/TR/REC-xml">Extensible Markup Language (XML) 1.0 (Second Edition)</a>
+ * @since 1.5
+ */
+public abstract class Schema {
+
+    /**
+     * Constructor for the derived class.
+     *
+     * <p>
+     * The constructor does nothing.
+     */
+    protected Schema() {
+    }
+
+    /**
+     * Creates a new {@link Validator} for this {@link Schema}.
+     *
+     * <p>
+     * A validator enforces/checks the set of constraints this object
+     * represents.
+     *
+     * @return
+     *      Always return a non-null valid object.
+     */
+    public abstract Validator newValidator();
+
+    /**
+     * Creates a new {@link ValidatorHandler} for this {@link Schema}.
+     *
+     * @return
+     *      Always return a non-null valid object.
+     */
+    public abstract ValidatorHandler newValidatorHandler();
+}
diff --git a/javax/xml/validation/SchemaFactory.java b/javax/xml/validation/SchemaFactory.java
new file mode 100644
index 0000000..2018067
--- /dev/null
+++ b/javax/xml/validation/SchemaFactory.java
@@ -0,0 +1,674 @@
+/*
+ * 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.
+ */
+
+// $Id: SchemaFactory.java 884952 2009-11-27 18:55:08Z mrglavas $
+
+package javax.xml.validation;
+
+import java.io.File;
+import java.net.URL;
+import javax.xml.transform.Source;
+import javax.xml.transform.stream.StreamSource;
+import org.w3c.dom.ls.LSResourceResolver;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXNotRecognizedException;
+import org.xml.sax.SAXNotSupportedException;
+
+/**
+ * Factory that creates {@link Schema} objects&#x2E; Entry-point to
+ * the validation API.
+ *
+ * <p>
+ * {@link SchemaFactory} is a schema compiler. It reads external
+ * representations of schemas and prepares them for validation.
+ *
+ * <p>
+ * The {@link SchemaFactory} class is not thread-safe. In other words,
+ * it is the application's responsibility to ensure that at most
+ * one thread is using a {@link SchemaFactory} object at any
+ * given moment. Implementations are encouraged to mark methods
+ * as <tt>synchronized</tt> to protect themselves from broken clients.
+ *
+ * <p>
+ * {@link SchemaFactory} is not re-entrant. While one of the
+ * <code>newSchema</code> methods is being invoked, applications
+ * may not attempt to recursively invoke the <code>newSchema</code> method,
+ * even from the same thread.
+ *
+ * <h2><a name="schemaLanguage"></a>Schema Language</h2>
+ * <p>
+ * This spec uses a namespace URI to designate a schema language.
+ * The following table shows the values defined by this specification.
+ * <p>
+ * To be compliant with the spec, the implementation
+ * is only required to support W3C XML Schema 1.0. However,
+ * if it chooses to support other schema languages listed here,
+ * it must conform to the relevant behaviors described in this spec.
+ *
+ * <p>
+ * Schema languages not listed here are expected to
+ * introduce their own URIs to represent themselves.
+ * The {@link SchemaFactory} class is capable of locating other
+ * implementations for other schema languages at run-time.
+ *
+ * <p>
+ * Note that because the XML DTD is strongly tied to the parsing process
+ * and has a significant effect on the parsing process, it is impossible
+ * to define the DTD validation as a process independent from parsing.
+ * For this reason, this specification does not define the semantics for
+ * the XML DTD. This doesn't prohibit implementers from implementing it
+ * in a way they see fit, but <em>users are warned that any DTD
+ * validation implemented on this interface necessarily deviate from
+ * the XML DTD semantics as defined in the XML 1.0</em>.
+ *
+ * <table border="1" cellpadding="2">
+ *   <thead>
+ *     <tr>
+ *       <th>value</th>
+ *       <th>language</th>
+ *     </tr>
+ *   </thead>
+ *   <tbody>
+ *     <tr>
+ *       <td>{@link javax.xml.XMLConstants#W3C_XML_SCHEMA_NS_URI} ("<code>http://www.w3.org/2001/XMLSchema</code>")</td>
+ *       <td><a href="http://www.w3.org/TR/xmlschema-1">W3C XML Schema 1.0</a></td>
+ *     </tr>
+ *     <tr>
+ *       <td>{@link javax.xml.XMLConstants#RELAXNG_NS_URI} ("<code>http://relaxng.org/ns/structure/1.0</code>")</td>
+ *       <td><a href="http://www.relaxng.org/">RELAX NG 1.0</a></td>
+ *     </tr>
+ *   </tbody>
+ * </table>
+ *
+ * @author  <a href="mailto:[email protected]">Kohsuke Kawaguchi</a>
+ * @version $Revision: 884952 $, $Date: 2009-11-27 10:55:08 -0800 (Fri, 27 Nov 2009) $
+ * @since 1.5
+ */
+public abstract class SchemaFactory {
+
+    /**
+     * <p>Constructor for derived classes.</p>
+     *
+     * <p>The constructor does nothing.</p>
+     *
+     * <p>Derived classes must create {@link SchemaFactory} objects that have
+     * <code>null</code> {@link ErrorHandler} and
+     * <code>null</code> {@link LSResourceResolver}.</p>
+     */
+    protected SchemaFactory() {
+    }
+
+    /**
+     * <p>Lookup an implementation of the <code>SchemaFactory</code> that supports the specified
+     * schema language and return it.</p>
+     *
+     * <p>To find a <code>SchemaFactory</code> object for a given schema language,
+     * this method looks the following places in the following order
+     * where "the class loader" refers to the context class loader:</p>
+     * <ol>
+     *  <li>
+     *     If the system property
+     *     <code>"javax.xml.validation.SchemaFactory:<i>schemaLanguage</i>"</code>
+     *     is present (where <i>schemaLanguage</i> is the parameter
+     *     to this method), then its value is read
+     *     as a class name. The method will try to
+     *     create a new instance of this class by using the class loader,
+     *     and returns it if it is successfully created.
+     *   </li>
+     *   <li>
+     *     <code>$java.home/lib/jaxp.properties</code> is read and
+     *     the value associated with the key being the system property above
+     *     is looked for. If present, the value is processed just like above.
+     *   </li>
+     *   <li>
+     *     <p>The class loader is asked for service provider provider-configuration files matching
+     *     <code>javax.xml.validation.SchemaFactory</code> in the resource directory META-INF/services.
+     *     See the JAR File Specification for file format and parsing rules.
+     *     Each potential service provider is required to implement the method:</p>
+     *     <pre>
+     *        {@link #isSchemaLanguageSupported(String schemaLanguage)}
+     *     </pre>
+     *     The first service provider found in class loader order that supports the specified schema language is returned.
+     *   </li>
+     *   <li>
+     *     Platform default <code>SchemaFactory</code> is located
+     *     in a implementation specific way. There must be a platform default
+     *     <code>SchemaFactory</code> for W3C XML Schema.
+     *   </li>
+     * </ol>
+     *
+     * <p>If everything fails, {@link IllegalArgumentException} will be thrown.</p>
+     *
+     * <p><strong>Tip for Trouble-shooting:</strong></p>
+     * <p>See {@link java.util.Properties#load(java.io.InputStream)} for
+     * exactly how a property file is parsed. In particular, colons ':'
+     * need to be escaped in a property file, so make sure schema language
+     * URIs are properly escaped in it. For example:</p>
+     * <pre>
+     * http\://www.w3.org/2001/XMLSchema=org.acme.foo.XSSchemaFactory
+     * </pre>
+     *
+     * @param schemaLanguage
+     *      Specifies the schema language which the returned
+     *      SchemaFactory will understand. See
+     *      <a href="#schemaLanguage">the list of available
+     *      schema languages</a> for the possible values.
+     *
+     * @return New instance of a <code>SchemaFactory</code>
+     *
+     * @throws IllegalArgumentException
+     *      If no implementation of the schema language is available.
+     *
+     * @throws NullPointerException
+     *      If the <tt>schemaLanguage</tt> parameter is null.
+     */
+    public static SchemaFactory newInstance(String schemaLanguage) {
+        ClassLoader cl;
+        cl = Thread.currentThread().getContextClassLoader();
+
+        if (cl == null) {
+            //cl = ClassLoader.getSystemClassLoader();
+            //use the current class loader
+            cl = SchemaFactory.class.getClassLoader();
+        }
+
+        SchemaFactory f = new SchemaFactoryFinder(cl).newFactory(schemaLanguage);
+        if (f == null) {
+            throw new IllegalArgumentException(schemaLanguage);
+        }
+        return f;
+    }
+
+    /**
+     * Returns an instance of the named implementation of {@code SchemaFactory}.
+     *
+     * @throws IllegalArgumentException if {@code factoryClassName} is not available, cannot be
+     *     instantiated, or doesn't support {@code schemaLanguage}.
+     * @since 1.6
+     */
+    public static SchemaFactory newInstance(String schemaLanguage, String factoryClassName,
+            ClassLoader classLoader) {
+        if (schemaLanguage == null) {
+            throw new NullPointerException("schemaLanguage == null");
+        } else if (factoryClassName == null) {
+            throw new NullPointerException("factoryClassName == null");
+        }
+        if (classLoader == null) {
+            classLoader = Thread.currentThread().getContextClassLoader();
+        }
+        try {
+            Class<?> type = classLoader != null
+                    ? classLoader.loadClass(factoryClassName)
+                    : Class.forName(factoryClassName);
+            SchemaFactory result = (SchemaFactory) type.newInstance();
+            if (result == null || !result.isSchemaLanguageSupported(schemaLanguage)) {
+                throw new IllegalArgumentException(schemaLanguage);
+            }
+            return result;
+        } catch (ClassNotFoundException e) {
+            throw new IllegalArgumentException(e);
+        } catch (InstantiationException e) {
+            throw new IllegalArgumentException(e);
+        } catch (IllegalAccessException e) {
+            throw new IllegalArgumentException(e);
+        }
+    }
+
+    /**
+     * <p>Is specified schema supported by this <code>SchemaFactory</code>?</p>
+     *
+     * @param schemaLanguage Specifies the schema language which the returned <code>SchemaFactory</code> will understand.
+     *    <code>schemaLanguage</code> must specify a <a href="#schemaLanguage">valid</a> schema language.
+     *
+     * @return <code>true</code> if <code>SchemaFactory</code> supports <code>schemaLanguage</code>, else <code>false</code>.
+     *
+     * @throws NullPointerException If <code>schemaLanguage</code> is <code>null</code>.
+     * @throws IllegalArgumentException If <code>schemaLanguage.length() == 0</code>
+     *   or <code>schemaLanguage</code> does not specify a <a href="#schemaLanguage">valid</a> schema language.
+     */
+    public abstract boolean isSchemaLanguageSupported(String schemaLanguage);
+
+    /**
+     * Look up the value of a feature flag.
+     *
+     * <p>The feature name is any fully-qualified URI.  It is
+     * possible for a {@link SchemaFactory} to recognize a feature name but
+     * temporarily be unable to return its value.
+     *
+     * <p>Implementers are free (and encouraged) to invent their own features,
+     * using names built on their own URIs.</p>
+     *
+     * @param name The feature name, which is a non-null fully-qualified URI.
+     * @return The current value of the feature (true or false).
+     * @exception org.xml.sax.SAXNotRecognizedException If the feature
+     *            value can't be assigned or retrieved.
+     * @exception org.xml.sax.SAXNotSupportedException When the
+     *            {@link SchemaFactory} recognizes the feature name but
+     *            cannot determine its value at this time.
+     * @exception NullPointerException
+     *              if the name parameter is null.
+     * @see #setFeature(String, boolean)
+     */
+    public boolean getFeature(String name) throws SAXNotRecognizedException, SAXNotSupportedException {
+
+        if (name == null) {
+            throw new NullPointerException("name == null");
+        }
+        throw new SAXNotRecognizedException(name);
+    }
+
+    /**
+     * Set the value of a feature flag.
+     *
+     * <p>
+     * Feature can be used to control the way a {@link SchemaFactory}
+     * parses schemas, although {@link SchemaFactory}s are not required
+     * to recognize any specific feature names.</p>
+     *
+     * <p>The feature name is any fully-qualified URI.  It is
+     * possible for a {@link SchemaFactory} to expose a feature value but
+     * to be unable to change the current value.</p>
+     *
+     * <p>All implementations are required to support the {@link javax.xml.XMLConstants#FEATURE_SECURE_PROCESSING} feature.
+     * When the feature is:</p>
+     * <ul>
+     *   <li>
+     *     <code>true</code>: the implementation will limit XML processing to conform to implementation limits.
+     *     Examples include entity expansion limits and XML Schema constructs that would consume large amounts of resources.
+     *     If XML processing is limited for security reasons, it will be reported via a call to the registered
+     *     {@link ErrorHandler#fatalError(org.xml.sax.SAXParseException)}.
+     *     See {@link  #setErrorHandler(ErrorHandler errorHandler)}.
+     *   </li>
+     *   <li>
+     *     <code>false</code>: the implementation will processing XML according to the XML specifications without
+     *     regard to possible implementation limits.
+     *   </li>
+     * </ul>
+     *
+     * @param name The feature name, which is a non-null fully-qualified URI.
+     * @param value The requested value of the feature (true or false).
+     *
+     * @exception org.xml.sax.SAXNotRecognizedException If the feature
+     *            value can't be assigned or retrieved.
+     * @exception org.xml.sax.SAXNotSupportedException When the
+     *            {@link SchemaFactory} recognizes the feature name but
+     *            cannot set the requested value.
+     * @exception NullPointerException
+     *              if the name parameter is null.
+     *
+     * @see #getFeature(String)
+     */
+    public void setFeature(String name, boolean value) throws SAXNotRecognizedException, SAXNotSupportedException {
+        if (name == null) {
+            throw new NullPointerException("name == null");
+        }
+        throw new SAXNotRecognizedException(name);
+    }
+
+    /**
+     * Set the value of a property.
+     *
+     * <p>The property name is any fully-qualified URI.  It is
+     * possible for a {@link SchemaFactory} to recognize a property name but
+     * to be unable to change the current value.</p>
+     *
+     * <p>{@link SchemaFactory}s are not required to recognize setting
+     * any specific property names.</p>
+     *
+     * @param name The property name, which is a non-null fully-qualified URI.
+     * @param object The requested value for the property.
+     * @exception org.xml.sax.SAXNotRecognizedException If the property
+     *            value can't be assigned or retrieved.
+     * @exception org.xml.sax.SAXNotSupportedException When the
+     *            {@link SchemaFactory} recognizes the property name but
+     *            cannot set the requested value.
+     * @exception NullPointerException
+     *              if the name parameter is null.
+     */
+    public void setProperty(String name, Object object) throws SAXNotRecognizedException, SAXNotSupportedException {
+        if (name == null) {
+            throw new NullPointerException("name == null");
+        }
+        throw new SAXNotRecognizedException(name);
+    }
+
+    /**
+     * Look up the value of a property.
+     *
+     * <p>The property name is any fully-qualified URI.  It is
+     * possible for a {@link SchemaFactory} to recognize a property name but
+     * temporarily be unable to return its value.</p>
+     *
+     * <p>{@link SchemaFactory}s are not required to recognize any specific
+     * property names.</p>
+     *
+     * <p>Implementers are free (and encouraged) to invent their own properties,
+     * using names built on their own URIs.</p>
+     *
+     * @param name The property name, which is a non-null fully-qualified URI.
+     * @return The current value of the property.
+     * @exception org.xml.sax.SAXNotRecognizedException If the property
+     *            value can't be assigned or retrieved.
+     * @exception org.xml.sax.SAXNotSupportedException When the
+     *            XMLReader recognizes the property name but
+     *            cannot determine its value at this time.
+     * @exception NullPointerException
+     *              if the name parameter is null.
+     * @see #setProperty(String, Object)
+     */
+    public Object getProperty(String name) throws SAXNotRecognizedException, SAXNotSupportedException {
+        if (name == null) {
+            throw new NullPointerException("name == null");
+        }
+        throw new SAXNotRecognizedException(name);
+    }
+
+    /**
+     * Sets the {@link ErrorHandler} to receive errors encountered
+     * during the <code>newSchema</code> method invocation.
+     *
+     * <p>
+     * Error handler can be used to customize the error handling process
+     * during schema parsing. When an {@link ErrorHandler} is set,
+     * errors found during the parsing of schemas will be first sent
+     * to the {@link ErrorHandler}.
+     *
+     * <p>
+     * The error handler can abort the parsing of a schema immediately
+     * by throwing {@link SAXException} from the handler. Or for example
+     * it can print an error to the screen and try to continue the
+     * processing by returning normally from the {@link ErrorHandler}
+     *
+     * <p>
+     * If any {@link Throwable} (or instances of its derived classes)
+     * is thrown from an {@link ErrorHandler},
+     * the caller of the <code>newSchema</code> method will be thrown
+     * the same {@link Throwable} object.
+     *
+     * <p>
+     * {@link SchemaFactory} is not allowed to
+     * throw {@link SAXException} without first reporting it to
+     * {@link ErrorHandler}.
+     *
+     * <p>
+     * Applications can call this method even during a {@link Schema}
+     * is being parsed.
+     *
+     * <p>
+     * When the {@link ErrorHandler} is null, the implementation will
+     * behave as if the following {@link ErrorHandler} is set:
+     * <pre>
+     * class DraconianErrorHandler implements {@link ErrorHandler} {
+     *     public void fatalError( {@link org.xml.sax.SAXParseException} e ) throws {@link SAXException} {
+     *         throw e;
+     *     }
+     *     public void error( {@link org.xml.sax.SAXParseException} e ) throws {@link SAXException} {
+     *         throw e;
+     *     }
+     *     public void warning( {@link org.xml.sax.SAXParseException} e ) throws {@link SAXException} {
+     *         // noop
+     *     }
+     * }
+     * </pre>
+     *
+     * <p>
+     * When a new {@link SchemaFactory} object is created, initially
+     * this field is set to null. This field will <em>NOT</em> be
+     * inherited to {@link Schema}s, {@link Validator}s, or
+     * {@link ValidatorHandler}s that are created from this {@link SchemaFactory}.
+     *
+     *
+     * @param   errorHandler
+     *      A new error handler to be set. This parameter can be null.
+     */
+    public abstract void setErrorHandler(ErrorHandler errorHandler);
+
+    /**
+     * Gets the current {@link ErrorHandler} set to this {@link SchemaFactory}.
+     *
+     * @return
+     *      This method returns the object that was last set through
+     *      the {@link #setErrorHandler(ErrorHandler)} method, or null
+     *      if that method has never been called since this {@link SchemaFactory}
+     *      has created.
+     *
+     * @see #setErrorHandler(ErrorHandler)
+     */
+    public abstract ErrorHandler getErrorHandler();
+
+    /**
+     * Sets the {@link LSResourceResolver} to customize
+     * resource resolution when parsing schemas.
+     *
+     * <p>
+     * {@link SchemaFactory} uses a {@link LSResourceResolver}
+     * when it needs to locate external resources while parsing schemas,
+     * although exactly what constitutes "locating external resources" is
+     * up to each schema language. For example, for W3C XML Schema,
+     * this includes files <tt>&lt;include></tt>d or <tt>&lt;import></tt>ed,
+     * and DTD referenced from schema files, etc.
+     *
+     * <p>
+     * Applications can call this method even during a {@link Schema}
+     * is being parsed.
+     *
+     * <p>
+     * When the {@link LSResourceResolver} is null, the implementation will
+     * behave as if the following {@link LSResourceResolver} is set:
+     * <pre>
+     * class DumbDOMResourceResolver implements {@link LSResourceResolver} {
+     *     public {@link org.w3c.dom.ls.LSInput} resolveResource(
+     *         String publicId, String systemId, String baseURI) {
+     *
+     *         return null; // always return null
+     *     }
+     * }
+     * </pre>
+     *
+     * <p>
+     * If a {@link LSResourceResolver} throws a {@link RuntimeException}
+     *  (or instances of its derived classes),
+     * then the {@link SchemaFactory} will abort the parsing and
+     * the caller of the <code>newSchema</code> method will receive
+     * the same {@link RuntimeException}.
+     *
+     * <p>
+     * When a new {@link SchemaFactory} object is created, initially
+     * this field is set to null.  This field will <em>NOT</em> be
+     * inherited to {@link Schema}s, {@link Validator}s, or
+     * {@link ValidatorHandler}s that are created from this {@link SchemaFactory}.
+     *
+     * @param   resourceResolver
+     *      A new resource resolver to be set. This parameter can be null.
+     */
+    public abstract void setResourceResolver(LSResourceResolver resourceResolver);
+
+    /**
+     * Gets the current {@link LSResourceResolver} set to this {@link SchemaFactory}.
+     *
+     * @return
+     *      This method returns the object that was last set through
+     *      the {@link #setResourceResolver(LSResourceResolver)} method, or null
+     *      if that method has never been called since this {@link SchemaFactory}
+     *      has created.
+     *
+     * @see #setErrorHandler(ErrorHandler)
+     */
+    public abstract LSResourceResolver getResourceResolver();
+
+    /**
+     * <p>Parses the specified source as a schema and returns it as a schema.</p>
+     *
+     * <p>This is a convenience method for {@link #newSchema(Source[] schemas)}.</p>
+     *
+     * @param schema Source that represents a schema.
+     *
+     * @return New <code>Schema</code> from parsing <code>schema</code>.
+     *
+     * @throws SAXException If a SAX error occurs during parsing.
+     * @throws NullPointerException if <tt>schema</tt> is null.
+     */
+    public Schema newSchema(Source schema) throws SAXException {
+        return newSchema(new Source[]{schema});
+    }
+
+    /**
+     * <p>Parses the specified <code>File</code> as a schema and returns it as a <code>Schema</code>.</p>
+     *
+     * <p>This is a convenience method for {@link #newSchema(Source schema)}.</p>
+     *
+     * @param schema File that represents a schema.
+     *
+     * @return New <code>Schema</code> from parsing <code>schema</code>.
+     *
+     * @throws SAXException If a SAX error occurs during parsing.
+     * @throws NullPointerException if <tt>schema</tt> is null.
+     */
+    public Schema newSchema(File schema) throws SAXException {
+        return newSchema(new StreamSource(schema));
+    }
+
+    /**
+     * <p>Parses the specified <code>URL</code> as a schema and returns it as a <code>Schema</code>.</p>
+     *
+     * <p>This is a convenience method for {@link #newSchema(Source schema)}.</p>
+     *
+     * @param schema <code>URL</code> that represents a schema.
+     *
+     * @return New <code>Schema</code> from parsing <code>schema</code>.
+     *
+     * @throws SAXException If a SAX error occurs during parsing.
+     * @throws NullPointerException if <tt>schema</tt> is null.
+     */
+    public Schema newSchema(URL schema) throws SAXException {
+        return newSchema(new StreamSource(schema.toExternalForm()));
+    }
+
+    /**
+     * Parses the specified source(s) as a schema and returns it as a schema.
+     *
+     * <p>
+     * The callee will read all the {@link Source}s and combine them into a
+     * single schema. The exact semantics of the combination depends on the schema
+     * language that this {@link SchemaFactory} object is created for.
+     *
+     * <p>
+     * When an {@link ErrorHandler} is set, the callee will report all the errors
+     * found in sources to the handler. If the handler throws an exception, it will
+     * abort the schema compilation and the same exception will be thrown from
+     * this method. Also, after an error is reported to a handler, the callee is allowed
+     * to abort the further processing by throwing it. If an error handler is not set,
+     * the callee will throw the first error it finds in the sources.
+     *
+     * <h2>W3C XML Schema 1.0</h2>
+     * <p>
+     * The resulting schema contains components from the specified sources.
+     * The same result would be achieved if all these sources were
+     * imported, using appropriate values for schemaLocation and namespace,
+     * into a single schema document with a different targetNamespace
+     * and no components of its own, if the import elements were given
+     * in the same order as the sources.  Section 4.2.3 of the XML Schema
+     * recommendation describes the options processors have in this
+     * regard.  While a processor should be consistent in its treatment of
+     * JAXP schema sources and XML Schema imports, the behavior between
+     * JAXP-compliant parsers may vary; in particular, parsers may choose
+     * to ignore all but the first &lt;import> for a given namespace,
+     * regardless of information provided in schemaLocation.
+     *
+     * <p>
+     * If the parsed set of schemas includes error(s) as
+     * specified in the section 5.1 of the XML Schema spec, then
+     * the error must be reported to the {@link ErrorHandler}.
+     *
+     * <h2>RELAX NG</h2>
+     *
+     * <p>For RELAX NG, this method must throw {@link UnsupportedOperationException}
+     * if <tt>schemas.length!=1</tt>.
+     *
+     *
+     * @param schemas
+     *      inputs to be parsed. {@link SchemaFactory} is required
+     *      to recognize {@link StreamSource},
+     *      {@link javax.xml.transform.sax.SAXSource},
+     *      and {@link javax.xml.transform.dom.DOMSource}.
+     *
+     * @return
+     *      Always return a non-null valid {@link Schema} object.
+     *      Note that when an error has been reported, there is no
+     *      guarantee that the returned {@link Schema} object is
+     *      meaningful.
+     *
+     * @throws SAXException
+     *      If an error is found during processing the specified inputs.
+     *      When an {@link ErrorHandler} is set, errors are reported to
+     *      there first. See {@link #setErrorHandler(ErrorHandler)}.
+     * @throws NullPointerException
+     *      If the <code>schemas</code> parameter itself is null or
+     *      any item in the array is null.
+     * @throws IllegalArgumentException
+     *      If any item in the array is not recognized by this method.
+     * @throws UnsupportedOperationException
+     *      If the schema language doesn't support this operation.
+     */
+    public abstract Schema newSchema(Source[] schemas) throws SAXException;
+
+    /**
+     * Creates a special {@link Schema} object.
+     *
+     * <p>
+     * The exact semantics of the returned {@link Schema} object depends
+     * on the schema language that this {@link SchemaFactory} is created
+     * for.
+     *
+     * <p>
+     * Also, implementations are allowed to use implementation-specific
+     * property/feature to alter the semantics of this method.
+     *
+     *
+     * <h2>W3C XML Schema 1.0</h2>
+     * <p>
+     * For XML Schema, this method creates a {@link Schema} object that
+     * performs validation by using location hints specified in documents.
+     *
+     * <p>
+     * The returned {@link Schema} object assumes that if documents
+     * refer to the same URL in the schema location hints,
+     * they will always resolve to the same schema document. This
+     * assumption allows implementations to reuse parsed results of
+     * schema documents so that multiple validations against the same
+     * schema will run faster.
+     *
+     * <p>
+     * Note that the use of schema location hints introduces a
+     * vulnerability to denial-of-service attacks.
+     *
+     *
+     * <h2>RELAX NG</h2>
+     * <p>
+     * RELAX NG does not support this operation.
+     *
+     * @return
+     *      Always return non-null valid {@link Schema} object.
+     *
+     * @throws UnsupportedOperationException
+     *      If this operation is not supported by the callee.
+     * @throws SAXException
+     *      If this operation is supported but failed for some reason.
+     */
+    public abstract Schema newSchema() throws SAXException;
+}
diff --git a/javax/xml/validation/SchemaFactoryFinder.java b/javax/xml/validation/SchemaFactoryFinder.java
new file mode 100644
index 0000000..50a644f
--- /dev/null
+++ b/javax/xml/validation/SchemaFactoryFinder.java
@@ -0,0 +1,411 @@
+/*
+ * 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.
+ */
+// $Id: SchemaFactoryFinder.java 727367 2008-12-17 13:05:26Z mrglavas $
+
+package javax.xml.validation;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.Properties;
+import javax.xml.XMLConstants;
+import libcore.io.IoUtils;
+
+/**
+ * Implementation of {@link SchemaFactory#newInstance(String)}.
+ *
+ * @author <a href="[email protected]">Kohsuke Kawaguchi</a>
+ * @version $Revision: 727367 $, $Date: 2008-12-17 05:05:26 -0800 (Wed, 17 Dec 2008) $
+ * @since 1.5
+ */
+final class SchemaFactoryFinder  {
+
+    /** XML Schema language identifiers. */
+    private static final String W3C_XML_SCHEMA10_NS_URI = "http://www.w3.org/XML/XMLSchema/v1.0";
+    private static final String W3C_XML_SCHEMA11_NS_URI = "http://www.w3.org/XML/XMLSchema/v1.1";
+
+    /** debug support code. */
+    private static boolean debug = false;
+
+    /**
+     * <p>Cache properties for performance. Use a static class to avoid double-checked
+     * locking.</p>
+     */
+    private static class CacheHolder {
+
+        private static Properties cacheProps = new Properties();
+
+        static {
+            String javah = System.getProperty("java.home");
+            String configFile = javah + File.separator + "lib" + File.separator + "jaxp.properties";
+            File f = new File(configFile);
+            if (f.exists()) {
+                if (debug) debugPrintln("Read properties file " + f);
+                try (FileInputStream inputStream = new FileInputStream(f)) {
+                    cacheProps.load(inputStream);
+                } catch (Exception ex) {
+                    if (debug) {
+                        ex.printStackTrace();
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Default columns per line.
+     */
+    private static final int DEFAULT_LINE_LENGTH = 80;
+
+    static {
+        String val = System.getProperty("jaxp.debug");
+        // Allow simply setting the prop to turn on debug
+        debug = val != null && (! "false".equals(val));
+    }
+
+    /**
+     * <p>Conditional debug printing.</p>
+     *
+     * @param msg to print
+     */
+    private static void debugPrintln(String msg) {
+        if (debug) {
+            System.err.println("JAXP: " + msg);
+        }
+    }
+
+    /**
+     * <p><code>ClassLoader</code> to use to find <code>SchemaFactory</code>.</p>
+     */
+    private final ClassLoader classLoader;
+
+    /**
+     * <p>Constructor that specifies <code>ClassLoader</code> to use
+     * to find <code>SchemaFactory</code>.</p>
+     *
+     * @param loader
+     *      to be used to load resource, {@link SchemaFactory}, and
+     *      {@link SchemaFactoryLoader} implementations during
+     *      the resolution process.
+     *      If this parameter is null, the default system class loader
+     *      will be used.
+     */
+    public SchemaFactoryFinder(ClassLoader loader) {
+        this.classLoader = loader;
+        if( debug ) {
+            debugDisplayClassLoader();
+        }
+    }
+
+    private void debugDisplayClassLoader() {
+        if (classLoader == Thread.currentThread().getContextClassLoader()) {
+            debugPrintln("using thread context class loader ("+classLoader+") for search");
+            return;
+        }
+
+        if (classLoader == ClassLoader.getSystemClassLoader()) {
+            debugPrintln("using system class loader ("+classLoader+") for search");
+            return;
+        }
+
+        debugPrintln("using class loader (" + classLoader + ") for search");
+    }
+
+    /**
+     * <p>Creates a new {@link SchemaFactory} object for the specified
+     * schema language.</p>
+     *
+     * @param schemaLanguage
+     *      See {@link SchemaFactory Schema Language} table in <code>SchemaFactory</code>
+     *      for the list of available schema languages.
+     *
+     * @return <code>null</code> if the callee fails to create one.
+     *
+     * @throws NullPointerException
+     *      If the <tt>schemaLanguage</tt> parameter is null.
+     */
+    public SchemaFactory newFactory(String schemaLanguage) {
+        if (schemaLanguage == null) {
+            throw new NullPointerException("schemaLanguage == null");
+        }
+        SchemaFactory f = _newFactory(schemaLanguage);
+        if (debug) {
+            if (f != null) {
+                debugPrintln("factory '" + f.getClass().getName() + "' was found for " + schemaLanguage);
+            } else {
+                debugPrintln("unable to find a factory for " + schemaLanguage);
+            }
+        }
+        return f;
+    }
+
+    /**
+     * <p>Lookup a <code>SchemaFactory</code> for the given <code>schemaLanguage</code>.</p>
+     *
+     * @param schemaLanguage Schema language to lookup <code>SchemaFactory</code> for.
+     *
+     * @return <code>SchemaFactory</code> for the given <code>schemaLanguage</code>.
+     */
+    private SchemaFactory _newFactory(String schemaLanguage) {
+        SchemaFactory sf;
+        String propertyName = SERVICE_CLASS.getName() + ":" + schemaLanguage;
+
+        // system property look up
+        try {
+            if (debug) debugPrintln("Looking up system property '"+propertyName+"'" );
+            String r = System.getProperty(propertyName);
+            if (r != null && r.length() > 0) {
+                if (debug) debugPrintln("The value is '"+r+"'");
+                sf = createInstance(r);
+                if(sf!=null)    return sf;
+            }
+            else if (debug) {
+                debugPrintln("The property is undefined.");
+            }
+        }
+        // The VM ran out of memory or there was some other serious problem. Re-throw.
+        catch (VirtualMachineError vme) {
+            throw vme;
+        }
+        // ThreadDeath should always be re-thrown
+        catch (ThreadDeath td) {
+            throw td;
+        }
+        catch (Throwable t) {
+            if( debug ) {
+                debugPrintln("failed to look up system property '"+propertyName+"'" );
+                t.printStackTrace();
+            }
+        }
+
+        // try to read from $java.home/lib/jaxp.properties
+        try {
+            String factoryClassName = CacheHolder.cacheProps.getProperty(propertyName);
+            if (debug) debugPrintln("found " + factoryClassName + " in $java.home/jaxp.properties");
+
+            if (factoryClassName != null) {
+                sf = createInstance(factoryClassName);
+                if(sf != null){
+                    return sf;
+                }
+            }
+        } catch (Exception ex) {
+            if (debug) {
+                ex.printStackTrace();
+            }
+        }
+
+        // try META-INF/services files
+        for (URL resource : createServiceFileIterator()) {
+            if (debug) debugPrintln("looking into " + resource);
+            try {
+                sf = loadFromServicesFile(schemaLanguage,resource.toExternalForm(),
+                        resource.openStream());
+                if(sf!=null)    return sf;
+            } catch(IOException e) {
+                if( debug ) {
+                    debugPrintln("failed to read "+resource);
+                    e.printStackTrace();
+                }
+            }
+        }
+
+        // platform defaults
+        if (schemaLanguage.equals(XMLConstants.W3C_XML_SCHEMA_NS_URI) || schemaLanguage.equals(W3C_XML_SCHEMA10_NS_URI)) {
+            if (debug) debugPrintln("attempting to use the platform default XML Schema 1.0 validator");
+            return createInstance("org.apache.xerces.jaxp.validation.XMLSchemaFactory");
+        }
+        else if (schemaLanguage.equals(W3C_XML_SCHEMA11_NS_URI)) {
+            if (debug) debugPrintln("attempting to use the platform default XML Schema 1.1 validator");
+            return createInstance("org.apache.xerces.jaxp.validation.XMLSchema11Factory");
+        }
+
+        if (debug) debugPrintln("all things were tried, but none was found. bailing out.");
+        return null;
+    }
+
+    /**
+     * <p>Creates an instance of the specified and returns it.</p>
+     *
+     * @param className
+     *      fully qualified class name to be instantiated.
+     *
+     * @return null
+     *      if it fails. Error messages will be printed by this method.
+     */
+    SchemaFactory createInstance( String className ) {
+        try {
+            if (debug) debugPrintln("instantiating "+className);
+            Class clazz;
+            if( classLoader!=null )
+                clazz = classLoader.loadClass(className);
+            else
+                clazz = Class.forName(className);
+            if(debug)       debugPrintln("loaded it from "+which(clazz));
+            Object o = clazz.newInstance();
+
+            if( o instanceof SchemaFactory )
+                return (SchemaFactory)o;
+
+            if (debug) debugPrintln(className+" is not assignable to "+SERVICE_CLASS.getName());
+        }
+        // The VM ran out of memory or there was some other serious problem. Re-throw.
+        catch (VirtualMachineError vme) {
+            throw vme;
+        }
+        // ThreadDeath should always be re-thrown
+        catch (ThreadDeath td) {
+            throw td;
+        }
+        catch (Throwable t) {
+            debugPrintln("failed to instantiate "+className);
+            if(debug)   t.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * Returns an {@link Iterator} that enumerates all
+     * the META-INF/services files that we care.
+     */
+    private Iterable<URL> createServiceFileIterator() {
+        if (classLoader == null) {
+            ClassLoader classLoader = SchemaFactoryFinder.class.getClassLoader();
+            return Collections.singleton(classLoader.getResource(SERVICE_ID));
+        } else {
+            try {
+                Enumeration<URL> e = classLoader.getResources(SERVICE_ID);
+                if (debug && !e.hasMoreElements()) {
+                    debugPrintln("no "+SERVICE_ID+" file was found");
+                }
+
+                // wrap it into an Iterator.
+                return Collections.list(e);
+            } catch (IOException e) {
+                if (debug) {
+                    debugPrintln("failed to enumerate resources "+SERVICE_ID);
+                    e.printStackTrace();
+                }
+                return Collections.emptySet();
+            }
+        }
+    }
+
+    /** Searches for a SchemaFactory for a given schema language in a META-INF/services file. */
+    private SchemaFactory loadFromServicesFile(String schemaLanguage, String resourceName, InputStream in) {
+
+        if (debug) debugPrintln("Reading "+resourceName );
+
+        // Read the service provider name in UTF-8 as specified in
+        // the jar spec.  Unfortunately this fails in Microsoft
+        // VJ++, which does not implement the UTF-8
+        // encoding. Theoretically, we should simply let it fail in
+        // that case, since the JVM is obviously broken if it
+        // doesn't support such a basic standard.  But since there
+        // are still some users attempting to use VJ++ for
+        // development, we have dropped in a fallback which makes a
+        // second attempt using the platform's default encoding. In
+        // VJ++ this is apparently ASCII, which is a subset of
+        // UTF-8... and since the strings we'll be reading here are
+        // also primarily limited to the 7-bit ASCII range (at
+        // least, in English versions), this should work well
+        // enough to keep us on the air until we're ready to
+        // officially decommit from VJ++. [Edited comment from
+        // jkesselm]
+        BufferedReader rd;
+        try {
+            rd = new BufferedReader(new InputStreamReader(in, "UTF-8"), DEFAULT_LINE_LENGTH);
+        } catch (java.io.UnsupportedEncodingException e) {
+            rd = new BufferedReader(new InputStreamReader(in), DEFAULT_LINE_LENGTH);
+        }
+
+        String factoryClassName = null;
+        SchemaFactory resultFactory = null;
+        // See spec for provider-configuration files: http://java.sun.com/j2se/1.5.0/docs/guide/jar/jar.html#Provider%20Configuration%20File
+        while (true) {
+            try {
+                factoryClassName = rd.readLine();
+            } catch (IOException x) {
+                // No provider found
+                break;
+            }
+            if (factoryClassName != null) {
+                // Ignore comments in the provider-configuration file
+                int hashIndex = factoryClassName.indexOf('#');
+                if (hashIndex != -1) {
+                    factoryClassName = factoryClassName.substring(0, hashIndex);
+                }
+
+                // Ignore leading and trailing whitespace
+                factoryClassName = factoryClassName.trim();
+
+                // If there's no text left or if this was a blank line, go to the next one.
+                if (factoryClassName.length() == 0) {
+                    continue;
+                }
+
+                try {
+                    // Found the right SchemaFactory if its isSchemaLanguageSupported(schemaLanguage) method returns true.
+                    SchemaFactory foundFactory = (SchemaFactory) createInstance(factoryClassName);
+                    if (foundFactory.isSchemaLanguageSupported(schemaLanguage)) {
+                        resultFactory = foundFactory;
+                        break;
+                    }
+                }
+                catch (Exception ignored) {}
+            }
+            else {
+                break;
+            }
+        }
+
+        IoUtils.closeQuietly(rd);
+
+        return resultFactory;
+    }
+
+    private static final Class SERVICE_CLASS = SchemaFactory.class;
+    private static final String SERVICE_ID = "META-INF/services/" + SERVICE_CLASS.getName();
+
+    private static String which( Class clazz ) {
+        return which( clazz.getName(), clazz.getClassLoader() );
+    }
+
+    /**
+     * <p>Search the specified classloader for the given classname.</p>
+     *
+     * @param classname the fully qualified name of the class to search for
+     * @param loader the classloader to search
+     *
+     * @return the source location of the resource, or null if it wasn't found
+     */
+    private static String which(String classname, ClassLoader loader) {
+        String classnameAsResource = classname.replace('.', '/') + ".class";
+
+        if (loader == null)  loader = ClassLoader.getSystemClassLoader();
+
+        URL it = loader.getResource(classnameAsResource);
+        return it != null ? it.toString() : null;
+    }
+}
diff --git a/javax/xml/validation/SchemaFactoryLoader.java b/javax/xml/validation/SchemaFactoryLoader.java
new file mode 100644
index 0000000..2ac0fd7
--- /dev/null
+++ b/javax/xml/validation/SchemaFactoryLoader.java
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+// $Id: SchemaFactoryLoader.java 448801 2006-09-22 04:19:20Z mrglavas $
+
+package javax.xml.validation;
+
+/**
+ * <p>This class was removed from JAXP 1.3 before it was finalized but
+ * was mistakenly included in Java 5. It only exists now for compatibility
+ * reasons. Applications should avoid using it.</p>
+ */
+public abstract class SchemaFactoryLoader {
+
+    protected SchemaFactoryLoader() {}
+    public abstract SchemaFactory newFactory(String schemaLanguage);
+
+} // SchemaFactoryLoader
diff --git a/javax/xml/validation/TypeInfoProvider.java b/javax/xml/validation/TypeInfoProvider.java
new file mode 100644
index 0000000..5f5332c
--- /dev/null
+++ b/javax/xml/validation/TypeInfoProvider.java
@@ -0,0 +1,181 @@
+/*
+ * 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.
+ */
+// $Id: TypeInfoProvider.java 884939 2009-11-27 18:20:46Z mrglavas $
+
+package javax.xml.validation;
+
+import org.w3c.dom.TypeInfo;
+
+/**
+ * This class provides access to the type information determined
+ * by {@link ValidatorHandler}.
+ *
+ * <p>
+ * Some schema languages, such as W3C XML Schema, encourages a validator
+ * to report the "type" it assigns to each attribute/element.
+ * Those applications who wish to access this type information can invoke
+ * methods defined on this "interface" to access such type information.
+ *
+ * <p>
+ * Implementation of this "interface" can be obtained through the
+ * {@link ValidatorHandler#getTypeInfoProvider()} method.
+ *
+ * @author  <a href="mailto:[email protected]">Kohsuke Kawaguchi</a>
+ * @version $Revision: 884939 $, $Date: 2009-11-27 10:20:46 -0800 (Fri, 27 Nov 2009) $
+ * @see org.w3c.dom.TypeInfo
+ * @since 1.5
+ */
+public abstract class TypeInfoProvider {
+
+    /**
+     * Constructor for the derived class.
+     *
+     * <p>
+     * The constructor does nothing.
+     */
+    protected TypeInfoProvider() {
+    }
+
+    /**
+     * <p>Returns the immutable {@link TypeInfo} object for the current element.</p>
+     *
+     * <p>
+     * The method may only be called by the startElement and endElement event of
+     * the {@link org.xml.sax.ContentHandler} that the application sets to the
+     * {@link ValidatorHandler}.</p>
+     *
+     * @throws IllegalStateException
+     *      If this method is called from other {@link org.xml.sax.ContentHandler}
+     *      methods.
+     * @return
+     *      An immutable {@link TypeInfo} object that represents the
+     *      type of the current element.
+     *      Note that the caller can keep references to the obtained
+     *      {@link TypeInfo} longer than the callback scope.
+     *
+     *      Otherwise, this method returns
+     *      null if the validator is unable to
+     *      determine the type of the current element for some reason
+     *      (for example, if the validator is recovering from
+     *      an earlier error.)
+     *
+     */
+    public abstract TypeInfo getElementTypeInfo();
+
+    /**
+     * Returns the immutable {@link TypeInfo} object for the specified
+     * attribute of the current element.
+     *
+     * <p>
+     * The method may only be called by the startElement event of
+     * the {@link org.xml.sax.ContentHandler} that the application sets to the
+     * {@link ValidatorHandler}.
+     *
+     * @param index
+     *      The index of the attribute. The same index for
+     *      the {@link org.xml.sax.Attributes} object passed to the
+     *      <tt>startElement</tt> callback.
+     *
+     * @throws IndexOutOfBoundsException
+     *      If the index is invalid.
+     * @throws IllegalStateException
+     *      If this method is called from other {@link org.xml.sax.ContentHandler}
+     *      methods.
+     *
+     * @return
+     *      An immutable {@link TypeInfo} object that represents the
+     *      type of the specified attribute.
+     *      Note that the caller can keep references to the obtained
+     *      {@link TypeInfo} longer than the callback scope.
+     *
+     *      Otherwise, this method returns
+     *      null if the validator is unable to
+     *      determine the type.
+     */
+    public abstract TypeInfo getAttributeTypeInfo(int index);
+
+    /**
+     * Returns <tt>true</tt> if the specified attribute is determined
+     * to be ID.
+     *
+     * <p>
+     * Exactly how an attribute is "determined to be ID" is up to the
+     * schema language. In case of W3C XML Schema, this means
+     * that the actual type of the attribute is the built-in ID type
+     * or its derived type.
+     *
+     * <p>
+     * A {@link javax.xml.parsers.DocumentBuilder} uses this information
+     * to properly implement {@link org.w3c.dom.Attr#isId()}.
+     *
+     * <p>
+     * The method may only be called by the startElement event of
+     * the {@link org.xml.sax.ContentHandler} that the application sets to the
+     * {@link ValidatorHandler}.
+     *
+     * @param index
+     *      The index of the attribute. The same index for
+     *      the {@link org.xml.sax.Attributes} object passed to the
+     *      <tt>startElement</tt> callback.
+     *
+     * @throws IndexOutOfBoundsException
+     *      If the index is invalid.
+     * @throws IllegalStateException
+     *      If this method is called from other {@link org.xml.sax.ContentHandler}
+     *      methods.
+     *
+     * @return true
+     *      if the type of the specified attribute is ID.
+     */
+    public abstract boolean isIdAttribute(int index);
+
+    /**
+     * Returns <tt>false</tt> if the attribute was added by the validator.
+     *
+     * <p>
+     * This method provides information necessary for
+     * a {@link javax.xml.parsers.DocumentBuilder} to determine what
+     * the DOM tree should return from the {@link org.w3c.dom.Attr#getSpecified()} method.
+     *
+     * <p>
+     * The method may only be called by the startElement event of
+     * the {@link org.xml.sax.ContentHandler} that the application sets to the
+     * {@link ValidatorHandler}.
+     *
+     * <p>
+     * A general guideline for validators is to return true if
+     * the attribute was originally present in the pipeline, and
+     * false if it was added by the validator.
+     *
+     * @param index
+     *      The index of the attribute. The same index for
+     *      the {@link org.xml.sax.Attributes} object passed to the
+     *      <tt>startElement</tt> callback.
+     *
+     * @throws IndexOutOfBoundsException
+     *      If the index is invalid.
+     * @throws IllegalStateException
+     *      If this method is called from other {@link org.xml.sax.ContentHandler}
+     *      methods.
+     *
+     * @return
+     *      <tt>true</tt> if the attribute was present before the validator
+     *      processes input. <tt>false</tt> if the attribute was added
+     *      by the validator.
+     */
+    public abstract boolean isSpecified(int index);
+}
diff --git a/javax/xml/validation/Validator.java b/javax/xml/validation/Validator.java
new file mode 100644
index 0000000..ea7908a
--- /dev/null
+++ b/javax/xml/validation/Validator.java
@@ -0,0 +1,445 @@
+/*
+ * 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.
+ */
+// $Id: Validator.java 888884 2009-12-09 17:36:46Z mrglavas $
+
+package javax.xml.validation;
+
+import java.io.IOException;
+import javax.xml.transform.Result;
+import javax.xml.transform.Source;
+import org.w3c.dom.ls.LSResourceResolver;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXNotRecognizedException;
+import org.xml.sax.SAXNotSupportedException;
+
+/**
+ * <p>A processor that checks an XML document against {@link Schema}.</p>
+ *
+ * <p>
+ * A validator is a thread-unsafe and non-reentrant object.
+ * In other words, it is the application's responsibility to make
+ * sure that one {@link Validator} object is not used from
+ * more than one thread at any given time, and while the <tt>validate</tt>
+ * method is invoked, applications may not recursively call
+ * the <tt>validate</tt> method.
+ * <p>
+ *
+ * Note that while the {@link #validate(javax.xml.transform.Source)} and {@link #validate(javax.xml.transform.Source, javax.xml.transform.Result)}
+ * methods take a {@link Source} instance, the <code>Source</code>
+ * instance must be a <code>SAXSource</code>, <code>DOMSource</code>, <code>StAXSource</code> or <code>StreamSource</code>.
+ *
+ * @author  <a href="mailto:[email protected]">Kohsuke Kawaguchi</a>
+ * @version $Revision: 888884 $, $Date: 2009-12-09 09:36:46 -0800 (Wed, 09 Dec 2009) $
+ * @since 1.5
+ */
+public abstract class Validator {
+
+    /**
+     * Constructor for derived classes.
+     *
+     * <p>
+     * The constructor does nothing.
+     *
+     * <p>
+     * Derived classes must create {@link Validator} objects that have
+     * <tt>null</tt> {@link ErrorHandler} and
+     * <tt>null</tt> {@link LSResourceResolver}.
+     */
+    protected Validator() {
+    }
+
+    /**
+     * <p>Reset this <code>Validator</code> to its original configuration.</p>
+     *
+     * <p><code>Validator</code> is reset to the same state as when it was created with
+     * {@link Schema#newValidator()}.
+     * <code>reset()</code> is designed to allow the reuse of existing <code>Validator</code>s
+     * thus saving resources associated with the creation of new <code>Validator</code>s.</p>
+     *
+     * <p>The reset <code>Validator</code> is not guaranteed to have the same {@link LSResourceResolver} or {@link ErrorHandler}
+     * <code>Object</code>s, e.g. {@link Object#equals(Object obj)}.  It is guaranteed to have a functionally equal
+     * <code>LSResourceResolver</code> and <code>ErrorHandler</code>.</p>
+     */
+    public abstract void reset();
+
+    /**
+     * Validates the specified input.
+     *
+     * <p>
+     * This is just a convenience method of:
+     * <pre>
+     * validate(source,null);
+     * </pre>
+     *
+     * @see #setErrorHandler(ErrorHandler)
+     */
+    public void validate(Source source) throws SAXException, IOException {
+        validate(source, null);
+    }
+
+    /**
+     * Validates the specified input and send the augmented validation
+     * result to the specified output.
+     *
+     * <p>
+     * This method places the following restrictions on the types of
+     * the {@link Source}/{@link Result} accepted.
+     *
+     * <h4>{@link Source}/{@link Result} accepted:</h4>
+     * <table border=1>
+     * <thead>
+     *  <tr>
+     *   <td></td>
+     *   <td>{@link javax.xml.transform.sax.SAXSource}</td>
+     *   <td>{@link javax.xml.transform.dom.DOMSource}</td>
+     *   <td>{@link javax.xml.transform.stream.StreamSource}</td>
+     *  </tr>
+     * </thead>
+     * <tbody>
+     *  <tr>
+     *   <td><tt>null</tt></td>
+     *   <td>OK</td>
+     *   <td>OK</td>
+     *   <td>OK</td>
+     *   <td>OK</td>
+     *  </tr>
+     *  <tr>
+     *   <td>{@link javax.xml.transform.sax.SAXResult}</td>
+     *   <td>OK</td>
+     *   <td>Err</td>
+     *   <td>Err</td>
+     *   <td>Err</td>
+     *  </tr>
+     *  <tr>
+     *   <td>{@link javax.xml.transform.dom.DOMResult}</td>
+     *   <td>Err</td>
+     *   <td>OK</td>
+     *   <td>Err</td>
+     *   <td>Err</td>
+     *  </tr>
+     *  <tr>
+     *   <td>{@link javax.xml.transform.stream.StreamResult}</td>
+     *   <td>Err</td>
+     *   <td>Err</td>
+     *   <td>Err</td>
+     *   <td>OK</td>
+     *  </tr>
+     * </tbody>
+     * </table>
+     *
+     * <p>
+     * To validate one {@link Source} into another kind of {@link Result}, use the identity transformer
+     * (see {@link javax.xml.transform.TransformerFactory#newTransformer()}).
+     *
+     * <p>
+     * Errors found during the validation is sent to the specified
+     * {@link ErrorHandler}.
+     *
+     * <p>
+     * If a document is valid, or if a document contains some errors
+     * but none of them were fatal and the {@link ErrorHandler} didn't
+     * throw any exception, then the method returns normally.
+     *
+     * @param source
+     *      XML to be validated. Must not be null.
+     *
+     * @param result
+     *      The {@link Result} object that receives (possibly augmented)
+     *      XML. This parameter can be null if the caller is not interested
+     *      in it.
+     *
+     *      Note that when a {@link javax.xml.transform.dom.DOMResult} is used,
+     *      a validator might just pass the same DOM node from
+     *      {@link javax.xml.transform.dom.DOMSource} to
+     *      {@link javax.xml.transform.dom.DOMResult}
+     *      (in which case <tt>source.getNode()==result.getNode()</tt>),
+     *      it might copy the entire DOM tree, or it might alter the
+     *      node given by the source.
+     *
+     * @throws IllegalArgumentException
+     *      If the {@link Result} type doesn't match the {@link Source} type,
+     *      or if the specified source is not a
+     *      {@link javax.xml.transform.sax.SAXSource},
+     *      {@link javax.xml.transform.dom.DOMSource} or
+     *      {@link javax.xml.transform.stream.StreamSource}.
+     *
+     * @throws SAXException
+     *      If the {@link ErrorHandler} throws a {@link SAXException} or
+     *      if a fatal error is found and the {@link ErrorHandler} returns
+     *      normally.
+     *
+     * @throws IOException
+     *      If the validator is processing a
+     *      {@link javax.xml.transform.sax.SAXSource} and the
+     *      underlying {@link org.xml.sax.XMLReader} throws an
+     *      {@link IOException}.
+     *
+     * @throws NullPointerException
+     *      If the <tt>source</tt> parameter is null.
+     *
+     * @see #validate(Source)
+     */
+    public abstract void validate(Source source, Result result) throws SAXException, IOException;
+
+    /**
+     * Sets the {@link ErrorHandler} to receive errors encountered
+     * during the <code>validate</code> method invocation.
+     *
+     * <p>
+     * Error handler can be used to customize the error handling process
+     * during a validation. When an {@link ErrorHandler} is set,
+     * errors found during the validation will be first sent
+     * to the {@link ErrorHandler}.
+     *
+     * <p>
+     * The error handler can abort further validation immediately
+     * by throwing {@link SAXException} from the handler. Or for example
+     * it can print an error to the screen and try to continue the
+     * validation by returning normally from the {@link ErrorHandler}
+     *
+     * <p>
+     * If any {@link Throwable} is thrown from an {@link ErrorHandler},
+     * the caller of the <code>validate</code> method will be thrown
+     * the same {@link Throwable} object.
+     *
+     * <p>
+     * {@link Validator} is not allowed to
+     * throw {@link SAXException} without first reporting it to
+     * {@link ErrorHandler}.
+     *
+     * <p>
+     * When the {@link ErrorHandler} is null, the implementation will
+     * behave as if the following {@link ErrorHandler} is set:
+     * <pre>
+     * class DraconianErrorHandler implements {@link ErrorHandler} {
+     *     public void fatalError( {@link org.xml.sax.SAXParseException} e ) throws {@link SAXException} {
+     *         throw e;
+     *     }
+     *     public void error( {@link org.xml.sax.SAXParseException} e ) throws {@link SAXException} {
+     *         throw e;
+     *     }
+     *     public void warning( {@link org.xml.sax.SAXParseException} e ) throws {@link SAXException} {
+     *         // noop
+     *     }
+     * }
+     * </pre>
+     *
+     * <p>
+     * When a new {@link Validator} object is created, initially
+     * this field is set to null.
+     *
+     * @param   errorHandler
+     *      A new error handler to be set. This parameter can be null.
+     */
+    public abstract void setErrorHandler(ErrorHandler errorHandler);
+
+    /**
+     * Gets the current {@link ErrorHandler} set to this {@link Validator}.
+     *
+     * @return
+     *      This method returns the object that was last set through
+     *      the {@link #setErrorHandler(ErrorHandler)} method, or null
+     *      if that method has never been called since this {@link Validator}
+     *      has created.
+     *
+     * @see #setErrorHandler(ErrorHandler)
+     */
+    public abstract ErrorHandler getErrorHandler();
+
+    /**
+     * Sets the {@link LSResourceResolver} to customize
+     * resource resolution while in a validation episode.
+     *
+     * <p>
+     * {@link Validator} uses a {@link LSResourceResolver}
+     * when it needs to locate external resources while a validation,
+     * although exactly what constitutes "locating external resources" is
+     * up to each schema language.
+     *
+     * <p>
+     * When the {@link LSResourceResolver} is null, the implementation will
+     * behave as if the following {@link LSResourceResolver} is set:
+     * <pre>
+     * class DumbLSResourceResolver implements {@link LSResourceResolver} {
+     *     public {@link org.w3c.dom.ls.LSInput} resolveResource(
+     *         String publicId, String systemId, String baseURI) {
+     *
+     *         return null; // always return null
+     *     }
+     * }
+     * </pre>
+     *
+     * <p>
+     * If a {@link LSResourceResolver} throws a {@link RuntimeException}
+     *  (or instances of its derived classes),
+     * then the {@link Validator} will abort the parsing and
+     * the caller of the <code>validate</code> method will receive
+     * the same {@link RuntimeException}.
+     *
+     * <p>
+     * When a new {@link Validator} object is created, initially
+     * this field is set to null.
+     *
+     * @param   resourceResolver
+     *      A new resource resolver to be set. This parameter can be null.
+     */
+    public abstract void setResourceResolver(LSResourceResolver resourceResolver);
+
+    /**
+     * Gets the current {@link LSResourceResolver} set to this {@link Validator}.
+     *
+     * @return
+     *      This method returns the object that was last set through
+     *      the {@link #setResourceResolver(LSResourceResolver)} method, or null
+     *      if that method has never been called since this {@link Validator}
+     *      has created.
+     *
+     * @see #setErrorHandler(ErrorHandler)
+     */
+    public abstract LSResourceResolver getResourceResolver();
+
+
+
+    /**
+     * Look up the value of a feature flag.
+     *
+     * <p>The feature name is any fully-qualified URI.  It is
+     * possible for a {@link Validator} to recognize a feature name but
+     * temporarily be unable to return its value.
+     * Some feature values may be available only in specific
+     * contexts, such as before, during, or after a validation.
+     *
+     * <p>Implementors are free (and encouraged) to invent their own features,
+     * using names built on their own URIs.</p>
+     *
+     * @param name The feature name, which is a non-null fully-qualified URI.
+     * @return The current value of the feature (true or false).
+     * @exception org.xml.sax.SAXNotRecognizedException If the feature
+     *            value can't be assigned or retrieved.
+     * @exception org.xml.sax.SAXNotSupportedException When the
+     *            {@link Validator} recognizes the feature name but
+     *            cannot determine its value at this time.
+     * @throws NullPointerException
+     *          When the name parameter is null.
+     * @see #setFeature(String, boolean)
+     */
+    public boolean getFeature(String name) throws SAXNotRecognizedException, SAXNotSupportedException {
+        if (name == null) {
+            throw new NullPointerException("name == null");
+        }
+        throw new SAXNotRecognizedException(name);
+    }
+
+    /**
+     * Set the value of a feature flag.
+     *
+     * <p>
+     * Feature can be used to control the way a {@link Validator}
+     * parses schemas, although {@link Validator}s are not required
+     * to recognize any specific property names.</p>
+     *
+     * <p>The feature name is any fully-qualified URI.  It is
+     * possible for a {@link Validator} to expose a feature value but
+     * to be unable to change the current value.
+     * Some feature values may be immutable or mutable only
+     * in specific contexts, such as before, during, or after
+     * a validation.</p>
+     *
+     * @param name The feature name, which is a non-null fully-qualified URI.
+     * @param value The requested value of the feature (true or false).
+     *
+     * @exception org.xml.sax.SAXNotRecognizedException If the feature
+     *            value can't be assigned or retrieved.
+     * @exception org.xml.sax.SAXNotSupportedException When the
+     *            {@link Validator} recognizes the feature name but
+     *            cannot set the requested value.
+     * @throws NullPointerException
+     *          When the name parameter is null.
+     *
+     * @see #getFeature(String)
+     */
+    public void setFeature(String name, boolean value) throws SAXNotRecognizedException, SAXNotSupportedException {
+        if (name == null) {
+            throw new NullPointerException("name == null");
+        }
+        throw new SAXNotRecognizedException(name);
+    }
+
+    /**
+     * Set the value of a property.
+     *
+     * <p>The property name is any fully-qualified URI.  It is
+     * possible for a {@link Validator} to recognize a property name but
+     * to be unable to change the current value.
+     * Some property values may be immutable or mutable only
+     * in specific contexts, such as before, during, or after
+     * a validation.</p>
+     *
+     * <p>{@link Validator}s are not required to recognize setting
+     * any specific property names.</p>
+     *
+     * @param name The property name, which is a non-null fully-qualified URI.
+     * @param object The requested value for the property.
+     * @exception org.xml.sax.SAXNotRecognizedException If the property
+     *            value can't be assigned or retrieved.
+     * @exception org.xml.sax.SAXNotSupportedException When the
+     *            {@link Validator} recognizes the property name but
+     *            cannot set the requested value.
+     * @throws NullPointerException
+     *          When the name parameter is null.
+     */
+    public void setProperty(String name, Object object) throws SAXNotRecognizedException, SAXNotSupportedException {
+        if (name == null) {
+            throw new NullPointerException("name == null");
+        }
+        throw new SAXNotRecognizedException(name);
+    }
+
+    /**
+     * Look up the value of a property.
+     *
+     * <p>The property name is any fully-qualified URI.  It is
+     * possible for a {@link Validator} to recognize a property name but
+     * temporarily be unable to return its value.
+     * Some property values may be available only in specific
+     * contexts, such as before, during, or after a validation.</p>
+     *
+     * <p>{@link Validator}s are not required to recognize any specific
+     * property names.</p>
+     *
+     * <p>Implementors are free (and encouraged) to invent their own properties,
+     * using names built on their own URIs.</p>
+     *
+     * @param name The property name, which is a non-null fully-qualified URI.
+     * @return The current value of the property.
+     * @exception org.xml.sax.SAXNotRecognizedException If the property
+     *            value can't be assigned or retrieved.
+     * @exception org.xml.sax.SAXNotSupportedException When the
+     *            XMLReader recognizes the property name but
+     *            cannot determine its value at this time.
+     * @throws NullPointerException
+     *          When the name parameter is null.
+     * @see #setProperty(String, Object)
+     */
+    public Object getProperty(String name) throws SAXNotRecognizedException, SAXNotSupportedException {
+        if (name == null) {
+            throw new NullPointerException("name == null");
+        }
+        throw new SAXNotRecognizedException(name);
+    }
+}
diff --git a/javax/xml/validation/ValidatorHandler.java b/javax/xml/validation/ValidatorHandler.java
new file mode 100644
index 0000000..2b621ff
--- /dev/null
+++ b/javax/xml/validation/ValidatorHandler.java
@@ -0,0 +1,454 @@
+/*
+ * 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.
+ */
+// $Id: ValidatorHandler.java 446598 2006-09-15 12:55:40Z jeremias $
+
+package javax.xml.validation;
+
+import org.w3c.dom.ls.LSResourceResolver;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.SAXNotRecognizedException;
+import org.xml.sax.SAXNotSupportedException;
+
+/**
+ * Streaming validator that works on SAX stream.
+ *
+ * <p>
+ * A {@link ValidatorHandler} object is a thread-unsafe, non-reentrant object.
+ * In other words, it is the application's responsibility to make
+ * sure that one {@link ValidatorHandler} object is not used from
+ * more than one thread at any given time.
+ *
+ * <p>
+ * {@link ValidatorHandler} checks if the SAX events follow
+ * the set of constraints described in the associated {@link Schema},
+ * and additionally it may modify the SAX events (for example
+ * by adding default values, etc.)
+ *
+ * <p>
+ * {@link ValidatorHandler} extends from {@link ContentHandler},
+ * but it refines the underlying {@link ContentHandler} in
+ * the following way:
+ * <ol>
+ *  <li>startElement/endElement events must receive non-null String
+ *      for <code>uri</code>, <code>localName</code>, and <code>qname</code>,
+ *      even though SAX allows some of them to be null.
+ *      Similarly, the user-specified {@link ContentHandler} will receive non-null
+ *      Strings for all three parameters.
+ *
+ *  <li>Applications must ensure that {@link ValidatorHandler}'s
+ *      {@link ContentHandler#startPrefixMapping(String,String)} and
+ *      {@link ContentHandler#endPrefixMapping(String)} are invoked
+ *      properly. Similarly, the user-specified {@link ContentHandler}
+ *      will receive startPrefixMapping/endPrefixMapping events.
+ *      If the {@link ValidatorHandler} introduces additional namespace
+ *      bindings, the user-specified {@link ContentHandler} will receive
+ *      additional startPrefixMapping/endPrefixMapping events.
+ *
+ *  <li>{@link org.xml.sax.Attributes} for the
+ *      {@link ContentHandler#startElement(String,String,String,Attributes)} method
+ *      may or may not include xmlns* attributes.
+ * </ol>
+ *
+ * <p>
+ * A {@link ValidatorHandler} is automatically reset every time
+ * the startDocument method is invoked.
+ *
+ * <h2>Recognized Properties and Features</h2>
+ * <p>
+ * This spec defines the following feature that must be recognized
+ * by all {@link ValidatorHandler} implementations.
+ *
+ * <h3><code>http://xml.org/sax/features/namespace-prefixes</code></h3>
+ * <p>
+ * This feature controls how a {@link ValidatorHandler} introduces
+ * namespace bindings that were not present in the original SAX event
+ * stream.
+ * When this feature is set to true, it must make
+ * sure that the user's {@link ContentHandler} will see
+ * the corresponding <code>xmlns*</code> attribute in
+ * the {@link org.xml.sax.Attributes} object of the
+ * {@link ContentHandler#startElement(String,String,String,Attributes)}
+ * callback. Otherwise, <code>xmlns*</code> attributes must not be
+ * added to {@link org.xml.sax.Attributes} that's passed to the
+ * user-specified {@link ContentHandler}.
+ * <p>
+ * (Note that regardless of this switch, namespace bindings are
+ * always notified to applications through
+ * {@link ContentHandler#startPrefixMapping(String,String)} and
+ * {@link ContentHandler#endPrefixMapping(String)} methods of the
+ * {@link ContentHandler} specified by the user.)
+ *
+ * <p>
+ * Note that this feature does <em>NOT</em> affect the way
+ * a {@link ValidatorHandler} receives SAX events. It merely
+ * changes the way it augments SAX events.
+ *
+ * <p>This feature is set to <code>false</code> by default.</p>
+ *
+ * @author  <a href="mailto:[email protected]">Kohsuke Kawaguchi</a>
+ * @version $Revision: 446598 $, $Date: 2006-09-15 05:55:40 -0700 (Fri, 15 Sep 2006) $
+ * @since 1.5
+ */
+public abstract class ValidatorHandler implements ContentHandler {
+
+    /**
+     * Constructor for derived classes.
+     *
+     * <p>
+     * The constructor does nothing.
+     *
+     * <p>
+     * Derived classes must create {@link ValidatorHandler} objects that have
+     * <tt>null</tt> {@link ErrorHandler} and
+     * <tt>null</tt> {@link LSResourceResolver}.
+     */
+    protected ValidatorHandler() {
+    }
+
+    /**
+     * Sets the {@link ContentHandler} which receives
+     * the augmented validation result.
+     *
+     * <p>
+     * When a {@link ContentHandler} is specified, a
+     * {@link ValidatorHandler} will work as a filter
+     * and basically copy the incoming events to the
+     * specified {@link ContentHandler}.
+     *
+     * <p>
+     * In doing so, a {@link ValidatorHandler} may modify
+     * the events, for example by adding defaulted attributes.
+     *
+     * <p>
+     * A {@link ValidatorHandler} may buffer events to certain
+     * extent, but to allow {@link ValidatorHandler} to be used
+     * by a parser, the following requirement has to be met.
+     *
+     * <ol>
+     *  <li>When
+     *      {@link ContentHandler#startElement(String, String, String, Attributes)},
+     *      {@link ContentHandler#endElement(String, String, String)},
+     *      {@link ContentHandler#startDocument()}, or
+     *      {@link ContentHandler#endDocument()}
+     *      are invoked on a {@link ValidatorHandler},
+     *      the same method on the user-specified {@link ContentHandler}
+     *      must be invoked for the same event before the callback
+     *      returns.
+     *  <li>{@link ValidatorHandler} may not introduce new elements that
+     *      were not present in the input.
+     *
+     *  <li>{@link ValidatorHandler} may not remove attributes that were
+     *      present in the input.
+     * </ol>
+     *
+     * <p>
+     * When a callback method on the specified {@link ContentHandler}
+     * throws an exception, the same exception object must be thrown
+     * from the {@link ValidatorHandler}. The {@link ErrorHandler}
+     * should not be notified of such an exception.
+     *
+     * <p>
+     * This method can be called even during a middle of a validation.
+     *
+     * @param receiver
+     *      A {@link ContentHandler} or a null value.
+     */
+    public abstract void setContentHandler(ContentHandler receiver);
+
+    /**
+     * Gets the {@link ContentHandler} which receives the
+     * augmented validation result.
+     *
+     * @return
+     *      This method returns the object that was last set through
+     *      the {@link #getContentHandler()} method, or null
+     *      if that method has never been called since this {@link ValidatorHandler}
+     *      has created.
+     *
+     * @see #setContentHandler(ContentHandler)
+     */
+    public abstract ContentHandler getContentHandler();
+
+    /**
+     * Sets the {@link ErrorHandler} to receive errors encountered
+     * during the validation.
+     *
+     * <p>
+     * Error handler can be used to customize the error handling process
+     * during a validation. When an {@link ErrorHandler} is set,
+     * errors found during the validation will be first sent
+     * to the {@link ErrorHandler}.
+     *
+     * <p>
+     * The error handler can abort further validation immediately
+     * by throwing {@link org.xml.sax.SAXException} from the handler. Or for example
+     * it can print an error to the screen and try to continue the
+     * validation by returning normally from the {@link ErrorHandler}
+     *
+     * <p>
+     * If any {@link Throwable} is thrown from an {@link ErrorHandler},
+     * the same {@link Throwable} object will be thrown toward the
+     * root of the call stack.
+     *
+     * <p>
+     * {@link ValidatorHandler} is not allowed to
+     * throw {@link org.xml.sax.SAXException} without first reporting it to
+     * {@link ErrorHandler}.
+     *
+     * <p>
+     * When the {@link ErrorHandler} is null, the implementation will
+     * behave as if the following {@link ErrorHandler} is set:
+     * <pre>
+     * class DraconianErrorHandler implements {@link ErrorHandler} {
+     *     public void fatalError( {@link org.xml.sax.SAXParseException} e ) throws {@link org.xml.sax.SAXException} {
+     *         throw e;
+     *     }
+     *     public void error( {@link org.xml.sax.SAXParseException} e ) throws {@link org.xml.sax.SAXException} {
+     *         throw e;
+     *     }
+     *     public void warning( {@link org.xml.sax.SAXParseException} e ) throws {@link org.xml.sax.SAXException} {
+     *         // noop
+     *     }
+     * }
+     * </pre>
+     *
+     * <p>
+     * When a new {@link ValidatorHandler} object is created, initially
+     * this field is set to null.
+     *
+     * @param   errorHandler
+     *      A new error handler to be set. This parameter can be null.
+     */
+    public abstract void setErrorHandler(ErrorHandler errorHandler);
+
+    /**
+     * Gets the current {@link ErrorHandler} set to this {@link ValidatorHandler}.
+     *
+     * @return
+     *      This method returns the object that was last set through
+     *      the {@link #setErrorHandler(ErrorHandler)} method, or null
+     *      if that method has never been called since this {@link ValidatorHandler}
+     *      has created.
+     *
+     * @see #setErrorHandler(ErrorHandler)
+     */
+    public abstract ErrorHandler getErrorHandler();
+
+    /**
+     * Sets the {@link LSResourceResolver} to customize
+     * resource resolution while in a validation episode.
+     *
+     * <p>
+     * {@link ValidatorHandler} uses a {@link LSResourceResolver}
+     * when it needs to locate external resources while a validation,
+     * although exactly what constitutes "locating external resources" is
+     * up to each schema language.
+     *
+     * <p>
+     * When the {@link LSResourceResolver} is null, the implementation will
+     * behave as if the following {@link LSResourceResolver} is set:
+     * <pre>
+     * class DumbLSResourceResolver implements {@link LSResourceResolver} {
+     *     public {@link org.w3c.dom.ls.LSInput} resolveResource(
+     *         String publicId, String systemId, String baseURI) {
+     *
+     *         return null; // always return null
+     *     }
+     * }
+     * </pre>
+     *
+     * <p>
+     * If a {@link LSResourceResolver} throws a {@link RuntimeException}
+     *  (or instances of its derived classes),
+     * then the {@link ValidatorHandler} will abort the parsing and
+     * the caller of the <code>validate</code> method will receive
+     * the same {@link RuntimeException}.
+     *
+     * <p>
+     * When a new {@link ValidatorHandler} object is created, initially
+     * this field is set to null.
+     *
+     * @param   resourceResolver
+     *      A new resource resolver to be set. This parameter can be null.
+     */
+    public abstract void setResourceResolver(LSResourceResolver resourceResolver);
+
+    /**
+     * Gets the current {@link LSResourceResolver} set to this {@link ValidatorHandler}.
+     *
+     * @return
+     *      This method returns the object that was last set through
+     *      the {@link #setResourceResolver(LSResourceResolver)} method, or null
+     *      if that method has never been called since this {@link ValidatorHandler}
+     *      has created.
+     *
+     * @see #setErrorHandler(ErrorHandler)
+     */
+    public abstract LSResourceResolver getResourceResolver();
+
+    /**
+     * Obtains the {@link TypeInfoProvider} implementation of this
+     * {@link ValidatorHandler}.
+     *
+     * <p>
+     * The obtained {@link TypeInfoProvider} can be queried during a parse
+     * to access the type information determined by the validator.
+     *
+     * <p>
+     * Some schema languages do not define the notion of type,
+     * for those languages, this method may not be supported.
+     * However, to be compliant with this specification, implementations
+     * for W3C XML Schema 1.0 must support this operation.
+     *
+     * @return
+     *      null if the validator / schema language does not support
+     *      the notion of {@link org.w3c.dom.TypeInfo}.
+     *      Otherwise a non-null valid {@link TypeInfoProvider}.
+     */
+    public abstract TypeInfoProvider getTypeInfoProvider();
+
+
+    /**
+     * Look up the value of a feature flag.
+     *
+     * <p>The feature name is any fully-qualified URI.  It is
+     * possible for a {@link ValidatorHandler} to recognize a feature name but
+     * temporarily be unable to return its value.
+     * Some feature values may be available only in specific
+     * contexts, such as before, during, or after a validation.
+     *
+     * <p>Implementors are free (and encouraged) to invent their own features,
+     * using names built on their own URIs.</p>
+     *
+     * @param name The feature name, which is a non-null fully-qualified URI.
+     * @return The current value of the feature (true or false).
+     * @exception org.xml.sax.SAXNotRecognizedException If the feature
+     *            value can't be assigned or retrieved.
+     * @exception org.xml.sax.SAXNotSupportedException When the
+     *            {@link ValidatorHandler} recognizes the feature name but
+     *            cannot determine its value at this time.
+     * @throws NullPointerException
+     *          When the name parameter is null.
+     * @see #setFeature(String, boolean)
+     */
+    public boolean getFeature(String name) throws SAXNotRecognizedException, SAXNotSupportedException {
+        if (name == null) {
+            throw new NullPointerException("name == null");
+        }
+        throw new SAXNotRecognizedException(name);
+    }
+
+    /**
+     * Set the value of a feature flag.
+     *
+     * <p>
+     * Feature can be used to control the way a {@link ValidatorHandler}
+     * parses schemas, although {@link ValidatorHandler}s are not required
+     * to recognize any specific property names.</p>
+     *
+     * <p>The feature name is any fully-qualified URI.  It is
+     * possible for a {@link ValidatorHandler} to expose a feature value but
+     * to be unable to change the current value.
+     * Some feature values may be immutable or mutable only
+     * in specific contexts, such as before, during, or after
+     * a validation.</p>
+     *
+     * @param name The feature name, which is a non-null fully-qualified URI.
+     * @param value The requested value of the feature (true or false).
+     *
+     * @exception org.xml.sax.SAXNotRecognizedException If the feature
+     *            value can't be assigned or retrieved.
+     * @exception org.xml.sax.SAXNotSupportedException When the
+     *            {@link ValidatorHandler} recognizes the feature name but
+     *            cannot set the requested value.
+     * @throws NullPointerException
+     *          When the name parameter is null.
+     *
+     * @see #getFeature(String)
+     */
+    public void setFeature(String name, boolean value) throws SAXNotRecognizedException, SAXNotSupportedException {
+        if (name == null) {
+            throw new NullPointerException("name == null");
+        }
+        throw new SAXNotRecognizedException(name);
+    }
+
+    /**
+     * Set the value of a property.
+     *
+     * <p>The property name is any fully-qualified URI.  It is
+     * possible for a {@link ValidatorHandler} to recognize a property name but
+     * to be unable to change the current value.
+     * Some property values may be immutable or mutable only
+     * in specific contexts, such as before, during, or after
+     * a validation.</p>
+     *
+     * <p>{@link ValidatorHandler}s are not required to recognize setting
+     * any specific property names.</p>
+     *
+     * @param name The property name, which is a non-null fully-qualified URI.
+     * @param object The requested value for the property.
+     *
+     * @exception org.xml.sax.SAXNotRecognizedException If the property
+     *            value can't be assigned or retrieved.
+     * @exception org.xml.sax.SAXNotSupportedException When the
+     *            {@link ValidatorHandler} recognizes the property name but
+     *            cannot set the requested value.
+     * @throws NullPointerException
+     *          When the name parameter is null.
+     */
+    public void setProperty(String name, Object object) throws SAXNotRecognizedException, SAXNotSupportedException {
+        if (name == null) {
+            throw new NullPointerException("name == null");
+        }
+        throw new SAXNotRecognizedException(name);
+    }
+
+    /**
+     * Look up the value of a property.
+     *
+     * <p>The property name is any fully-qualified URI.  It is
+     * possible for a {@link ValidatorHandler} to recognize a property name but
+     * temporarily be unable to return its value.
+     * Some property values may be available only in specific
+     * contexts, such as before, during, or after a validation.</p>
+     *
+     * <p>{@link ValidatorHandler}s are not required to recognize any specific
+     * property names.</p>
+     *
+     * <p>Implementors are free (and encouraged) to invent their own properties,
+     * using names built on their own URIs.</p>
+     *
+     * @param name The property name, which is a non-null fully-qualified URI.
+     * @return The current value of the property.
+     * @exception org.xml.sax.SAXNotRecognizedException If the property
+     *            value can't be assigned or retrieved.
+     * @exception org.xml.sax.SAXNotSupportedException When the
+     *            XMLReader recognizes the property name but
+     *            cannot determine its value at this time.
+     * @throws NullPointerException
+     *          When the name parameter is null.
+     * @see #setProperty(String, Object)
+     */
+    public Object getProperty(String name) throws SAXNotRecognizedException, SAXNotSupportedException {
+        if (name == null) {
+            throw new NullPointerException("name == null");
+        }
+        throw new SAXNotRecognizedException(name);
+    }
+}
diff --git a/javax/xml/xpath/XPath.java b/javax/xml/xpath/XPath.java
new file mode 100644
index 0000000..c027b58
--- /dev/null
+++ b/javax/xml/xpath/XPath.java
@@ -0,0 +1,299 @@
+/*
+ * 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.
+ */
+// $Id: XPath.java 569998 2007-08-27 04:40:02Z mrglavas $
+
+package javax.xml.xpath;
+
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.namespace.QName;
+import org.xml.sax.InputSource;
+
+/**
+ * <p><code>XPath</code> provides access to the XPath evaluation environment and expressions.</p>
+ *
+ * <table id="XPath-evaluation" border="1" cellpadding="2">
+ *   <thead>
+ *     <tr>
+ *       <th colspan="2">Evaluation of XPath Expressions.</th>
+ *     </tr>
+ *   </thead>
+ *   <tbody>
+ *     <tr>
+ *       <td>context</td>
+ *       <td>
+ *         If a request is made to evaluate the expression in the absence
+ * of a context item, an empty document node will be used for the context.
+ * For the purposes of evaluating XPath expressions, a DocumentFragment
+ * is treated like a Document node.
+ *      </td>
+ *    </tr>
+ *    <tr>
+ *      <td>variables</td>
+ *      <td>
+ *        If the expression contains a variable reference, its value will be found through the {@link XPathVariableResolver}
+ *        set with {@link #setXPathVariableResolver(XPathVariableResolver resolver)}.
+ *        An {@link XPathExpressionException} is raised if the variable resolver is undefined or
+ *        the resolver returns <code>null</code> for the variable.
+ *        The value of a variable must be immutable through the course of any single evaluation.</p>
+ *      </td>
+ *    </tr>
+ *    <tr>
+ *      <td>functions</td>
+ *      <td>
+ *        If the expression contains a function reference, the function will be found through the {@link XPathFunctionResolver}
+ *        set with {@link #setXPathFunctionResolver(XPathFunctionResolver resolver)}.
+ *        An {@link XPathExpressionException} is raised if the function resolver is undefined or
+ *        the function resolver returns <code>null</code> for the function.</p>
+ *      </td>
+ *    </tr>
+ *    <tr>
+ *      <td>QNames</td>
+ *      <td>
+ *        QNames in the expression are resolved against the XPath namespace context
+ *        set with {@link #setNamespaceContext(NamespaceContext nsContext)}.
+ *      </td>
+ *    </tr>
+ *    <tr>
+ *      <td>result</td>
+ *      <td>
+ *        This result of evaluating an expression is converted to an instance of the desired return type.
+ *        Valid return types are defined in {@link XPathConstants}.
+ *        Conversion to the return type follows XPath conversion rules.</p>
+ *      </td>
+ *    </tr>
+ * </table>
+ *
+ * @author  <a href="[email protected]">Norman Walsh</a>
+ * @author  <a href="[email protected]">Jeff Suttor</a>
+ * @version $Revision: 569998 $, $Date: 2007-08-26 21:40:02 -0700 (Sun, 26 Aug 2007) $
+ * @see <a href="http://www.w3.org/TR/xpath">XML Path Language (XPath) Version 1.0</a>
+ * @since 1.5
+ */
+public interface XPath {
+
+    /**
+     * <p>Reset this <code>XPath</code> to its original configuration.</p>
+     *
+     * <p><code>XPath</code> is reset to the same state as when it was created with
+     * {@link XPathFactory#newXPath()}.
+     * <code>reset()</code> is designed to allow the reuse of existing <code>XPath</code>s
+     * thus saving resources associated with the creation of new <code>XPath</code>s.</p>
+     *
+     * <p>The reset <code>XPath</code> is not guaranteed to have the same {@link XPathFunctionResolver}, {@link XPathVariableResolver}
+     * or {@link NamespaceContext} <code>Object</code>s, e.g. {@link Object#equals(Object obj)}.
+     * It is guaranteed to have a functionally equal <code>XPathFunctionResolver</code>, <code>XPathVariableResolver</code>
+     * and <code>NamespaceContext</code>.</p>
+     */
+    public void reset();
+
+    /**
+     * <p>Establish a variable resolver.</p>
+     *
+     * <p>A <code>NullPointerException</code> is thrown if <code>resolver</code> is <code>null</code>.</p>
+     *
+     * @param resolver Variable resolver.
+     *
+     *  @throws NullPointerException If <code>resolver</code> is <code>null</code>.
+     */
+    public void setXPathVariableResolver(XPathVariableResolver resolver);
+
+    /**
+       * <p>Return the current variable resolver.</p>
+       *
+       * <p><code>null</code> is returned in no variable resolver is in effect.</p>
+       *
+       * @return Current variable resolver.
+       */
+    public XPathVariableResolver getXPathVariableResolver();
+
+    /**
+       * <p>Establish a function resolver.</p>
+       *
+       * <p>A <code>NullPointerException</code> is thrown if <code>resolver</code> is <code>null</code>.</p>
+       *
+       * @param resolver XPath function resolver.
+       *
+       * @throws NullPointerException If <code>resolver</code> is <code>null</code>.
+       */
+    public void setXPathFunctionResolver(XPathFunctionResolver resolver);
+
+    /**
+       * <p>Return the current function resolver.</p>
+       *
+       * <p><code>null</code> is returned in no function resolver is in effect.</p>
+       *
+       * @return Current function resolver.
+       */
+    public XPathFunctionResolver getXPathFunctionResolver();
+
+    /**
+       * <p>Establish a namespace context.</p>
+       *
+       * <p>A <code>NullPointerException</code> is thrown if <code>nsContext</code> is <code>null</code>.</p>
+       *
+       * @param nsContext Namespace context to use.
+       *
+       * @throws NullPointerException If <code>nsContext</code> is <code>null</code>.
+       */
+    public void setNamespaceContext(NamespaceContext nsContext);
+
+    /**
+       * <p>Return the current namespace context.</p>
+       *
+       * <p><code>null</code> is returned in no namespace context is in effect.</p>
+       *
+       * @return Current Namespace context.
+       */
+    public NamespaceContext getNamespaceContext();
+
+    /**
+       * <p>Compile an XPath expression for later evaluation.</p>
+       *
+       * <p>If <code>expression</code> contains any {@link XPathFunction}s,
+       * they must be available via the {@link XPathFunctionResolver}.
+       * An {@link XPathExpressionException} will be thrown if the <code>XPathFunction</code>
+       * cannot be resolved with the <code>XPathFunctionResolver</code>.</p>
+       *
+       * <p>If <code>expression</code> is <code>null</code>, a <code>NullPointerException</code> is thrown.</p>
+       *
+       * @param expression The XPath expression.
+       *
+       * @return Compiled XPath expression.
+
+       * @throws XPathExpressionException If <code>expression</code> cannot be compiled.
+       * @throws NullPointerException If <code>expression</code> is <code>null</code>.
+       */
+    public XPathExpression compile(String expression)
+        throws XPathExpressionException;
+
+    /**
+     * <p>Evaluate an <code>XPath</code> expression in the specified context and return the result as the specified type.</p>
+     *
+     * <p>See <a href="#XPath-evaluation">Evaluation of XPath Expressions</a> for context item evaluation,
+     * variable, function and <code>QName</code> resolution and return type conversion.</p>
+     *
+     * <p>If <code>returnType</code> is not one of the types defined in {@link XPathConstants} (
+     * {@link XPathConstants#NUMBER NUMBER},
+     * {@link XPathConstants#STRING STRING},
+     * {@link XPathConstants#BOOLEAN BOOLEAN},
+     * {@link XPathConstants#NODE NODE} or
+     * {@link XPathConstants#NODESET NODESET})
+     * then an <code>IllegalArgumentException</code> is thrown.</p>
+     *
+     * <p>If a <code>null</code> value is provided for
+     * <code>item</code>, an empty document will be used for the
+     * context.
+     * If <code>expression</code> or <code>returnType</code> is <code>null</code>, then a
+     * <code>NullPointerException</code> is thrown.</p>
+     *
+     * @param expression The XPath expression.
+     * @param item The starting context (node or node list, for example).
+     * @param returnType The desired return type.
+     *
+     * @return Result of evaluating an XPath expression as an <code>Object</code> of <code>returnType</code>.
+     *
+     * @throws XPathExpressionException If <code>expression</code> cannot be evaluated.
+     * @throws IllegalArgumentException If <code>returnType</code> is not one of the types defined in {@link XPathConstants}.
+     * @throws NullPointerException If <code>expression</code> or <code>returnType</code> is <code>null</code>.
+     */
+    public Object evaluate(String expression, Object item, QName returnType)
+        throws XPathExpressionException;
+
+    /**
+     * <p>Evaluate an XPath expression in the specified context and return the result as a <code>String</code>.</p>
+     *
+     * <p>This method calls {@link #evaluate(String expression, Object item, QName returnType)} with a <code>returnType</code> of
+     * {@link XPathConstants#STRING}.</p>
+     *
+     * <p>See <a href="#XPath-evaluation">Evaluation of XPath Expressions</a> for context item evaluation,
+     * variable, function and QName resolution and return type conversion.</p>
+     *
+     * <p>If a <code>null</code> value is provided for
+     * <code>item</code>, an empty document will be used for the
+     * context.
+     * If <code>expression</code> is <code>null</code>, then a <code>NullPointerException</code> is thrown.</p>
+     *
+     * @param expression The XPath expression.
+     * @param item The starting context (node or node list, for example).
+     *
+     * @return The <code>String</code> that is the result of evaluating the expression and
+     *   converting the result to a <code>String</code>.
+     *
+     * @throws XPathExpressionException If <code>expression</code> cannot be evaluated.
+     * @throws NullPointerException If <code>expression</code> is <code>null</code>.
+     */
+    public String evaluate(String expression, Object item)
+        throws XPathExpressionException;
+
+    /**
+     * <p>Evaluate an XPath expression in the context of the specified <code>InputSource</code>
+     * and return the result as the specified type.</p>
+     *
+     * <p>This method builds a data model for the {@link InputSource} and calls
+     * {@link #evaluate(String expression, Object item, QName returnType)} on the resulting document object.</p>
+     *
+     * <p>See <a href="#XPath-evaluation">Evaluation of XPath Expressions</a> for context item evaluation,
+     * variable, function and QName resolution and return type conversion.</p>
+     *
+     * <p>If <code>returnType</code> is not one of the types defined in {@link XPathConstants},
+     * then an <code>IllegalArgumentException</code> is thrown.</p>
+     *
+     * <p>If <code>expression</code>, <code>source</code> or <code>returnType</code> is <code>null</code>,
+     * then a <code>NullPointerException</code> is thrown.</p>
+     *
+     * @param expression The XPath expression.
+     * @param source The input source of the document to evaluate over.
+     * @param returnType The desired return type.
+     *
+     * @return The <code>Object</code> that encapsulates the result of evaluating the expression.
+     *
+     * @throws XPathExpressionException If expression cannot be evaluated.
+     * @throws IllegalArgumentException If <code>returnType</code> is not one of the types defined in {@link XPathConstants}.
+     * @throws NullPointerException If <code>expression</code>, <code>source</code> or <code>returnType</code>
+     *   is <code>null</code>.
+     */
+    public Object evaluate(
+        String expression,
+        InputSource source,
+        QName returnType)
+        throws XPathExpressionException;
+
+    /**
+     * <p>Evaluate an XPath expression in the context of the specified <code>InputSource</code>
+     * and return the result as a <code>String</code>.</p>
+     *
+     * <p>This method calls {@link #evaluate(String expression, InputSource source, QName returnType)} with a
+     * <code>returnType</code> of {@link XPathConstants#STRING}.</p>
+     *
+     * <p>See <a href="#XPath-evaluation">Evaluation of XPath Expressions</a> for context item evaluation,
+     * variable, function and QName resolution and return type conversion.</p>
+     *
+     * <p>If <code>expression</code> or <code>source</code> is <code>null</code>,
+     * then a <code>NullPointerException</code> is thrown.</p>
+     *
+     * @param expression The XPath expression.
+     * @param source The <code>InputSource</code> of the document to evaluate over.
+     *
+     * @return The <code>String</code> that is the result of evaluating the expression and
+     *   converting the result to a <code>String</code>.
+     *
+     * @throws XPathExpressionException If expression cannot be evaluated.
+     * @throws NullPointerException If <code>expression</code> or <code>source</code> is <code>null</code>.
+     */
+    public String evaluate(String expression, InputSource source)
+        throws XPathExpressionException;
+}
diff --git a/javax/xml/xpath/XPathConstants.java b/javax/xml/xpath/XPathConstants.java
new file mode 100644
index 0000000..2ff3622
--- /dev/null
+++ b/javax/xml/xpath/XPathConstants.java
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+// $Id: XPathConstants.java 446598 2006-09-15 12:55:40Z jeremias $
+
+package javax.xml.xpath;
+
+import javax.xml.namespace.QName;
+
+/**
+ * <p>XPath constants.</p>
+ *
+ * @author <a href="mailto:[email protected]">Norman Walsh</a>
+ * @author <a href="mailto:[email protected]">Jeff Suttor</a>
+ * @version $Revision: 446598 $, $Date: 2006-09-15 05:55:40 -0700 (Fri, 15 Sep 2006) $
+ * @see <a href="http://www.w3.org/TR/xpath">XML Path Language (XPath) Version 1.0</a>
+ * @since 1.5
+ */
+public class XPathConstants {
+
+    /**
+     * <p>Private constructor to prevent instantiation.</p>
+     */
+    private XPathConstants() { }
+
+    /**
+     * <p>The XPath 1.0 number data type.</p>
+     *
+     * <p>Maps to Java {@link Double}.</p>
+     */
+    public static final QName NUMBER = new QName("http://www.w3.org/1999/XSL/Transform", "NUMBER");
+
+    /**
+     * <p>The XPath 1.0 string data type.</p>
+     *
+     * <p>Maps to Java {@link String}.</p>
+     */
+    public static final QName STRING = new QName("http://www.w3.org/1999/XSL/Transform", "STRING");
+
+    /**
+     * <p>The XPath 1.0 boolean data type.</p>
+     *
+     * <p>Maps to Java {@link Boolean}.</p>
+     */
+    public static final QName BOOLEAN = new QName("http://www.w3.org/1999/XSL/Transform", "BOOLEAN");
+
+    /**
+     * <p>The XPath 1.0 NodeSet data type.</p>
+     *
+     * <p>Maps to Java {@link org.w3c.dom.NodeList}.</p>
+     */
+    public static final QName NODESET = new QName("http://www.w3.org/1999/XSL/Transform", "NODESET");
+
+    /**
+     * <p>The XPath 1.0 NodeSet data type.
+     *
+     * <p>Maps to Java {@link org.w3c.dom.Node}.</p>
+     */
+    public static final QName NODE = new QName("http://www.w3.org/1999/XSL/Transform", "NODE");
+
+    /**
+     * <p>The URI for the DOM object model, "http://java.sun.com/jaxp/xpath/dom".</p>
+     */
+    public static final String DOM_OBJECT_MODEL = "http://java.sun.com/jaxp/xpath/dom";
+}
diff --git a/javax/xml/xpath/XPathException.java b/javax/xml/xpath/XPathException.java
new file mode 100644
index 0000000..376d477
--- /dev/null
+++ b/javax/xml/xpath/XPathException.java
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+// $Id: XPathException.java 446598 2006-09-15 12:55:40Z jeremias $
+
+package javax.xml.xpath;
+
+import java.io.PrintWriter;
+
+/**
+ * <code>XPathException</code> represents a generic XPath exception.</p>
+ *
+ * @author  <a href="[email protected]">Norman Walsh</a>
+ * @author <a href="mailto:[email protected]">Jeff Suttor</a>
+ * @version $Revision: 446598 $, $Date: 2006-09-15 05:55:40 -0700 (Fri, 15 Sep 2006) $
+ * @since 1.5
+ */
+public class XPathException extends Exception {
+
+    private final Throwable cause;
+
+    /**
+     * <p>Stream Unique Identifier.</p>
+     */
+    private static final long serialVersionUID = -1837080260374986980L;
+
+    /**
+     * <p>Constructs a new <code>XPathException</code> with the specified detail <code>message</code>.</p>
+     *
+     * <p>The <code>cause</code> is not initialized.</p>
+     *
+     * <p>If <code>message</code> is <code>null</code>, then a <code>NullPointerException</code> is thrown.</p>
+     *
+     * @param message The detail message.
+     */
+    public XPathException(String message) {
+        super(message);
+        if (message == null) {
+            throw new NullPointerException("message == null");
+        }
+        this.cause = null;
+    }
+
+    /**
+     * <p>Constructs a new <code>XPathException</code> with the specified <code>cause</code>.</p>
+     *
+     * <p>If <code>cause</code> is <code>null</code>, then a <code>NullPointerException</code> is thrown.</p>
+     *
+     * @param cause The cause.
+     *
+     * @throws NullPointerException if <code>cause</code> is <code>null</code>.
+     */
+    public XPathException(Throwable cause) {
+        super(cause == null ? null : cause.toString());
+        this.cause = cause;
+        if (cause == null) {
+            throw new NullPointerException("cause == null");
+        }
+    }
+
+    public Throwable getCause() {
+        return cause;
+    }
+
+    public void printStackTrace( java.io.PrintStream s ) {
+        if( getCause() != null ) {
+            getCause().printStackTrace(s);
+          s.println("--------------- linked to ------------------");
+        }
+
+        super.printStackTrace(s);
+    }
+
+    public void printStackTrace() {
+        printStackTrace(System.err);
+    }
+
+    public void printStackTrace(PrintWriter s) {
+        if( getCause() != null ) {
+            getCause().printStackTrace(s);
+          s.println("--------------- linked to ------------------");
+        }
+
+        super.printStackTrace(s);
+    }
+}
diff --git a/javax/xml/xpath/XPathExpression.java b/javax/xml/xpath/XPathExpression.java
new file mode 100644
index 0000000..0182d91
--- /dev/null
+++ b/javax/xml/xpath/XPathExpression.java
@@ -0,0 +1,185 @@
+/*
+ * 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.
+ */
+// $Id: XPathExpression.java 446598 2006-09-15 12:55:40Z jeremias $
+
+package javax.xml.xpath;
+
+import javax.xml.namespace.QName;
+import org.xml.sax.InputSource;
+
+/**
+ * <p><code>XPathExpression</code> provides access to compiled XPath expressions.</p>
+ *
+ * <table id="XPathExpression-evaluation" border="1" cellpadding="2">
+ *   <thead>
+ *     <tr>
+ *       <th colspan="2">Evaluation of XPath Expressions.</th>
+ *     </tr>
+ *   </thead>
+ *   <tbody>
+ *     <tr>
+ *       <td>context</td>
+ *       <td>
+ *         If a request is made to evaluate the expression in the absence
+ * of a context item, an empty document node will be used for the context.
+ * For the purposes of evaluating XPath expressions, a DocumentFragment
+ * is treated like a Document node.
+ *      </td>
+ *    </tr>
+ *    <tr>
+ *      <td>variables</td>
+ *      <td>
+ *        If the expression contains a variable reference, its value will be found through the {@link XPathVariableResolver}.
+ *        An {@link XPathExpressionException} is raised if the variable resolver is undefined or
+ *        the resolver returns <code>null</code> for the variable.
+ *        The value of a variable must be immutable through the course of any single evaluation.</p>
+ *      </td>
+ *    </tr>
+ *    <tr>
+ *      <td>functions</td>
+ *      <td>
+ *        If the expression contains a function reference, the function will be found through the {@link XPathFunctionResolver}.
+ *        An {@link XPathExpressionException} is raised if the function resolver is undefined or
+ *        the function resolver returns <code>null</code> for the function.</p>
+ *      </td>
+ *    </tr>
+ *    <tr>
+ *      <td>QNames</td>
+ *      <td>
+ *        QNames in the expression are resolved against the XPath namespace context.
+ *      </td>
+ *    </tr>
+ *    <tr>
+ *      <td>result</td>
+ *      <td>
+ *        This result of evaluating an expression is converted to an instance of the desired return type.
+ *        Valid return types are defined in {@link XPathConstants}.
+ *        Conversion to the return type follows XPath conversion rules.</p>
+ *      </td>
+ *    </tr>
+ * </table>
+ *
+ * @author  <a href="mailto:[email protected]">Norman Walsh</a>
+ * @author  <a href="mailto:[email protected]">Jeff Suttor</a>
+ * @version $Revision: 446598 $, $Date: 2006-09-15 05:55:40 -0700 (Fri, 15 Sep 2006) $
+ * @see <a href="http://www.w3.org/TR/xpath#section-Expressions">XML Path Language (XPath) Version 1.0, Expressions</a>
+ * @since 1.5
+ */
+public interface XPathExpression {
+
+    /**
+     * <p>Evaluate the compiled XPath expression in the specified context and return the result as the specified type.</p>
+     *
+     * <p>See <a href="#XPathExpression-evaluation">Evaluation of XPath Expressions</a> for context item evaluation,
+     * variable, function and QName resolution and return type conversion.</p>
+     *
+     * <p>If <code>returnType</code> is not one of the types defined in {@link XPathConstants},
+     * then an <code>IllegalArgumentException</code> is thrown.</p>
+     *
+     * <p>If a <code>null</code> value is provided for
+     * <code>item</code>, an empty document will be used for the
+     * context.
+     * If <code>returnType</code> is <code>null</code>, then a <code>NullPointerException</code> is thrown.</p>
+     *
+     * @param item The starting context (node or node list, for example).
+     * @param returnType The desired return type.
+     *
+     * @return The <code>Object</code> that is the result of evaluating the expression and converting the result to
+     *   <code>returnType</code>.
+     *
+     * @throws XPathExpressionException If the expression cannot be evaluated.
+     * @throws IllegalArgumentException If <code>returnType</code> is not one of the types defined in {@link XPathConstants}.
+     * @throws NullPointerException If  <code>returnType</code> is <code>null</code>.
+     */
+    public Object evaluate(Object item, QName returnType)
+        throws XPathExpressionException;
+
+    /**
+     * <p>Evaluate the compiled XPath expression in the specified context and return the result as a <code>String</code>.</p>
+     *
+     * <p>This method calls {@link #evaluate(Object item, QName returnType)} with a <code>returnType</code> of
+     * {@link XPathConstants#STRING}.</p>
+     *
+     * <p>See <a href="#XPathExpression-evaluation">Evaluation of XPath Expressions</a> for context item evaluation,
+     * variable, function and QName resolution and return type conversion.</p>
+     *
+     * <p>If a <code>null</code> value is provided for
+     * <code>item</code>, an empty document will be used for the
+     * context.
+     *
+     * @param item The starting context (node or node list, for example).
+     *
+     * @return The <code>String</code> that is the result of evaluating the expression and converting the result to a
+     *   <code>String</code>.
+     *
+     * @throws XPathExpressionException If the expression cannot be evaluated.
+     */
+    public String evaluate(Object item)
+        throws XPathExpressionException;
+
+    /**
+     * <p>Evaluate the compiled XPath expression in the context of the specified <code>InputSource</code> and return the result as the
+     * specified type.</p>
+     *
+     * <p>This method builds a data model for the {@link InputSource} and calls
+     * {@link #evaluate(Object item, QName returnType)} on the resulting document object.</p>
+     *
+     * <p>See <a href="#XPathExpression-evaluation">Evaluation of XPath Expressions</a> for context item evaluation,
+     * variable, function and QName resolution and return type conversion.</p>
+     *
+     * <p>If <code>returnType</code> is not one of the types defined in {@link XPathConstants},
+     * then an <code>IllegalArgumentException</code> is thrown.</p>
+     *
+     * <p>If <code>source</code> or <code>returnType</code> is <code>null</code>,
+     * then a <code>NullPointerException</code> is thrown.</p>
+     *
+     * @param source The <code>InputSource</code> of the document to evaluate over.
+     * @param returnType The desired return type.
+     *
+     * @return The <code>Object</code> that is the result of evaluating the expression and converting the result to
+     *   <code>returnType</code>.
+     *
+     * @throws XPathExpressionException If the expression cannot be evaluated.
+     * @throws IllegalArgumentException If <code>returnType</code> is not one of the types defined in {@link XPathConstants}.
+     * @throws NullPointerException If  <code>source</code> or <code>returnType</code> is <code>null</code>.
+     */
+    public Object evaluate(InputSource source, QName returnType)
+        throws XPathExpressionException;
+
+    /**
+     * <p>Evaluate the compiled XPath expression in the context of the specified <code>InputSource</code> and return the result as a
+     * <code>String</code>.</p>
+     *
+     * <p>This method calls {@link #evaluate(InputSource source, QName returnType)} with a <code>returnType</code> of
+     * {@link XPathConstants#STRING}.</p>
+     *
+     * <p>See <a href="#XPathExpression-evaluation">Evaluation of XPath Expressions</a> for context item evaluation,
+     * variable, function and QName resolution and return type conversion.</p>
+     *
+     * <p>If <code>source</code> is <code>null</code>, then a <code>NullPointerException</code> is thrown.</p>
+     *
+     * @param source The <code>InputSource</code> of the document to evaluate over.
+     *
+     * @return The <code>String</code> that is the result of evaluating the expression and converting the result to a
+     *   <code>String</code>.
+     *
+     * @throws XPathExpressionException If the expression cannot be evaluated.
+     * @throws NullPointerException If  <code>source</code> is <code>null</code>.
+     */
+    public String evaluate(InputSource source)
+        throws XPathExpressionException;
+}
diff --git a/javax/xml/xpath/XPathExpressionException.java b/javax/xml/xpath/XPathExpressionException.java
new file mode 100644
index 0000000..f21fd7a
--- /dev/null
+++ b/javax/xml/xpath/XPathExpressionException.java
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+// $Id: XPathExpressionException.java 446598 2006-09-15 12:55:40Z jeremias $
+
+package javax.xml.xpath;
+
+/**
+ * <code>XPathExpressionException</code> represents an error in an XPath expression.</p>
+ *
+ * @author  <a href="mailto:[email protected]">Norman Walsh</a>
+ * @author  <a href="mailto:[email protected]">Jeff Suttor</a>
+ * @version $Revision: 446598 $, $Date: 2006-09-15 05:55:40 -0700 (Fri, 15 Sep 2006) $
+ * @since 1.5
+ */
+public class XPathExpressionException extends XPathException {
+
+    /**
+     * <p>Stream Unique Identifier.</p>
+     */
+    private static final long serialVersionUID = -1837080260374986980L;
+
+    /**
+     * <p>Constructs a new <code>XPathExpressionException</code> with the specified detail <code>message</code>.</p>
+     *
+     * <p>The <code>cause</code> is not initialized.</p>
+     *
+     * <p>If <code>message</code> is <code>null</code>, then a <code>NullPointerException</code> is thrown.</p>
+     *
+     * @param message The detail message.
+     */
+    public XPathExpressionException(String message) {
+        super(message);
+    }
+
+    /**
+     * <p>Constructs a new <code>XPathExpressionException</code> with the specified <code>cause</code>.</p>
+     *
+     * <p>If <code>cause</code> is <code>null</code>, then a <code>NullPointerException</code> is thrown.</p>
+     *
+     * @param cause The cause.
+     *
+     * @throws NullPointerException if <code>cause</code> is <code>null</code>.
+     */
+    public XPathExpressionException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/javax/xml/xpath/XPathFactory.java b/javax/xml/xpath/XPathFactory.java
new file mode 100644
index 0000000..57f2195
--- /dev/null
+++ b/javax/xml/xpath/XPathFactory.java
@@ -0,0 +1,288 @@
+/*
+ * 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.
+ */
+// $Id: XPathFactory.java 888889 2009-12-09 17:43:18Z mrglavas $
+
+package javax.xml.xpath;
+
+/**
+ * <p>An <code>XPathFactory</code> instance can be used to create
+ * {@link javax.xml.xpath.XPath} objects.</p>
+ *
+ *<p>See {@link #newInstance(String uri)} for lookup mechanism.</p>
+ *
+ * @author  <a href="mailto:[email protected]">Norman Walsh</a>
+ * @author  <a href="mailto:[email protected]">Jeff Suttor</a>
+ * @version $Revision: 888889 $, $Date: 2009-12-09 09:43:18 -0800 (Wed, 09 Dec 2009) $
+ * @since 1.5
+ */
+public abstract class XPathFactory {
+
+
+    /**
+     * <p>The default property name according to the JAXP spec.</p>
+     */
+    public static final String DEFAULT_PROPERTY_NAME = "javax.xml.xpath.XPathFactory";
+
+    /**
+     * <p>Default Object Model URI.</p>
+     */
+    public static final String DEFAULT_OBJECT_MODEL_URI = "http://java.sun.com/jaxp/xpath/dom";
+
+    /**
+     * <p>Protected constructor as {@link #newInstance()}, {@link #newInstance(String uri)}
+     * or {@link #newInstance(String uri, String factoryClassName, ClassLoader classLoader)}
+     * should be used to create a new instance of an <code>XPathFactory</code>.</p>
+     */
+    protected XPathFactory() {
+    }
+
+    /**
+     * <p>Get a new <code>XPathFactory</code> instance using the default object model,
+     * {@link #DEFAULT_OBJECT_MODEL_URI},
+     * the W3C DOM.</p>
+     *
+     * <p>This method is functionally equivalent to:</p>
+     * <pre>
+     *   newInstance(DEFAULT_OBJECT_MODEL_URI)
+     * </pre>
+     *
+     * <p>Since the implementation for the W3C DOM is always available, this method will never fail.</p>
+     *
+     * @return Instance of an <code>XPathFactory</code>.
+     */
+    public static final XPathFactory newInstance() {
+        try {
+            return newInstance(DEFAULT_OBJECT_MODEL_URI);
+        }
+        catch (XPathFactoryConfigurationException xpathFactoryConfigurationException) {
+            throw new RuntimeException(
+                "XPathFactory#newInstance() failed to create an XPathFactory for the default object model: "
+                + DEFAULT_OBJECT_MODEL_URI
+                + " with the XPathFactoryConfigurationException: "
+                + xpathFactoryConfigurationException.toString()
+            );
+        }
+    }
+
+    /**
+    * <p>Get a new <code>XPathFactory</code> instance using the specified object model.</p>
+    *
+    * <p>To find a <code>XPathFactory</code> object,
+    * this method looks the following places in the following order where "the class loader" refers to the context class loader:</p>
+    * <ol>
+    *   <li>
+    *     If the system property {@link #DEFAULT_PROPERTY_NAME} + ":uri" is present,
+    *     where uri is the parameter to this method, then its value is read as a class name.
+    *     The method will try to create a new instance of this class by using the class loader,
+    *     and returns it if it is successfully created.
+    *   </li>
+    *   <li>
+    *     ${java.home}/lib/jaxp.properties is read and the value associated with the key being the system property above is looked for.
+    *     If present, the value is processed just like above.
+    *   </li>
+    *   <li>
+    *     The class loader is asked for service provider provider-configuration files matching <code>javax.xml.xpath.XPathFactory</code>
+    *     in the resource directory META-INF/services.
+    *     See the JAR File Specification for file format and parsing rules.
+    *     Each potential service provider is required to implement the method:
+    *     <pre>
+    *       {@link #isObjectModelSupported(String objectModel)}
+    *     </pre>
+    *     The first service provider found in class loader order that supports the specified object model is returned.
+    *   </li>
+    *   <li>
+    *     Platform default <code>XPathFactory</code> is located in a platform specific way.
+    *     There must be a platform default XPathFactory for the W3C DOM, i.e. {@link #DEFAULT_OBJECT_MODEL_URI}.
+    *   </li>
+    * </ol>
+    * <p>If everything fails, an <code>XPathFactoryConfigurationException</code> will be thrown.</p>
+    *
+    * <p>Tip for Trouble-shooting:</p>
+    * <p>See {@link java.util.Properties#load(java.io.InputStream)} for exactly how a property file is parsed.
+    * In particular, colons ':' need to be escaped in a property file, so make sure the URIs are properly escaped in it.
+    * For example:</p>
+    * <pre>
+    *   http\://java.sun.com/jaxp/xpath/dom=org.acme.DomXPathFactory
+    * </pre>
+    *
+    * @param uri Identifies the underlying object model.
+    *   The specification only defines the URI {@link #DEFAULT_OBJECT_MODEL_URI},
+    *   <code>http://java.sun.com/jaxp/xpath/dom</code> for the W3C DOM,
+    *   the org.w3c.dom package, and implementations are free to introduce other URIs for other object models.
+    *
+    * @return Instance of an <code>XPathFactory</code>.
+    *
+    * @throws XPathFactoryConfigurationException If the specified object model is unavailable.
+    * @throws NullPointerException If <code>uri</code> is <code>null</code>.
+    * @throws IllegalArgumentException If <code>uri.length() == 0</code>.
+    */
+    public static final XPathFactory newInstance(final String uri)
+        throws XPathFactoryConfigurationException {
+        if (uri == null) {
+            throw new NullPointerException("uri == null");
+        }
+        if (uri.length() == 0) {
+            throw new IllegalArgumentException(
+                "XPathFactory#newInstance(String uri) cannot be called with uri == \"\""
+            );
+        }
+        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+        if (classLoader == null) {
+            //use the current class loader
+            classLoader = XPathFactory.class.getClassLoader();
+        }
+        XPathFactory xpathFactory = new XPathFactoryFinder(classLoader).newFactory(uri);
+        if (xpathFactory == null) {
+            throw new XPathFactoryConfigurationException(
+                "No XPathFactory implementation found for the object model: "
+                + uri
+            );
+        }
+        return xpathFactory;
+    }
+
+    /**
+     * @return Instance of an <code>XPathFactory</code>.
+     *
+     * @throws XPathFactoryConfigurationException If the specified object model is unavailable.
+     * @throws NullPointerException If <code>uri</code> is <code>null</code>.
+     * @throws IllegalArgumentException If <code>uri.length() == 0</code>.
+     */
+    public static XPathFactory newInstance(String uri, String factoryClassName,
+            ClassLoader classLoader) throws XPathFactoryConfigurationException {
+        if (uri == null) {
+            throw new NullPointerException("uri == null");
+        }
+        if (uri.length() == 0) {
+            throw new IllegalArgumentException(
+                "XPathFactory#newInstance(String uri) cannot be called with uri == \"\""
+            );
+        }
+        if (factoryClassName == null) {
+            throw new XPathFactoryConfigurationException("factoryClassName cannot be null.");
+        }
+        if (classLoader == null) {
+            classLoader = Thread.currentThread().getContextClassLoader();
+        }
+        XPathFactory xpathFactory = new XPathFactoryFinder(classLoader).createInstance(factoryClassName);
+        if (xpathFactory == null || !xpathFactory.isObjectModelSupported(uri)) {
+            throw new XPathFactoryConfigurationException(
+                "No XPathFactory implementation found for the object model: "
+                + uri
+            );
+        }
+        return xpathFactory;
+    }
+
+    /**
+     * <p>Is specified object model supported by this <code>XPathFactory</code>?</p>
+     *
+     * @param objectModel Specifies the object model which the returned <code>XPathFactory</code> will understand.
+     *
+     * @return <code>true</code> if <code>XPathFactory</code> supports <code>objectModel</code>, else <code>false</code>.
+     *
+     * @throws NullPointerException If <code>objectModel</code> is <code>null</code>.
+     * @throws IllegalArgumentException If <code>objectModel.length() == 0</code>.
+     */
+    public abstract boolean isObjectModelSupported(String objectModel);
+
+    /**
+     * <p>Set a feature for this <code>XPathFactory</code> and <code>XPath</code>s created by this factory.</p>
+     *
+     * <p>
+     * Feature names are fully qualified {@link java.net.URI}s.
+     * Implementations may define their own features.
+     * An {@link XPathFactoryConfigurationException} is thrown if this <code>XPathFactory</code> or the <code>XPath</code>s
+     *  it creates cannot support the feature.
+     * It is possible for an <code>XPathFactory</code> to expose a feature value but be unable to change its state.
+     * </p>
+     *
+     * <p>
+     * All implementations are required to support the {@link javax.xml.XMLConstants#FEATURE_SECURE_PROCESSING} feature.
+     * When the feature is <code>true</code>, any reference to  an external function is an error.
+     * Under these conditions, the implementation must not call the {@link XPathFunctionResolver}
+     * and must throw an {@link XPathFunctionException}.
+     * </p>
+     *
+     * @param name Feature name.
+     * @param value Is feature state <code>true</code> or <code>false</code>.
+     *
+     * @throws XPathFactoryConfigurationException if this <code>XPathFactory</code> or the <code>XPath</code>s
+     *   it creates cannot support this feature.
+     * @throws NullPointerException if <code>name</code> is <code>null</code>.
+     */
+    public abstract void setFeature(String name, boolean value)
+        throws XPathFactoryConfigurationException;
+
+    /**
+     * <p>Get the state of the named feature.</p>
+     *
+     * <p>
+     * Feature names are fully qualified {@link java.net.URI}s.
+     * Implementations may define their own features.
+     * An {@link XPathFactoryConfigurationException} is thrown if this <code>XPathFactory</code> or the <code>XPath</code>s
+     * it creates cannot support the feature.
+     * It is possible for an <code>XPathFactory</code> to expose a feature value but be unable to change its state.
+     * </p>
+     *
+     * @param name Feature name.
+     *
+     * @return State of the named feature.
+     *
+     * @throws XPathFactoryConfigurationException if this <code>XPathFactory</code> or the <code>XPath</code>s
+     *   it creates cannot support this feature.
+     * @throws NullPointerException if <code>name</code> is <code>null</code>.
+     */
+    public abstract boolean getFeature(String name)
+        throws XPathFactoryConfigurationException;
+
+    /**
+     * <p>Establish a default variable resolver.</p>
+     *
+     * <p>Any <code>XPath</code> objects constructed from this factory will use
+     * the specified resolver by default.</p>
+     *
+     * <p>A <code>NullPointerException</code> is thrown if <code>resolver</code> is <code>null</code>.</p>
+     *
+     * @param resolver Variable resolver.
+     *
+     *  @throws NullPointerException If <code>resolver</code> is <code>null</code>.
+     */
+    public abstract void setXPathVariableResolver(XPathVariableResolver resolver);
+
+    /**
+       * <p>Establish a default function resolver.</p>
+       *
+       * <p>Any <code>XPath</code> objects constructed from this factory will use
+       * the specified resolver by default.</p>
+       *
+       * <p>A <code>NullPointerException</code> is thrown if <code>resolver</code> is <code>null</code>.</p>
+       *
+       * @param resolver XPath function resolver.
+       *
+       * @throws NullPointerException If <code>resolver</code> is <code>null</code>.
+       */
+    public abstract void setXPathFunctionResolver(XPathFunctionResolver resolver);
+
+    /**
+    * <p>Return a new <code>XPath</code> using the underlying object
+    * model determined when the <code>XPathFactory</code> was instantiated.</p>
+    *
+    * @return New instance of an <code>XPath</code>.
+    */
+    public abstract XPath newXPath();
+}
diff --git a/javax/xml/xpath/XPathFactoryConfigurationException.java b/javax/xml/xpath/XPathFactoryConfigurationException.java
new file mode 100644
index 0000000..0d19b22
--- /dev/null
+++ b/javax/xml/xpath/XPathFactoryConfigurationException.java
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+// $Id: XPathFactoryConfigurationException.java 446598 2006-09-15 12:55:40Z jeremias $
+
+package javax.xml.xpath;
+
+/**
+ * <code>XPathFactoryConfigurationException</code> represents a configuration error in a <code>XPathFactory</code> environment.</p>
+ *
+ * @author  <a href="mailto:[email protected]">Norman Walsh</a>
+ * @author  <a href="mailto:[email protected]">Jeff Suttor</a>
+ * @version $Revision: 446598 $, $Date: 2006-09-15 05:55:40 -0700 (Fri, 15 Sep 2006) $
+ * @since 1.5
+ */
+public class XPathFactoryConfigurationException extends XPathException {
+
+    /**
+     * <p>Stream Unique Identifier.</p>
+     */
+    private static final long serialVersionUID = -1837080260374986980L;
+
+    /**
+     * <p>Constructs a new <code>XPathFactoryConfigurationException</code> with the specified detail <code>message</code>.</p>
+     *
+     * <p>The <code>cause</code> is not initialized.</p>
+     *
+     * <p>If <code>message</code> is <code>null</code>, then a <code>NullPointerException</code> is thrown.</p>
+     *
+     * @param message The detail message.
+     */
+    public XPathFactoryConfigurationException(String message) {
+        super(message);
+    }
+
+    /**
+     * <p>Constructs a new <code>XPathFactoryConfigurationException</code> with the specified <code>cause</code>.</p>
+     *
+     * <p>If <code>cause</code> is <code>null</code>, then a <code>NullPointerException</code> is thrown.</p>
+     *
+     * @param cause The cause.
+     *
+     * @throws NullPointerException if <code>cause</code> is <code>null</code>.
+     */
+    public XPathFactoryConfigurationException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/javax/xml/xpath/XPathFactoryFinder.java b/javax/xml/xpath/XPathFactoryFinder.java
new file mode 100644
index 0000000..7a4f6b3
--- /dev/null
+++ b/javax/xml/xpath/XPathFactoryFinder.java
@@ -0,0 +1,370 @@
+/*
+ * 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.
+ */
+// $Id: XPathFactoryFinder.java 670432 2008-06-23 02:02:08Z mrglavas $
+
+package javax.xml.xpath;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.Properties;
+import javax.xml.validation.SchemaFactory;
+import libcore.io.IoUtils;
+
+/**
+ * Implementation of {@link XPathFactory#newInstance(String)}.
+ *
+ * @author <a href="[email protected]">Kohsuke Kawaguchi</a>
+ * @version $Revision: 670432 $, $Date: 2008-06-22 19:02:08 -0700 (Sun, 22 Jun 2008) $
+ * @since 1.5
+ */
+final class XPathFactoryFinder {
+
+    /** debug support code. */
+    private static boolean debug = false;
+
+    /**
+     * Default columns per line.
+     */
+    private static final int DEFAULT_LINE_LENGTH = 80;
+
+    static {
+        String val = System.getProperty("jaxp.debug");
+        // Allow simply setting the prop to turn on debug
+        debug = val != null && (! "false".equals(val));
+    }
+
+    /**
+     * <p>Cache properties for performance. Use a static class to avoid double-checked
+     * locking.</p>
+     */
+    private static class CacheHolder {
+
+        private static Properties cacheProps = new Properties();
+
+        static {
+            String javah = System.getProperty("java.home");
+            String configFile = javah + File.separator + "lib" + File.separator + "jaxp.properties";
+            File f = new File(configFile);
+            if (f.exists()) {
+                if (debug) debugPrintln("Read properties file " + f);
+                try (FileInputStream inputStream = new FileInputStream(f)) {
+                    cacheProps.load(inputStream);
+                } catch (Exception ex) {
+                    if (debug) {
+                        ex.printStackTrace();
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * <p>Conditional debug printing.</p>
+     *
+     * @param msg to print
+     */
+    private static void debugPrintln(String msg) {
+        if (debug) {
+            System.err.println("JAXP: " + msg);
+        }
+    }
+
+    /**
+     * <p><code>ClassLoader</code> to use to find <code>SchemaFactory</code>.</p>
+     */
+    private final ClassLoader classLoader;
+
+    /**
+     * <p>Constructor that specifies <code>ClassLoader</code> to use
+     * to find <code>SchemaFactory</code>.</p>
+     *
+     * @param loader
+     *      to be used to load resource, {@link SchemaFactory}, and
+     *      {@code SchemaFactoryLoader} implementations during
+     *      the resolution process.
+     *      If this parameter is null, the default system class loader
+     *      will be used.
+     */
+    public XPathFactoryFinder(ClassLoader loader) {
+        this.classLoader = loader;
+        if (debug) {
+            debugDisplayClassLoader();
+        }
+    }
+
+    private void debugDisplayClassLoader() {
+        if (classLoader == Thread.currentThread().getContextClassLoader()) {
+            debugPrintln("using thread context class loader (" + classLoader + ") for search");
+            return;
+        }
+
+        if (classLoader==ClassLoader.getSystemClassLoader()) {
+            debugPrintln("using system class loader (" + classLoader + ") for search");
+            return;
+        }
+
+        debugPrintln("using class loader (" + classLoader + ") for search");
+    }
+
+    /**
+     * <p>Creates a new {@link XPathFactory} object for the specified
+     * schema language.</p>
+     *
+     * @param uri
+     *       Identifies the underlying object model.
+     *
+     * @return <code>null</code> if the callee fails to create one.
+     *
+     * @throws NullPointerException
+     *      If the parameter is null.
+     */
+    public XPathFactory newFactory(String uri) {
+        if (uri == null) {
+            throw new NullPointerException("uri == null");
+        }
+        XPathFactory f = _newFactory(uri);
+        if (debug) {
+            if (f != null) {
+                debugPrintln("factory '" + f.getClass().getName() + "' was found for " + uri);
+            } else {
+                debugPrintln("unable to find a factory for " + uri);
+            }
+        }
+        return f;
+    }
+
+    /**
+     * <p>Lookup a {@link XPathFactory} for the given object model.</p>
+     *
+     * @param uri identifies the object model.
+     */
+    private XPathFactory _newFactory(String uri) {
+        XPathFactory xpf;
+        String propertyName = SERVICE_CLASS.getName() + ":" + uri;
+
+        // system property look up
+        try {
+            if (debug) debugPrintln("Looking up system property '"+propertyName+"'" );
+            String r = System.getProperty(propertyName);
+            if (r != null && r.length() > 0) {
+                if (debug) debugPrintln("The value is '"+r+"'");
+                xpf = createInstance(r);
+                if(xpf!=null)    return xpf;
+            } else if (debug) {
+                debugPrintln("The property is undefined.");
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        // try to read from $java.home/lib/jaxp.properties
+        try {
+            String factoryClassName = CacheHolder.cacheProps.getProperty(propertyName);
+            if (debug) debugPrintln("found " + factoryClassName + " in $java.home/jaxp.properties");
+
+            if (factoryClassName != null) {
+                xpf = createInstance(factoryClassName);
+                if(xpf != null){
+                    return xpf;
+                }
+            }
+        } catch (Exception ex) {
+            if (debug) {
+                ex.printStackTrace();
+            }
+        }
+
+        // try META-INF/services files
+        for (URL resource : createServiceFileIterator()) {
+            if (debug) debugPrintln("looking into " + resource);
+            try {
+                xpf = loadFromServicesFile(uri, resource.toExternalForm(), resource.openStream());
+                if(xpf!=null)    return xpf;
+            } catch(IOException e) {
+                if( debug ) {
+                    debugPrintln("failed to read "+resource);
+                    e.printStackTrace();
+                }
+            }
+        }
+
+        // platform default
+        if(uri.equals(XPathFactory.DEFAULT_OBJECT_MODEL_URI)) {
+            if (debug) debugPrintln("attempting to use the platform default W3C DOM XPath lib");
+            return createInstance("org.apache.xpath.jaxp.XPathFactoryImpl");
+        }
+
+        if (debug) debugPrintln("all things were tried, but none was found. bailing out.");
+        return null;
+    }
+
+    /**
+     * <p>Creates an instance of the specified and returns it.</p>
+     *
+     * @param className
+     *      fully qualified class name to be instantiated.
+     *
+     * @return null
+     *      if it fails. Error messages will be printed by this method.
+     */
+    XPathFactory createInstance( String className ) {
+        try {
+            if (debug) debugPrintln("instantiating "+className);
+            Class clazz;
+            if( classLoader!=null )
+                clazz = classLoader.loadClass(className);
+            else
+                clazz = Class.forName(className);
+            if(debug)       debugPrintln("loaded it from "+which(clazz));
+            Object o = clazz.newInstance();
+
+            if( o instanceof XPathFactory )
+                return (XPathFactory)o;
+
+            if (debug) debugPrintln(className+" is not assignable to "+SERVICE_CLASS.getName());
+        }
+        // The VM ran out of memory or there was some other serious problem. Re-throw.
+        catch (VirtualMachineError vme) {
+            throw vme;
+        }
+        // ThreadDeath should always be re-thrown
+        catch (ThreadDeath td) {
+            throw td;
+        }
+        catch (Throwable t) {
+            if (debug) {
+                debugPrintln("failed to instantiate "+className);
+                t.printStackTrace();
+            }
+        }
+        return null;
+    }
+
+    /** Searches for a XPathFactory for a given uri in a META-INF/services file. */
+    private XPathFactory loadFromServicesFile(String uri, String resourceName, InputStream in) {
+
+        if (debug) debugPrintln("Reading " + resourceName );
+
+        BufferedReader rd;
+        try {
+            rd = new BufferedReader(new InputStreamReader(in, "UTF-8"), DEFAULT_LINE_LENGTH);
+        } catch (java.io.UnsupportedEncodingException e) {
+            rd = new BufferedReader(new InputStreamReader(in), DEFAULT_LINE_LENGTH);
+        }
+
+        String factoryClassName;
+        XPathFactory resultFactory = null;
+        // See spec for provider-configuration files: http://java.sun.com/j2se/1.5.0/docs/guide/jar/jar.html#Provider%20Configuration%20File
+        while (true) {
+            try {
+                factoryClassName = rd.readLine();
+            } catch (IOException x) {
+                // No provider found
+                break;
+            }
+            if (factoryClassName != null) {
+                // Ignore comments in the provider-configuration file
+                int hashIndex = factoryClassName.indexOf('#');
+                if (hashIndex != -1) {
+                    factoryClassName = factoryClassName.substring(0, hashIndex);
+                }
+
+                // Ignore leading and trailing whitespace
+                factoryClassName = factoryClassName.trim();
+
+                // If there's no text left or if this was a blank line, go to the next one.
+                if (factoryClassName.length() == 0) {
+                    continue;
+                }
+
+                try {
+                    // Found the right XPathFactory if its isObjectModelSupported(String uri) method returns true.
+                    XPathFactory foundFactory = createInstance(factoryClassName);
+                    if (foundFactory.isObjectModelSupported(uri)) {
+                        resultFactory = foundFactory;
+                        break;
+                    }
+                } catch (Exception ignored) {
+                }
+            }
+            else {
+                break;
+            }
+        }
+
+        IoUtils.closeQuietly(rd);
+
+        return resultFactory;
+    }
+
+    /**
+     * Returns an {@link Iterator} that enumerates all
+     * the META-INF/services files that we care.
+     */
+    private Iterable<URL> createServiceFileIterator() {
+        if (classLoader == null) {
+            URL resource = XPathFactoryFinder.class.getClassLoader().getResource(SERVICE_ID);
+            return Collections.singleton(resource);
+        } else {
+            try {
+                Enumeration<URL> e = classLoader.getResources(SERVICE_ID);
+                if (debug && !e.hasMoreElements()) {
+                    debugPrintln("no "+SERVICE_ID+" file was found");
+                }
+
+                return Collections.list(e);
+            } catch (IOException e) {
+                if (debug) {
+                    debugPrintln("failed to enumerate resources "+SERVICE_ID);
+                    e.printStackTrace();
+                }
+                return Collections.emptySet();
+            }
+        }
+    }
+
+    private static final Class SERVICE_CLASS = XPathFactory.class;
+    private static final String SERVICE_ID = "META-INF/services/" + SERVICE_CLASS.getName();
+
+    private static String which( Class clazz ) {
+        return which( clazz.getName(), clazz.getClassLoader() );
+    }
+
+    /**
+     * <p>Search the specified classloader for the given classname.</p>
+     *
+     * @param classname the fully qualified name of the class to search for
+     * @param loader the classloader to search
+     *
+     * @return the source location of the resource, or null if it wasn't found
+     */
+    private static String which(String classname, ClassLoader loader) {
+        String classnameAsResource = classname.replace('.', '/') + ".class";
+        if (loader==null) loader = ClassLoader.getSystemClassLoader();
+
+        URL it = loader.getResource(classnameAsResource);
+        return it != null ? it.toString() : null;
+    }
+}
diff --git a/javax/xml/xpath/XPathFunction.java b/javax/xml/xpath/XPathFunction.java
new file mode 100644
index 0000000..1d80169
--- /dev/null
+++ b/javax/xml/xpath/XPathFunction.java
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+// $Id: XPathFunction.java 446598 2006-09-15 12:55:40Z jeremias $
+
+package javax.xml.xpath;
+
+import java.util.List;
+
+/**
+ * <p><code>XPathFunction</code> provides access to XPath functions.</p>
+ *
+ * <p>Functions are identified by QName and arity in XPath.</p>
+ *
+ * @author  <a href="mailto:[email protected]">Norman Walsh</a>
+ * @author  <a href="mailto:[email protected]">Jeff Suttor</a>
+ * @version $Revision: 446598 $, $Date: 2006-09-15 05:55:40 -0700 (Fri, 15 Sep 2006) $
+ * @since 1.5
+ */
+public interface XPathFunction {
+  /**
+   * <p>Evaluate the function with the specified arguments.</p>
+   *
+   * <p>To the greatest extent possible, side-effects should be avoided in the
+   * definition of extension functions. The implementation evaluating an
+   * XPath expression is under no obligation to call extension functions in
+   * any particular order or any particular number of times.</p>
+   *
+   * @param args The arguments, <code>null</code> is a valid value.
+   *
+   * @return The result of evaluating the <code>XPath</code> function as an <code>Object</code>.
+   *
+   * @throws XPathFunctionException If <code>args</code> cannot be evaluated with this <code>XPath</code> function.
+   */
+  public Object evaluate(List args)
+    throws XPathFunctionException;
+}
+
diff --git a/javax/xml/xpath/XPathFunctionException.java b/javax/xml/xpath/XPathFunctionException.java
new file mode 100644
index 0000000..6890124
--- /dev/null
+++ b/javax/xml/xpath/XPathFunctionException.java
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+// $Id: XPathFunctionException.java 446598 2006-09-15 12:55:40Z jeremias $
+
+package javax.xml.xpath;
+
+/**
+ * <code>XPathFunctionException</code> represents an error with an XPath function.</p>
+ *
+ * @author  <a href="mailto:[email protected]">Norman Walsh</a>
+ * @author  <a href="mailto:[email protected]">Jeff Suttor</a>
+ * @version $Revision: 446598 $, $Date: 2006-09-15 05:55:40 -0700 (Fri, 15 Sep 2006) $
+ * @since 1.5
+ */
+public class XPathFunctionException extends XPathExpressionException {
+
+    /**
+     * <p>Stream Unique Identifier.</p>
+     */
+    private static final long serialVersionUID = -1837080260374986980L;
+
+    /**
+     * <p>Constructs a new <code>XPathFunctionException</code> with the specified detail <code>message</code>.</p>
+     *
+     * <p>The <code>cause</code> is not initialized.</p>
+     *
+     * <p>If <code>message</code> is <code>null</code>, then a <code>NullPointerException</code> is thrown.</p>
+     *
+     * @param message The detail message.
+     */
+    public XPathFunctionException(String message) {
+        super(message);
+    }
+
+    /**
+     * <p>Constructs a new <code>XPathFunctionException</code> with the specified <code>cause</code>.</p>
+     *
+     * <p>If <code>cause</code> is <code>null</code>, then a <code>NullPointerException</code> is thrown.</p>
+     *
+     * @param cause The cause.
+     *
+     * @throws NullPointerException if <code>cause</code> is <code>null</code>.
+     */
+    public XPathFunctionException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/javax/xml/xpath/XPathFunctionResolver.java b/javax/xml/xpath/XPathFunctionResolver.java
new file mode 100644
index 0000000..c8236d4
--- /dev/null
+++ b/javax/xml/xpath/XPathFunctionResolver.java
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+// $Id: XPathFunctionResolver.java 446598 2006-09-15 12:55:40Z jeremias $
+
+package javax.xml.xpath;
+
+import javax.xml.namespace.QName;
+
+/**
+ * <p><code>XPathFunctionResolver</code> provides access to the set of user defined <code>XPathFunction</code>s.</p>
+ *
+ * <p>XPath functions are resolved by name and arity.
+ * The resolver is not needed for XPath built-in functions and the resolver
+ * <strong><em>cannot</em></strong> be used to override those functions.</p>
+ *
+ * <p>In particular, the resolver is only called for functions in an another
+ * namespace (functions with an explicit prefix). This means that you cannot
+ * use the <code>XPathFunctionResolver</code> to implement specifications
+ * like <a href="http://www.w3.org/TR/xmldsig-core/">XML-Signature Syntax
+ * and Processing</a> which extend the function library of XPath 1.0 in the
+ * same namespace. This is a consequence of the design of the resolver.</p>
+ *
+ * <p>If you wish to implement additional built-in functions, you will have to
+ * extend the underlying implementation directly.</p>
+ *
+ * @author  <a href="mailto:[email protected]">Norman Walsh</a>
+ * @author  <a href="mailto:[email protected]">Jeff Suttor</a>
+ * @version $Revision: 446598 $, $Date: 2006-09-15 05:55:40 -0700 (Fri, 15 Sep 2006) $
+ * @see <a href="http://www.w3.org/TR/xpath#corelib">XML Path Language (XPath) Version 1.0, Core Function Library</a>
+ * @since 1.5
+ */
+public interface XPathFunctionResolver {
+  /**
+   * <p>Find a function in the set of available functions.</p>
+   *
+   * <p>If <code>functionName</code> or <code>arity</code> is <code>null</code>, then a <code>NullPointerException</code> is thrown.</p>
+   *
+   * @param functionName The function name.
+   * @param arity The number of arguments that the returned function must accept.
+   *
+   * @return The function or <code>null</code> if no function named <code>functionName</code> with <code>arity</code> arguments exists.
+   *
+   * @throws NullPointerException If <code>functionName</code> or <code>arity</code> is <code>null</code>.
+   */
+  public XPathFunction resolveFunction(QName functionName, int arity);
+}
diff --git a/javax/xml/xpath/XPathVariableResolver.java b/javax/xml/xpath/XPathVariableResolver.java
new file mode 100644
index 0000000..f8938a8
--- /dev/null
+++ b/javax/xml/xpath/XPathVariableResolver.java
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+// $Id: XPathVariableResolver.java 446598 2006-09-15 12:55:40Z jeremias $
+
+package javax.xml.xpath;
+
+import javax.xml.namespace.QName;
+
+/**
+ * <p><code>XPathVariableResolver</code> provides access to the set of user defined XPath variables.</p>
+ *
+ * <p>The <code>XPathVariableResolver</code> and the XPath evaluator must adhere to a contract that
+ * cannot be directly enforced by the API.  Although variables may be mutable,
+ * that is, an application may wish to evaluate the same XPath expression more
+ * than once with different variable values, in the course of evaluating any
+ * single XPath expression, a variable's value <strong><em>must</em></strong> be immutable.</p>
+ *
+ * @author  <a href="mailto:[email protected]">Norman Walsh</a>
+ * @author  <a href="mailto:[email protected]">Jeff Suttor</a>
+ * @version $Revision: 446598 $, $Date: 2006-09-15 05:55:40 -0700 (Fri, 15 Sep 2006) $
+ * @since 1.5
+ */
+public interface XPathVariableResolver {
+  /**
+   * <p>Find a variable in the set of available variables.</p>
+   *
+   * <p>If <code>variableName</code> is <code>null</code>, then a <code>NullPointerException</code> is thrown.</p>
+   *
+   * @param variableName The <code>QName</code> of the variable name.
+   *
+   * @return The variables value, or <code>null</code> if no variable named <code>variableName</code>
+   *   exists.  The value returned must be of a type appropriate for the underlying object model.
+   *
+   * @throws NullPointerException If <code>variableName</code> is <code>null</code>.
+   */
+  public Object resolveVariable(QName variableName);
+}