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 & 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 & 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–25</td>
+ * <td>1–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> - <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> - <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 & 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–25</td>
+ * <td>1–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–25</td>
+ * <td>1–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–8, 11+</td>
+ * </tr>
+ * <tr>
+ * <td>DES-CBC-MD5</td>
+ * <td>SSL_CK_DES_64_CBC_WITH_MD5</td>
+ * <td>1–8</td>
+ * <td>1–8</td>
+ * </tr>
+ * <tr class="deprecated">
+ * <td>DES-CBC-SHA</td>
+ * <td>SSL_RSA_WITH_DES_CBC_SHA</td>
+ * <td>1–22</td>
+ * <td>1–19</td>
+ * </tr>
+ * <tr>
+ * <td>DES-CBC3-MD5</td>
+ * <td>SSL_CK_DES_192_EDE3_CBC_WITH_MD5</td>
+ * <td>1–8</td>
+ * <td>1–8</td>
+ * </tr>
+ * <tr>
+ * <td>DES-CBC3-SHA</td>
+ * <td>SSL_RSA_WITH_3DES_EDE_CBC_SHA</td>
+ * <td>1+</td>
+ * <td>1–19</td>
+ * </tr>
+ * <tr class="deprecated">
+ * <td>DHE-DSS-AES128-SHA</td>
+ * <td>TLS_DHE_DSS_WITH_AES_128_CBC_SHA</td>
+ * <td>1–22</td>
+ * <td>1–22</td>
+ * </tr>
+ * <tr class="deprecated">
+ * <td>DHE-DSS-AES256-SHA</td>
+ * <td>TLS_DHE_DSS_WITH_AES_256_CBC_SHA</td>
+ * <td>1–22</td>
+ * <td>1–8, 11–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–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–22</td>
+ * <td>1–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–22</td>
+ * <td>1–19</td>
+ * </tr>
+ * <tr class="deprecated">
+ * <td>EDH-RSA-DES-CBC-SHA</td>
+ * <td>SSL_DHE_RSA_WITH_DES_CBC_SHA</td>
+ * <td>1–22</td>
+ * <td>1–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–22</td>
+ * <td>1–19</td>
+ * </tr>
+ * <tr class="deprecated">
+ * <td>EXP-DES-CBC-SHA</td>
+ * <td>SSL_RSA_EXPORT_WITH_DES40_CBC_SHA</td>
+ * <td>1–22</td>
+ * <td>1–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–22</td>
+ * <td>1–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–22</td>
+ * <td>1–19</td>
+ * </tr>
+ * <tr>
+ * <td>EXP-RC2-CBC-MD5</td>
+ * <td>SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5</td>
+ * <td>1–8</td>
+ * <td>1–8</td>
+ * </tr>
+ * <tr class="deprecated">
+ * <td>EXP-RC4-MD5</td>
+ * <td>SSL_RSA_EXPORT_WITH_RC4_40_MD5</td>
+ * <td>1–22</td>
+ * <td>1–19</td>
+ * </tr>
+ * <tr>
+ * <td>RC2-CBC-MD5</td>
+ * <td>SSL_CK_RC2_128_CBC_WITH_MD5</td>
+ * <td>1–8</td>
+ * <td>1–8</td>
+ * </tr>
+ * <tr class="deprecated">
+ * <td>RC4-MD5</td>
+ * <td>SSL_RSA_WITH_RC4_128_MD5</td>
+ * <td>1–25</td>
+ * <td>1–19</td>
+ * </tr>
+ * <tr class="deprecated">
+ * <td>RC4-SHA</td>
+ * <td>SSL_RSA_WITH_RC4_128_SHA</td>
+ * <td>1–25</td>
+ * <td>1–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™
+ * 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 = <certificate read from a file, say>
+ * 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(<structured-type>)</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<B (A is shorter than B)
+ * <li>A>B (A is longer than B)
+ * <li>A==B (A and B are of the same duration)
+ * <li>A<>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><element xmlns:prefix="http://Namespace-name-URI"></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>
+ * <element xmlns:prefix1="http://Namespace-name-URI"
+ * xmlns:prefix2="http://Namespace-name-URI">
+ * </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>
+ * <parent xmlns:prefix1="http://Namespace-name-URI">
+ * <child xmlns:prefix2="http://Namespace-name-URI">
+ * ...
+ * </child>
+ * </parent>
+ * </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><default Namespace URI></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 <default Namespace URI></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>"javax.xml.parsers.SAXParserFactory"</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 <!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 <!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 <xyz:foo
+ * xmlns:xyz="http://xyz.foo.com/yada/baz.html"/>,
+ * 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 <xyz:foo
+ * xmlns:xyz="http://xyz.foo.com/yada/baz.html"/>,
+ * 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 <xyz:foo
+ * xmlns:xyz="http://xyz.foo.com/yada/baz.html"/>,
+ * 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. 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><include></tt>d or <tt><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 <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);
+}