Merge "java/security: remove system.scope from security.properties"
diff --git a/libart/src/main/java/java/lang/reflect/AbstractMethod.java b/libart/src/main/java/java/lang/reflect/AbstractMethod.java
index 95d90cc..2b93f52 100644
--- a/libart/src/main/java/java/lang/reflect/AbstractMethod.java
+++ b/libart/src/main/java/java/lang/reflect/AbstractMethod.java
@@ -116,6 +116,10 @@
         return (accessFlags & Modifier.SYNTHETIC) != 0;
     }
 
+    boolean isDefault() {
+      return (accessFlags & Modifier.DEFAULT) != 0;
+    }
+
     /**
      * @hide
      */
diff --git a/luni/src/main/java/java/security/security.properties b/luni/src/main/java/java/security/security.properties
index b5d6cb8..49daaf0 100644
--- a/luni/src/main/java/java/security/security.properties
+++ b/luni/src/main/java/java/security/security.properties
@@ -20,11 +20,10 @@
 #
 # Android's provider of OpenSSL backed implementations
 security.provider.1=com.android.org.conscrypt.OpenSSLProvider
-security.provider.2=sun.security.provider.Sun
 # Android's stripped down BouncyCastle provider
-security.provider.3=com.android.org.bouncycastle.jce.provider.BouncyCastleProvider
+security.provider.2=com.android.org.bouncycastle.jce.provider.BouncyCastleProvider
 # Android's provider of OpenSSL backed implementations
-security.provider.4=com.android.org.conscrypt.JSSEProvider
+security.provider.3=com.android.org.conscrypt.JSSEProvider
 
 
 
diff --git a/luni/src/test/java/libcore/java/net/ConcurrentCloseTest.java b/luni/src/test/java/libcore/java/net/ConcurrentCloseTest.java
index a629271..4309c6f 100644
--- a/luni/src/test/java/libcore/java/net/ConcurrentCloseTest.java
+++ b/luni/src/test/java/libcore/java/net/ConcurrentCloseTest.java
@@ -185,9 +185,9 @@
         sendBufferSize = s.getSendBufferSize(); // How big is the buffer really, Linux?
 
         // Linux still seems to accept more than it should.
-        // How much seems to differ from device to device, but I've yet to see anything accept
-        // twice as much again.
-        sendBufferSize *= 2;
+        // How much seems to differ from device to device. This used to be (sendBufferSize * 2)
+        // but that still failed on a bullhead (Nexus 5X).
+        sendBufferSize *= 4;
 
         s.connect(ss.getLocalSocketAddress());
         new Killer(s).start();
diff --git a/luni/src/test/java/libcore/java/net/InetAddressTest.java b/luni/src/test/java/libcore/java/net/InetAddressTest.java
index e4c97d2..d940aeb 100644
--- a/luni/src/test/java/libcore/java/net/InetAddressTest.java
+++ b/luni/src/test/java/libcore/java/net/InetAddressTest.java
@@ -371,7 +371,7 @@
         assertTrue(inetAddress.isLoopbackAddress());
     }
 
-    public void test_getByName_null() throws Exception {
+    public void test_getByName_v6loopback() throws Exception {
         InetAddress inetAddress = InetAddress.getByName("::1");
 
         Set<InetAddress> expectedLoopbackAddresses =
@@ -379,6 +379,21 @@
         assertTrue(expectedLoopbackAddresses.contains(inetAddress));
     }
 
+    public void test_getByName_cloning() throws Exception {
+        InetAddress[] addresses = InetAddress.getAllByName(null);
+        InetAddress[] addresses2 = InetAddress.getAllByName(null);
+        assertNotNull(addresses[0]);
+        assertNotNull(addresses[1]);
+        assertNotSame(addresses, addresses2);
+
+        // Also assert that changes to the return value do not affect the cache
+        // etc. i.e, that we return a copy.
+        addresses[0] = null;
+        addresses2 = InetAddress.getAllByName(null);
+        assertNotNull(addresses2[0]);
+        assertNotNull(addresses2[1]);
+    }
+
     public void test_getAllByName_null() throws Exception {
         InetAddress[] inetAddresses = InetAddress.getAllByName(null);
         assertEquals(2, inetAddresses.length);
diff --git a/luni/src/test/java/libcore/java/net/URITest.java b/luni/src/test/java/libcore/java/net/URITest.java
index e4c07a2..2c4a06a 100644
--- a/luni/src/test/java/libcore/java/net/URITest.java
+++ b/luni/src/test/java/libcore/java/net/URITest.java
@@ -114,6 +114,13 @@
         }
     }
 
+    // http://b/26632332
+    public void testSingleLetterHost() throws Exception {
+        URI uri = new URI("http://a");
+        assertEquals("a", uri.getHost());
+        assertEquals("", uri.getPath());
+    }
+
     public void testNoHostAndNoPath() throws Exception {
         try {
             new URI("http:");
@@ -136,6 +143,15 @@
         assertEquals("host", uri.getHost());
     }
 
+    // http://b/26632332
+    public void testUserNoHost() throws Exception {
+        URI uri = new URI("http://user@");
+        assertEquals("user@", uri.getAuthority());
+        // from RI. this is curious
+        assertEquals(null, uri.getUserInfo());
+        assertEquals(null, uri.getHost());
+    }
+
     public void testUserNoPasswordExplicitPort() throws Exception {
         URI uri = new URI("http://user@host:8080");
         assertEquals("user@host:8080", uri.getAuthority());
diff --git a/luni/src/test/java/libcore/java/text/SimpleDateFormatTest.java b/luni/src/test/java/libcore/java/text/SimpleDateFormatTest.java
index 72d3b76..d1ef127 100644
--- a/luni/src/test/java/libcore/java/text/SimpleDateFormatTest.java
+++ b/luni/src/test/java/libcore/java/text/SimpleDateFormatTest.java
@@ -17,6 +17,7 @@
 package libcore.java.text;
 
 import java.text.DateFormat;
+import java.text.ParseException;
 import java.text.ParsePosition;
 import java.text.SimpleDateFormat;
 import java.util.Calendar;
@@ -394,4 +395,32 @@
         df.setTimeZone(TimeZone.getTimeZone("UTC"));
         assertEquals("1. 1. 70", df.format(0L));
     }
+
+    public void testLenientParsingForZ() throws Exception {
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
+        Date date = sdf.parse("2016-01-06T23:05:49.480+00:00");
+        Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("+00:00"));
+        calendar.setTime(date);
+        assertEquals(11, calendar.get(Calendar.HOUR));
+        assertEquals(5, calendar.get(Calendar.MINUTE));
+        assertEquals(49, calendar.get(Calendar.SECOND));
+
+        Date date2 = sdf.parse("2016-01-06T23:05:49.480+00:00");
+        assertEquals(date, date2);
+
+        try {
+            date = sdf.parse("2016-01-06T23:05:49.480+00pissoff");
+            fail();
+        } catch (ParseException expected) {
+        }
+
+        SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
+        Date date3 = sdf2.parse("2016-01-06T23:05:49.480+00:00");
+        assertEquals(date, date3);
+        try {
+            sdf2.parse("2016-01-06T23:05:49.480+0000");
+            fail();
+        } catch (ParseException expected) {
+        }
+    }
 }
diff --git a/luni/src/test/java/libcore/java/util/CalendarTest.java b/luni/src/test/java/libcore/java/util/CalendarTest.java
index 2e13ad8..647c731 100644
--- a/luni/src/test/java/libcore/java/util/CalendarTest.java
+++ b/luni/src/test/java/libcore/java/util/CalendarTest.java
@@ -243,15 +243,28 @@
     // http://b/16938922.
     //
     // TODO: This is for backwards compatibility only. Seems like a better idea to throw
-    // here. We should add a targetSdkVersion based check and throw for each of these
-    // cases.
-    public void test_nullLocale() {
+    // here. We should add a targetSdkVersion based check and throw for this case.
+    public void test_nullLocale_getInstance_Locale() {
         assertCalendarConfigEquals(
                 Calendar.getInstance(Locale.getDefault()),
                 Calendar.getInstance((Locale) null));
+    }
+
+    // http://b/16938922.
+    //
+    // TODO: This is for backwards compatibility only. Seems like a better idea to throw
+    // here. We should add a targetSdkVersion based check and throw for this case.
+    public void test_nullLocale_getInstance_TimeZone_Locale() {
         assertCalendarConfigEquals(
                 Calendar.getInstance(TimeZone.getDefault(), Locale.getDefault()),
                 Calendar.getInstance(TimeZone.getDefault(), null));
+    }
+
+    // http://b/16938922.
+    //
+    // TODO: This is for backwards compatibility only. Seems like a better idea to throw
+    // here. We should add a targetSdkVersion based check and throw for this case.
+    public void test_nullLocale_GregorianCalendar_Locale() {
         assertCalendarConfigEquals(
                 new GregorianCalendar(Locale.getDefault()),
                 new GregorianCalendar((Locale) null));
diff --git a/luni/src/test/java/libcore/java/util/GregorianCalendarTest.java b/luni/src/test/java/libcore/java/util/GregorianCalendarTest.java
index 4a89289..4cb15ac 100644
--- a/luni/src/test/java/libcore/java/util/GregorianCalendarTest.java
+++ b/luni/src/test/java/libcore/java/util/GregorianCalendarTest.java
@@ -16,11 +16,11 @@
 
 package libcore.java.util;
 
-
 import java.util.Calendar;
 import java.util.Date;
 import java.util.GregorianCalendar;
 import java.util.Locale;
+import java.util.SimpleTimeZone;
 import java.util.TimeZone;
 import junit.framework.TestCase;
 
@@ -30,6 +30,14 @@
 
     private static final TimeZone LONDON = TimeZone.getTimeZone("Europe/London");
 
+    private static final int HOUR_IN_MILLIS = 3600000;
+
+    private static final SimpleTimeZone CUSTOM_LOS_ANGELES_TIME_ZONE = new SimpleTimeZone(-28800000,
+            "Custom America/Los_Angeles",
+            Calendar.MARCH, 9, 0, hours(2),
+            Calendar.NOVEMBER, 2, 0, hours(2),
+            hours(1));
+
     // Documented a previous difference in behavior between this and the RI, see
     // https://code.google.com/p/android/issues/detail?id=61993 for more details.
     // Switching to OpenJDK has fixed that issue and so this test has been changed to reflect
@@ -129,4 +137,224 @@
         assertEquals(5, gc.getActualMaximum(Calendar.DAY_OF_WEEK_IN_MONTH));
         assertEquals(4, gc.getLeastMaximum(Calendar.DAY_OF_WEEK_IN_MONTH));
     }
+
+    public void test_computeTime_enteringDst_TimeZone_LosAngeles_2014() {
+        TimeZone timeZone = TimeZone.getTimeZone("America/Los_Angeles");
+        checkDstLosAngeles2014(timeZone);
+    }
+
+    /**
+     * This test will fail in the RI.
+     *
+     * <p>The AOSP behavior is different for backwards compatibility with previous versions of
+     * Android.
+     *
+     * <p>Search in this file for 'OpenJDK Failure' to see more details.
+     */
+    public void test_computeTime_enteringDst_DelegatingTimeZone_LosAngeles_2014() {
+        TimeZone timeZone = TimeZone.getTimeZone("America/Los_Angeles");
+        timeZone = new DelegatingTimeZone(timeZone);
+        checkDstLosAngeles2014(timeZone);
+    }
+
+    /**
+     * This test will fail in the RI.
+     *
+     * <p>The AOSP behavior is different for backwards compatibility with previous versions of
+     * Android.
+     *
+     * <p>Search in this file for 'OpenJDK Failure' to see more details.
+     */
+    public void test_computeTime_enteringDst_SimpleTimeZone_LosAngeles_2014() {
+        checkDstLosAngeles2014(CUSTOM_LOS_ANGELES_TIME_ZONE);
+    }
+
+    public void test_computeTime_enteringDst() {
+        // Get the DST entry time with a ZoneInfo implementation of TimeZone.
+        TimeZone zoneInfo = TimeZone.getTimeZone("America/Los_Angeles");
+        long zoneInfoTime = getDstLosAngeles2014(zoneInfo);
+
+        // Check that the time is correct.
+        assertTrue(zoneInfo.inDaylightTime(new Date(zoneInfoTime)));
+        assertFalse(zoneInfo.inDaylightTime(new Date(zoneInfoTime - 1)));
+
+        // Get the DST entry time with a SimpleTimeZone implementation of TimeZone.
+        SimpleTimeZone simpleTimeZone = new SimpleTimeZone(-28800000,
+                "Custom America/Los_Angeles",
+                Calendar.MARCH, 9, 0, 7200000,
+                Calendar.NOVEMBER, 2, 0, 7200000,
+                3600000);
+        long simpleTimeZoneTime = getDstLosAngeles2014(simpleTimeZone);
+
+    }
+
+    private long getDstLosAngeles2014(TimeZone timeZone) {
+        GregorianCalendar cal = new GregorianCalendar(timeZone, Locale.ENGLISH);
+        cal.set(Calendar.MILLISECOND, 0);
+        cal.set(2014, Calendar.MARCH, 9, 2, 0, 0);
+
+        return cal.getTimeInMillis();
+    }
+
+    private void checkDstLosAngeles2014(TimeZone timeZone) {
+        Calendar cal = new GregorianCalendar(timeZone, Locale.ENGLISH);
+        // Clear the milliseconds field.
+        cal.set(Calendar.MILLISECOND, 0);
+
+        String description;
+
+        // Check milliseconds one second before the transition.
+        description = "01:59:59 - March 9th 2014";
+        cal.set(2014, Calendar.MARCH, 9, 1, 59, 59);
+        checkMillis(cal, description, 1394359199000L);
+
+        // Outside DST time.
+        checkOutsideDst(cal, description);
+
+        // Check milliseconds at the transition point but using an invalid wall clock
+        // (02:00 - 02:59:59.999) do not actually exist.
+        description = "02:00:00 - March 9th 2014";
+        cal.set(2014, Calendar.MARCH, 9, 2, 0, 0);
+
+        // OpenJDK Failure:
+        //   This fails on OpenJDK when running with SimpleTimeZone (or any custom TimeZone
+        //   implementation). It incorrectly calculates the time in millis to be 1394355600000.
+        //   That is because GregorianCalendar treats the implementation that underpins
+        //   TimeZone.getTimeZone(String) specially and the code that runs for other classes does
+        //   not handle the invalid wall clock period on entry to DST properly.
+        checkMillis(cal, description, 1394359200000L);
+
+        // Invalid wall clock but treated as being inside DST time.
+        checkInsideDst(cal, description);
+
+        // Check milliseconds at the first valid wall clock time after transition, 03:00 - should
+        // be treated the same as 02:00.
+        description = "03:00:00 - March 9th 2014";
+        cal.set(2014, Calendar.MARCH, 9, 3, 0, 0);
+        checkMillis(cal, description, 1394359200000L);
+
+        // Valid wall clock treated as being inside DST time.
+        checkInsideDst(cal, description);
+
+        // Check milliseconds at the last invalid wall clock time, 02:59:59.999.
+        description = "02:59:59.999 - March 9th 2014";
+        cal.set(2014, Calendar.MARCH, 9, 2, 59, 59);
+        cal.set(Calendar.MILLISECOND, 999);
+        checkMillis(cal, description, 1394362799999L);
+
+        // Invalid wall clock but treated as being inside DST time.
+        checkInsideDst(cal, description);
+
+        // Check milliseconds at 03:59:59.999 - should be treated the same as 02:59:59.999
+        description = "03:59:59.999 - March 9th 2014";
+        cal.set(2014, Calendar.MARCH, 9, 3, 59, 59);
+        cal.set(Calendar.MILLISECOND, 999);
+        checkMillis(cal, description, 1394362799999L);
+
+        // Valid wall clock treated as being inside DST time.
+        checkInsideDst(cal, description);
+    }
+
+    private void checkMillis(Calendar cal, String description, long expectedMillis) {
+        assertEquals("Incorrect millis: " + description, expectedMillis, cal.getTimeInMillis());
+    }
+
+    private void checkOutsideDst(Calendar cal, String description) {
+        TimeZone timeZone = cal.getTimeZone();
+        checkOutsideDst(cal, description, timeZone.getRawOffset());
+    }
+
+    private void checkOutsideDst(Calendar cal, String description, int expectedZoneOffset) {
+        checkDstFields(cal, description, expectedZoneOffset, 0);
+    }
+
+    private void checkInsideDst(Calendar cal, String description) {
+        TimeZone timeZone = cal.getTimeZone();
+        checkDstFields(cal, description, timeZone.getRawOffset(), timeZone.getDSTSavings());
+    }
+
+    private void checkDstFields(Calendar cal, String description, int expectedZoneOffset, int expectedDstOffset) {
+        assertEquals("Incorrect ZONE_OFFSET: " + description, expectedZoneOffset, cal.get(Calendar.ZONE_OFFSET));
+        assertEquals("Incorrect DST_OFFSET: " + description, expectedDstOffset, cal.get(Calendar.DST_OFFSET));
+    }
+
+    /**
+     * A custom {@link TimeZone} implementation.
+     *
+     * <p>Used to show the behavior of {@link GregorianCalendar} when provided with a custom
+     * implementation of {@link TimeZone}, i.e. one that is unknown to the runtime,
+     */
+    private static class DelegatingTimeZone extends TimeZone {
+
+        private final TimeZone timeZone;
+
+        public DelegatingTimeZone(TimeZone timeZone) {
+            this.timeZone = timeZone;
+        }
+
+        @Override
+        public int getOffset(int era, int year, int month, int day, int dayOfWeek,
+                int milliseconds) {
+            return timeZone.getOffset(era, year, month, day, dayOfWeek, milliseconds);
+        }
+
+        @Override
+        public int getOffset(long date) {
+            return timeZone.getOffset(date);
+        }
+
+        @Override
+        public void setRawOffset(int offsetMillis) {
+            timeZone.setRawOffset(offsetMillis);
+        }
+
+        @Override
+        public int getRawOffset() {
+            return timeZone.getRawOffset();
+        }
+
+        @Override
+        public String getID() {
+            return timeZone.getID();
+        }
+
+        @Override
+        public void setID(String ID) {
+            timeZone.setID(ID);
+        }
+
+        @Override
+        public String getDisplayName(boolean daylightTime, int style, Locale locale) {
+            return timeZone.getDisplayName(daylightTime, style, locale);
+        }
+
+        @Override
+        public int getDSTSavings() {
+            return timeZone.getDSTSavings();
+        }
+
+        @Override
+        public boolean useDaylightTime() {
+            return timeZone.useDaylightTime();
+        }
+
+        @Override
+        public boolean observesDaylightTime() {
+            return timeZone.observesDaylightTime();
+        }
+
+        @Override
+        public boolean inDaylightTime(Date date) {
+            return timeZone.inDaylightTime(date);
+        }
+
+        @Override
+        public boolean hasSameRules(TimeZone other) {
+            return timeZone.hasSameRules(other);
+        }
+    }
+
+    private static int hours(int count) {
+        return HOUR_IN_MILLIS * count;
+    }
 }
diff --git a/luni/src/test/java/libcore/java/util/SimpleTimeZoneTest.java b/luni/src/test/java/libcore/java/util/SimpleTimeZoneTest.java
index dc7773b..fdfcdcf 100644
--- a/luni/src/test/java/libcore/java/util/SimpleTimeZoneTest.java
+++ b/luni/src/test/java/libcore/java/util/SimpleTimeZoneTest.java
@@ -242,7 +242,7 @@
         return transitions;
     }
 
-    private static String formatCalendar(Calendar cal) {
+    public static String formatCalendar(Calendar cal) {
         SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ",
                 Locale.ENGLISH);
         format.setTimeZone(cal.getTimeZone());
diff --git a/luni/src/test/java/libcore/javax/net/ssl/SSLSocketFactoryTest.java b/luni/src/test/java/libcore/javax/net/ssl/SSLSocketFactoryTest.java
index 83b690b..3fe3ac3 100644
--- a/luni/src/test/java/libcore/javax/net/ssl/SSLSocketFactoryTest.java
+++ b/luni/src/test/java/libcore/javax/net/ssl/SSLSocketFactoryTest.java
@@ -191,18 +191,14 @@
         String origProvider = Security.getProperty(SSL_PROPERTY);
 
         try {
-            Field field_secprops = Security.class.getDeclaredField("secprops");
+            Field field_secprops = Security.class.getDeclaredField("props");
             field_secprops.setAccessible(true);
             Properties secprops = (Properties) field_secprops.get(null);
             secprops.remove(SSL_PROPERTY);
-
-            Class<?> class_services =
-                    Class.forName("org.apache.harmony.security.fortress.Services");
-            Method m_setNeedRefresh = class_services.getMethod("setNeedRefresh");
-            m_setNeedRefresh.invoke(null);
+            Security.increaseVersion();
         } catch (Exception e) {
             e.printStackTrace();
-            fail("Cannot find a way to clear out the SocketFactory provider");
+            throw new RuntimeException("Could not clear security provider", e);
         }
 
         assertNull(Security.getProperty(SSL_PROPERTY));
diff --git a/luni/src/test/java/org/apache/harmony/security/tests/java/security/SignerTest.java b/luni/src/test/java/org/apache/harmony/security/tests/java/security/SignerTest.java
index 018c2c4..254b467 100644
--- a/luni/src/test/java/org/apache/harmony/security/tests/java/security/SignerTest.java
+++ b/luni/src/test/java/org/apache/harmony/security/tests/java/security/SignerTest.java
@@ -34,6 +34,7 @@
 import org.apache.harmony.security.tests.support.PrivateKeyStub;
 import org.apache.harmony.security.tests.support.PublicKeyStub;
 import org.apache.harmony.security.tests.support.SignerStub;
+import org.apache.harmony.security.tests.support.SystemScope;
 
 
 import junit.framework.TestCase;
@@ -59,7 +60,7 @@
         Signer s1 = new SignerStub("testToString1");
         assertEquals("[Signer]testToString1", s1.toString());
 
-        Signer s2 = new SignerStub("testToString2", IdentityScope.getSystemScope());
+        Signer s2 = new SignerStub("testToString2", new SystemScope());
         s2.toString();
 
         KeyPair kp = new KeyPair(new PublicKeyStub("public", "SignerTest.testToString", null),
@@ -99,14 +100,18 @@
      * verify  Signer(String, IdentityScope) creates instance
      */
     public void testSignerStringIdentityScope() throws Exception {
-        Signer s = new SignerStub("sss4", IdentityScope.getSystemScope());
+        IdentityScope identityScope = new SystemScope();
+        Signer s = new SignerStub("sss4", identityScope);
         assertNotNull(s);
         assertEquals("sss4", s.getName());
-        assertSame(IdentityScope.getSystemScope(), s.getScope());
+        assertSame(identityScope, s.getScope());
         assertNull(s.getPrivateKey());
 
         try {
-            Signer s2 = new SignerStub("sss4", IdentityScope.getSystemScope());
+            // Check that the creation of a signer with a clashing name throws the required
+            // exception, provided that the underlying IdentityScope does (that is, check that
+            // the Signer is effectively being added to the scope).
+            Signer s2 = new SignerStub("sss4", identityScope);
             fail("expected KeyManagementException not thrown");
         } catch (KeyManagementException e)
         {
diff --git a/luni/src/test/java/tests/java/security/IdentityTest.java b/luni/src/test/java/tests/java/security/IdentityTest.java
index 405b100..6610350 100644
--- a/luni/src/test/java/tests/java/security/IdentityTest.java
+++ b/luni/src/test/java/tests/java/security/IdentityTest.java
@@ -33,6 +33,7 @@
 import org.apache.harmony.security.tests.support.CertificateStub;
 import org.apache.harmony.security.tests.support.IdentityStub;
 import org.apache.harmony.security.tests.support.PublicKeyStub;
+import org.apache.harmony.security.tests.support.SystemScope;
 
 import junit.framework.TestCase;
 
@@ -105,7 +106,7 @@
      * verify Identity(String, IdentityScope) creates instance with given name and in give scope
      */
     public void testIdentityStringIdentityScope() throws Exception {
-        IdentityScope s = IdentityScope.getSystemScope();
+        IdentityScope s = new SystemScope();
         Identity i = new IdentityStub("iii2", s);
         assertNotNull(i);
         assertEquals("iii2", i.getName());
@@ -212,6 +213,7 @@
      * verify Identity.identityEquals(Identity) return true, only if names and public keys are equal
      */
     public void testIdentityEquals() throws Exception {
+        IdentityScope identityScope = new SystemScope();
         String name = "nnn";
         PublicKey pk = new PublicKeyStub("aaa", "fff", new byte[]{1,2,3,4,5});
         IdentityStub i = new IdentityStub(name);
@@ -221,7 +223,7 @@
                 //new Object(), Boolean.FALSE,
                 new IdentityStub("111"), Boolean.FALSE,
                 new IdentityStub(name), Boolean.FALSE,
-                new IdentityStub(name, IdentityScope.getSystemScope()), Boolean.FALSE,
+                new IdentityStub(name, identityScope), Boolean.FALSE,
                 i, Boolean.TRUE,
                 new IdentityStub(name, pk), Boolean.TRUE
         };
@@ -229,7 +231,7 @@
             assertEquals(value[k+1], new Boolean(i.identityEquals((Identity)value[k])));
             if (Boolean.TRUE.equals(value[k+1])) assertEquals(i.hashCode(), value[k].hashCode());
         }
-        Identity i2 = IdentityScope.getSystemScope().getIdentity(name);
+        Identity i2 = identityScope.getIdentity(name);
         i2.setPublicKey(pk);
         assertTrue(i.identityEquals(i2));
     }
@@ -238,10 +240,11 @@
      * verify Identity.toString(boolean) return string representation of identity
      */
     public void testToStringboolean() throws Exception {
+        IdentityScope identityScope = new SystemScope();
         new IdentityStub("aaa").toString(false);
-        new IdentityStub("aaa2", IdentityScope.getSystemScope()).toString(false);
+        new IdentityStub("aaa2", identityScope).toString(false);
         new IdentityStub("bbb").toString(true);
-        new IdentityStub("bbb2", IdentityScope.getSystemScope()).toString(true);
+        new IdentityStub("bbb2", identityScope).toString(true);
     }
 
     /**
diff --git a/ojluni/src/main/java/java/lang/reflect/Method.java b/ojluni/src/main/java/java/lang/reflect/Method.java
index acbba78..1549a4f 100755
--- a/ojluni/src/main/java/java/lang/reflect/Method.java
+++ b/ojluni/src/main/java/java/lang/reflect/Method.java
@@ -644,4 +644,13 @@
     boolean equalNameAndParameters(Method m) {
         return getName().equals(m.getName()) && equalMethodParameters(m.getParameterTypes());
     }
+
+    /**
+     * Returns {@code true} if this method is a default method; returns {@code false} otherwise.
+     *
+     * @hide 1.8
+     */
+    public boolean isDefault() {
+      return super.isDefault();
+    }
 }
diff --git a/ojluni/src/main/java/java/lang/reflect/Modifier.java b/ojluni/src/main/java/java/lang/reflect/Modifier.java
index 949bbdb..78e0dbc 100755
--- a/ojluni/src/main/java/java/lang/reflect/Modifier.java
+++ b/ojluni/src/main/java/java/lang/reflect/Modifier.java
@@ -344,14 +344,6 @@
     }
 
     /**
-     * Miranda methods are fabrications to reserve virtual method
-     * table slots in abstract classes that implement interfaces
-     * without declaring the abstract methods that the interface would
-     * require they implement.
-     * @hide
-     */
-    public static final int MIRANDA = 0x8000;
-    /**
      * Dex addition to mark instance constructors and static class
      * initializer methods.
      * @hide
@@ -359,6 +351,15 @@
     public static final int CONSTRUCTOR = 0x10000;
 
     /**
+     * Default methods are marked with a synthetic access flag
+     * to speed up class loading and invocation target lookup.
+     * Implies INTERFACE, not-ABSTRACT, and not-STATIC.
+     *
+     * @hide
+     */
+    public static final int DEFAULT = 0x00400000;
+
+    /**
      * See JLSv3 section 8.1.1.
      */
     private static final int CLASS_MODIFIERS =
diff --git a/ojluni/src/main/java/java/net/Inet6AddressImpl.java b/ojluni/src/main/java/java/net/Inet6AddressImpl.java
index b40e98c..0e29418 100755
--- a/ojluni/src/main/java/java/net/Inet6AddressImpl.java
+++ b/ojluni/src/main/java/java/net/Inet6AddressImpl.java
@@ -76,7 +76,7 @@
             return new InetAddress[] { result };
         }
 
-        return lookupHostByName(host, netId).clone();
+        return lookupHostByName(host, netId);
     }
 
     /**
diff --git a/ojluni/src/main/java/java/net/InetAddress.java b/ojluni/src/main/java/java/net/InetAddress.java
index d86c3d3..019c4ac 100755
--- a/ojluni/src/main/java/java/net/InetAddress.java
+++ b/ojluni/src/main/java/java/net/InetAddress.java
@@ -722,7 +722,7 @@
      */
     public static InetAddress getByName(String host)
         throws UnknownHostException {
-        return InetAddress.getAllByName(host)[0];
+        return impl.lookupAllHostAddr(host, NETID_UNSET)[0];
     }
 
     /**
@@ -766,7 +766,7 @@
      */
     public static InetAddress[] getAllByName(String host)
         throws UnknownHostException {
-        return impl.lookupAllHostAddr(host, NETID_UNSET);
+        return impl.lookupAllHostAddr(host, NETID_UNSET).clone();
     }
 
     /**
diff --git a/ojluni/src/main/java/java/net/URI.java b/ojluni/src/main/java/java/net/URI.java
index 5563aba..b3dbaad 100755
--- a/ojluni/src/main/java/java/net/URI.java
+++ b/ojluni/src/main/java/java/net/URI.java
@@ -2036,7 +2036,7 @@
         }
 
         // 5.2 (6c-f)
-        String np = normalize(path);
+        String np = normalize(path, true);
 
         // 5.2 (6g): If the result is absolute but the path begins with "../",
         // then we simply leave the path as-is
@@ -2102,7 +2102,7 @@
                 // There is an additional step from RFC 3986 RI, requiring to remove dots for
                 // absolute path as well.
                 // http://b/25897693
-                ru.path = normalize(child.path);
+                ru.path = normalize(child.path, true);
             } else {
                 // 5.2 (6): Resolve relative path
                 ru.path = resolvePath(base.path, child.path, base.isAbsolute());
@@ -2355,7 +2355,7 @@
     // Remove "." segments from the given path, and remove segment pairs
     // consisting of a non-".." segment followed by a ".." segment.
     //
-    private static void removeDots(char[] path, int[] segs) {
+    private static void removeDots(char[] path, int[] segs, boolean removeLeading) {
         int ns = segs.length;
         int end = path.length - 1;
 
@@ -2402,7 +2402,7 @@
                         segs[i] = -1;
                         segs[j] = -1;
                     }
-                } else {
+                } else if (removeLeading) {
                     // This is a leading ".." segment. Per RFC 3986 RI, this should be removed as
                     // well. This fixes RFC 2396 "abnormal" examples.
                     // http://b/25897693
@@ -2455,6 +2455,10 @@
     // always retain trailing slashes.
     //
     private static String normalize(String ps) {
+        return normalize(ps, false);
+    }
+
+    private static String normalize(String ps, boolean removeLeading) {
 
         // Does this path need normalization?
         int ns = needsNormalization(ps);        // Number of segments
@@ -2469,7 +2473,7 @@
         split(path, segs);
 
         // Remove dots
-        removeDots(path, segs);
+        removeDots(path, segs, removeLeading);
 
         // Prevent scheme-name confusion
         maybeAddLeadingDot(path, segs);
@@ -3408,7 +3412,7 @@
                 // this prior to N and the behavior is used by some apps. They're accepted for
                 // compatibility but we produce a warning in the log.
                 // http://b/25991669
-                if (charAt(p) == '.') {
+                if (p < n && charAt(p) == '.') {
                   java.lang.System.logE("URI " + substring(start, n) +  " has empty labels in " +
                                         "the hostname. This is malformed and will not be accepted" +
                                         "in future Android releases.");
diff --git a/ojluni/src/main/java/java/security/Security.java b/ojluni/src/main/java/java/security/Security.java
index 9ccabd9..3db5369 100755
--- a/ojluni/src/main/java/java/security/Security.java
+++ b/ojluni/src/main/java/java/security/Security.java
@@ -91,9 +91,8 @@
      */
     private static void initializeStatic() {
         props.put("security.provider.1", "com.android.org.conscrypt.OpenSSLProvider");
-        props.put("security.provider.2", "sun.security.provider.Sun");
-        props.put("security.provider.3", "com.android.org.bouncycastle.jce.provider.BouncyCastleProvider");
-        props.put("security.provider.4", "com.android.org.conscrypt.JSSEProvider");
+        props.put("security.provider.2", "com.android.org.bouncycastle.jce.provider.BouncyCastleProvider");
+        props.put("security.provider.3", "com.android.org.conscrypt.JSSEProvider");
     }
 
     /**
diff --git a/ojluni/src/main/java/java/text/SimpleDateFormat.java b/ojluni/src/main/java/java/text/SimpleDateFormat.java
index dcc7515..bf6176a 100755
--- a/ojluni/src/main/java/java/text/SimpleDateFormat.java
+++ b/ojluni/src/main/java/java/text/SimpleDateFormat.java
@@ -1715,12 +1715,12 @@
      * @param start the character position to start parsing
      * @param sign  1: positive; -1: negative
      * @param count 0: 'Z' or "GMT+hh:mm" parsing; 1 - 3: the number of 'X's
-     * @param colon true - colon required between hh and mm; false - no colon required
+     * @param colonRequired true - colon required between hh and mm; false - no colon required
      * @param calb  a CalendarBuilder in which the parsed value is stored
      * @return updated parsed position, or its negative value to indicate a parsing error
      */
     private int subParseNumericZone(String text, int start, int sign, int count,
-                                    boolean colon, CalendarBuilder calb) {
+                                    boolean colonRequired, CalendarBuilder calb) {
         int index = start;
 
       parse:
@@ -1736,11 +1736,6 @@
             if (isDigit(c)) {
                 hours = hours * 10 + (c - '0');
             } else {
-                // If no colon in RFC 822 or 'X' (ISO), two digits are
-                // required.
-                if (count > 0 || !colon) {
-                    break parse;
-                }
                 --index;
             }
             if (hours > 23) {
@@ -1750,11 +1745,10 @@
             if (count != 1) {
                 // Proceed with parsing mm
                 c = text.charAt(index++);
-                if (colon) {
-                    if (c != ':') {
-                        break parse;
-                    }
+                if (c == ':') {
                     c = text.charAt(index++);
+                } else if (colonRequired) {
+                    break parse;
                 }
                 if (!isDigit(c)) {
                     break parse;
@@ -2041,9 +2035,9 @@
                                     return pos.index;
                                 }
 
-                                // Parse the rest as "hh:mm"
-                                int i = subParseNumericZone(text, ++pos.index,
-                                                            sign, 0, true, calb);
+                                // Parse the rest as "hh[:]?mm"
+                                int i = subParseNumericZone(text, ++pos.index, sign, 0,
+                                        false, calb);
                                 if (i > 0) {
                                     return i;
                                 }
@@ -2058,9 +2052,9 @@
                                 pos.index = -i;
                             }
                         } else {
-                            // Parse the rest as "hhmm" (RFC 822)
-                            int i = subParseNumericZone(text, ++pos.index,
-                                                        sign, 0, (count == 5), calb);
+                            // Parse the rest as "hh[:]?mm" (RFC 822)
+                            int i = subParseNumericZone(text, ++pos.index, sign, 0,
+                                    false, calb);
                             if (i > 0) {
                                 return i;
                             }
@@ -2093,8 +2087,7 @@
                         ++pos.index;
                         break parsing;
                     }
-                    int i = subParseNumericZone(text, ++pos.index, sign, count,
-                                                count == 3, calb);
+                    int i = subParseNumericZone(text, ++pos.index, sign, count, (count == 3), calb);
                     if (i > 0) {
                         return i;
                     }
diff --git a/ojluni/src/main/java/java/util/Calendar.java b/ojluni/src/main/java/java/util/Calendar.java
index 09f3a65..43b02cd 100755
--- a/ojluni/src/main/java/java/util/Calendar.java
+++ b/ojluni/src/main/java/java/util/Calendar.java
@@ -947,6 +947,13 @@
      */
     protected Calendar(TimeZone zone, Locale aLocale)
     {
+        // http://b/16938922.
+        //
+        // TODO: This is for backwards compatibility only. Seems like a better idea to throw
+        // here. We should add a targetSdkVersion based check and throw for this case.
+        if (aLocale == null) {
+            aLocale = Locale.getDefault();
+        }
         fields = new int[FIELD_COUNT];
         isSet = new boolean[FIELD_COUNT];
         stamp = new int[FIELD_COUNT];
diff --git a/ojluni/src/main/java/java/util/GregorianCalendar.java b/ojluni/src/main/java/java/util/GregorianCalendar.java
index f74dbcb..bc0361fe 100755
--- a/ojluni/src/main/java/java/util/GregorianCalendar.java
+++ b/ojluni/src/main/java/java/util/GregorianCalendar.java
@@ -2723,26 +2723,10 @@
         // We use the TimeZone object, unless the user has explicitly set the ZONE_OFFSET
         // or DST_OFFSET fields; then we use those fields.
         TimeZone zone = getZone();
-        if (zoneOffsets == null) {
-            zoneOffsets = new int[2];
-        }
-        int tzMask = fieldMask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK);
-        if (tzMask != (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) {
-            int gmtOffset = isFieldSet(fieldMask, ZONE_OFFSET) ?
-                                internalGet(ZONE_OFFSET) : zone.getRawOffset();
-            zone.getOffsets(millis - gmtOffset, zoneOffsets);
-        }
-        if (tzMask != 0) {
-            if (isFieldSet(tzMask, ZONE_OFFSET)) {
-                zoneOffsets[0] = internalGet(ZONE_OFFSET);
-            }
-            if (isFieldSet(tzMask, DST_OFFSET)) {
-                zoneOffsets[1] = internalGet(DST_OFFSET);
-            }
-        }
 
-        // Adjust the time zone offset values to get the UTC time.
-        millis -= zoneOffsets[0] + zoneOffsets[1];
+        int tzMask = fieldMask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK);
+
+        millis = adjustForZoneAndDaylightSavingsTime(fieldMask, tzMask, millis, zone);
 
         // Set this calendar's time in milliseconds
         time = millis;
@@ -2766,6 +2750,171 @@
     }
 
     /**
+     * Calculates the time in milliseconds that this calendar represents using the UTC time,
+     * timezone information (specifically Daylight Savings Time (DST) rules, if any) and knowledge
+     * of what fields were explicitly set on the calendar.
+     *
+     * <p>A time is represented as the number of milliseconds since
+     * <i>1st January 1970 00:00:00.000 UTC</i>.
+     *
+     * <p>This uses the terms {@link SimpleTimeZone#STANDARD_TIME standard time},
+     * {@link SimpleTimeZone#WALL_TIME} wall time} and {@link SimpleTimeZone#UTC_TIME UTC time} as
+     * used in {@link SimpleTimeZone}. Specifically:
+     *
+     * <dl>
+     * <dt><b>UTC time</b></dt>
+     * <dd>This is the time within the UTC time zone. UTC does not support DST so the UTC time,
+     * standard time and wall time are all identical within the UTC time zone.</dd>
+     * <dt><b>standard time</b></dt>
+     * <dd>This is the local time within the time zone and is not affected by DST.</dd>
+     * <dt><b>wall time</b></dt>
+     * <dd>This is the local time within the time zone as shown on a wall clock. If the time zone
+     * supports DST then it will be the same as <b>standard time</b> when outside DST and it will
+     * differ (usually be an hour later) when inside DST. This is what the fields on the Calendar
+     * represent.</dd>
+     * </dl>
+     *
+     * <p>The {@code utcTimeInMillis} value supplied was calculated as if the fields represented
+     * a standard time in the {@code UTC} time zone. It is the value that would be returned by
+     * {@link #getTimeInMillis()} when called on this calendar if it was in UTC time zone. e.g. If
+     * the calendar was set to say <i>2014 March 19th 13:27.53 -08:00</i> then the value of
+     * {@code utcTimeInMillis} would be the value of {@link #getTimeInMillis()} when called on a
+     * calendar set to <i>2014 March 19th 13:27.53 -00:00</i>, note the time zone offset is set to
+     * 0.
+     *
+     * <p>To adjust from a UTC time in millis to the standard time in millis we must
+     * <em>subtract</em> the offset from UTC. e.g. given an offset of UTC-08:00, to convert
+     * "14:00 UTC" to "14:00 UTC-08:00" we must subtract -08:00 (i.e. add 8 hours). Another way to
+     * think about it is that 8 hours has to elapse after 14:00 UTC before it is 14:00 UTC-08:00.
+     *
+     * <p>As the zone offset can depend on the time and we cannot calculate the time properly until
+     * we know the time there is a bit of a catch-22. So, what this does is use the
+     * {@link TimeZone#getRawOffset() raw offset} to calculate a ballpark standard time and then
+     * uses that value to retrieve the appropriate zone and DST offsets from the time zone. They
+     * are then used to make the final wall time calculation.
+     *
+     * <p>The DST offset will need clearing if the standard time is not a valid wall clock. See
+     * {@link #adjustDstOffsetForInvalidWallClock(long, TimeZone, int)} for more information.
+     *
+     * @param fieldMask the set of fields that should be used to calculate the time.
+     * @param tzMask the set of time zone related fields, i.e. {@link #ZONE_OFFSET_MASK} and
+     * {@link #DST_OFFSET_MASK}
+     * @param utcTimeInMillis the time in millis, calculated assuming the time zone was GMT.
+     * @param zone the actual time zone.
+     * @return the UTC time in millis after adjusting for zone and DST offset.
+     */
+    private long adjustForZoneAndDaylightSavingsTime(
+            int fieldMask, int tzMask, long utcTimeInMillis, TimeZone zone) {
+
+        // The following don't actually need to be initialized because they are always set before
+        // they are used but the compiler cannot detect that.
+        int zoneOffset = 0;
+        int dstOffset = 0;
+
+        // If either of the ZONE_OFFSET or DST_OFFSET fields are not set then get the information
+        // from the TimeZone.
+        if (tzMask != (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) {
+            if (zoneOffsets == null) {
+                zoneOffsets = new int[2];
+            }
+            int gmtOffset = isFieldSet(fieldMask, ZONE_OFFSET) ?
+                                internalGet(ZONE_OFFSET) : zone.getRawOffset();
+
+            // Calculate the standard time (no DST) in the supplied zone. This is a ballpark figure
+            // and not used in the final calculation as the offset used here may not be the same as
+            // the actual offset the time zone requires be used for this time. This is to handle
+            // situations like Honolulu, where its raw offset changed from GMT-10:30 to GMT-10:00
+            // in 1947. The TimeZone always uses a raw offset of -10:00 but will return -10:30
+            // for dates before the change over.
+            long standardTimeInZone = utcTimeInMillis - gmtOffset;
+
+            // Retrieve the correct zone and DST offsets from the time zone.
+            zone.getOffsets(standardTimeInZone, zoneOffsets);
+            zoneOffset = zoneOffsets[0];
+            dstOffset = zoneOffsets[1];
+
+            // If necessary adjust the DST offset to handle an invalid wall clock sensibly.
+            dstOffset = adjustDstOffsetForInvalidWallClock(standardTimeInZone, zone, dstOffset);
+        }
+
+        // If either ZONE_OFFSET of DST_OFFSET fields are set then get the information from the
+        // fields, potentially overriding information from the TimeZone.
+        if (tzMask != 0) {
+            if (isFieldSet(tzMask, ZONE_OFFSET)) {
+                zoneOffset = internalGet(ZONE_OFFSET);
+            }
+            if (isFieldSet(tzMask, DST_OFFSET)) {
+                dstOffset = internalGet(DST_OFFSET);
+            }
+        }
+
+        // Adjust the time zone offset values to get the UTC time.
+        long standardTimeInZone = utcTimeInMillis - zoneOffset;
+        return standardTimeInZone - dstOffset;
+    }
+
+    /**
+     * If the supplied millis is in daylight savings time (DST) and is the result of an invalid
+     * wall clock then adjust the DST offset to ensure sensible behavior.
+     *
+     * <p>When transitioning into DST, i.e. when the clocks spring forward (usually by one hour)
+     * there is a wall clock period that is invalid, it literally doesn't exist. e.g. If clocks
+     * go forward one hour at 02:00 on 9th March 2014 (standard time) then the wall time of
+     * 02:00-02:59:59.999 is not a valid. The wall clock jumps straight from 01:59:59.999 to
+     * 03:00. The following table shows the relationship between the time in millis, the standard
+     * time and the wall time at the point of transitioning into DST. As can be seen there is no
+     * 02:00 in the wall time.
+     *
+     * <pre>
+     * Time In Millis - ......  x+1h .....  x+2h .....  x+3h
+     * Standard Time  - ...... 01:00 ..... 02:00 ..... 03:00 .....
+     * Wall Time      - ...... 01:00 ..... 03:00 ..... 04:00 .....
+     *                                       ^
+     *                                 02:00 missing
+     * </pre>
+     *
+     * <p>The calendar fields represent wall time. If the user sets the fields on the calendar so
+     * that it is in that invalid period then this code attempts to do something sensible. It
+     * treats 02:MM:SS.SSS as if it is {@code 01:MM:SS.SSS + 1 hour}. That makes sense from both
+     * the input calendar fields perspective and from the time in millis perspective. Of course the
+     * result of that is that when the time is formatted in that time zone that the time is
+     * actually 03:MM:SS.SSS.
+     *
+     * <pre>
+     * Wall Time      - ...... 01:00 ..... <b>02:00 .....</b> 03:00 ..... 04:00 .....
+     * Time In Millis - ......  x+1h ..... <b> x+2h .....</b>  x+2h .....  x+3h .....
+     * </pre>
+     *
+     * <p>The way that works is as follows. First the standard time is calculated and the DST
+     * offset is determined. Then if the time is in DST (the DST offset is not 0) but it was not in
+     * DST an hour earlier (or however long the DST offset is) then it must be in that invalid
+     * period, in which case set the DST offset to 0. That is then subtracted from the time in
+     * millis to produce the correct result. The following diagram illustrates the process.
+     *
+     * <pre>
+     * Standard Time  - ...... 01:00 ..... 02:00 ..... 03:00 ..... 04:00 .....
+     * Time In Millis - ......  x+1h .....  x+2h .....  x+3h .....  x+4h .....
+     * DST Offset     - ......    0h .....    1h .....    1h .....    1h .....
+     * Adjusted DST   - ......    0h .....    <b>0h</b> .....    1h .....    1h .....
+     * Adjusted Time  - ......  x+1h .....  x+2h .....  <b>x+2h</b> .....  <b>x+3h</b> .....
+     * </pre>
+     *
+     * @return the adjusted DST offset.
+     */
+    private int adjustDstOffsetForInvalidWallClock(
+            long standardTimeInZone, TimeZone zone, int dstOffset) {
+
+        if (dstOffset != 0) {
+            // If applying the DST offset produces a time that is outside DST then it must be
+            // an invalid wall clock so clear the DST offset to avoid that happening.
+            if (!zone.inDaylightTime(new Date(standardTimeInZone - dstOffset))) {
+                dstOffset = 0;
+            }
+        }
+        return dstOffset;
+    }
+
+    /**
      * Computes the fixed date under either the Gregorian or the
      * Julian calendar, using the given year and the specified calendar fields.
      *
diff --git a/ojluni/src/main/java/java/util/logging/Level.java b/ojluni/src/main/java/java/util/logging/Level.java
index 6847518..ac7306e 100755
--- a/ojluni/src/main/java/java/util/logging/Level.java
+++ b/ojluni/src/main/java/java/util/logging/Level.java
@@ -27,9 +27,13 @@
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
+import java.util.MissingResourceException;
 import java.util.ResourceBundle;
 
+import dalvik.system.VMStack;
+
 /**
  * The Level class defines a set of standard logging levels that
  * can be used to control logging output.  The logging Level objects
@@ -83,6 +87,8 @@
     // localized level name
     private String localizedLevelName;
 
+    private transient  ResourceBundle rb;
+
     /**
      * OFF is a special level that can be used to turn off logging.
      * This level is initialized to <CODE>Integer.MAX_VALUE</CODE>.
@@ -208,6 +214,18 @@
         this.name = name;
         this.value = value;
         this.resourceBundleName = resourceBundleName;
+        if (resourceBundleName != null) {
+            try {
+                ClassLoader cl = VMStack.getCallingClassLoader();
+                if (cl != null) {
+                    rb = ResourceBundle.getBundle(resourceBundleName, Locale.getDefault(), cl);
+                } else {
+                    rb = ResourceBundle.getBundle(resourceBundleName);
+                }
+            } catch (MissingResourceException ex) {
+                rb = null;
+            }
+        }
         this.localizedLevelName = resourceBundleName == null ? name : null;
         KnownLevel.add(this);
     }
@@ -256,7 +274,6 @@
         }
 
         try {
-            ResourceBundle rb = ResourceBundle.getBundle(resourceBundleName);
             localizedLevelName = rb.getString(name);
         } catch (Exception ex) {
             localizedLevelName = name;
diff --git a/ojluni/src/main/java/java/util/logging/LogManager.java b/ojluni/src/main/java/java/util/logging/LogManager.java
index 4868df0..27f0d0c 100755
--- a/ojluni/src/main/java/java/util/logging/LogManager.java
+++ b/ojluni/src/main/java/java/util/logging/LogManager.java
@@ -176,13 +176,7 @@
                     try {
                         cname = System.getProperty("java.util.logging.manager");
                         if (cname != null) {
-                            try {
-                                Class clz = ClassLoader.getSystemClassLoader().loadClass(cname);
-                                manager = (LogManager) clz.newInstance();
-                            } catch (ClassNotFoundException ex) {
-                                Class clz = Thread.currentThread().getContextClassLoader().loadClass(cname);
-                                manager = (LogManager) clz.newInstance();
-                            }
+                                manager = (LogManager) getClassInstance(cname).newInstance();
                         }
                     } catch (Exception ex) {
                         System.err.println("Could not load Logmanager \"" + cname + "\"");
@@ -437,6 +431,22 @@
         return sysLogger;
     }
 
+    private static Class getClassInstance(String cname) {
+        Class clz = null;
+        if (cname != null) {
+            try {
+                clz = ClassLoader.getSystemClassLoader().loadClass(cname);
+            } catch (ClassNotFoundException ex) {
+                try {
+                    clz = Thread.currentThread().getContextClassLoader().loadClass(cname);
+                } catch (ClassNotFoundException innerEx) {
+                    clz = null;
+                }
+            }
+        }
+        return clz;
+    }
+
     // LoggerContext maintains the logger namespace per context.
     // The default LogManager implementation has one system context and user
     // context.  The system context is used to maintain the namespace for
@@ -750,7 +760,7 @@
                 for (int i = 0; i < names.length; i++) {
                     String word = names[i];
                     try {
-                        Class clz = ClassLoader.getSystemClassLoader().loadClass(word);
+                        Class clz = getClassInstance(word);
                         Handler hdl = (Handler) clz.newInstance();
                         // Check if there is a property defining the
                         // this handler's level.
@@ -1026,15 +1036,8 @@
                 // Instantiate the named class.  It is its constructor's
                 // responsibility to initialize the logging configuration, by
                 // calling readConfiguration(InputStream) with a suitable stream.
-                try {
-                    Class clz = ClassLoader.getSystemClassLoader().loadClass(cname);
-                    clz.newInstance();
-                    return;
-                } catch (ClassNotFoundException ex) {
-                    Class clz = Thread.currentThread().getContextClassLoader().loadClass(cname);
-                    clz.newInstance();
-                    return;
-                }
+                getClassInstance(cname).newInstance();
+                return;
             } catch (Exception ex) {
                 System.err.println("Logging configuration class \"" + cname + "\" failed");
                 System.err.println("" + ex);
@@ -1184,8 +1187,7 @@
         for (int i = 0; i < names.length; i++) {
             String word = names[i];
             try {
-                Class clz = ClassLoader.getSystemClassLoader().loadClass(word);
-                clz.newInstance();
+                getClassInstance(word).newInstance();
             } catch (Exception ex) {
                 System.err.println("Can't load config class \"" + word + "\"");
                 System.err.println("" + ex);
@@ -1279,19 +1281,12 @@
         String val = getProperty(name);
         try {
             if (val != null) {
-                Class clz = ClassLoader.getSystemClassLoader().loadClass(val);
-                return (Filter) clz.newInstance();
+                return (Filter) getClassInstance(val).newInstance();
             }
         } catch (Exception ex) {
-            try {
-              Class<?> clz =
-                  Thread.currentThread().getContextClassLoader().loadClass(val);
-              return (Filter) clz.newInstance();
-            } catch (Exception innerE) {
-                // We got one of a variety of exceptions in creating the
-                // class or creating an instance.
-                // Drop through.
-            }
+            // We got one of a variety of exceptions in creating the
+            // class or creating an instance.
+            // Drop through.
         }
         // We got an exception.  Return the defaultValue.
         return defaultValue;
@@ -1306,19 +1301,12 @@
         String val = getProperty(name);
         try {
             if (val != null) {
-                Class clz = ClassLoader.getSystemClassLoader().loadClass(val);
-                return (Formatter) clz.newInstance();
+                return (Formatter) getClassInstance(val).newInstance();
             }
         } catch (Exception ex) {
-            try {
-              Class<?> clz =
-                  Thread.currentThread().getContextClassLoader().loadClass(val);
-              return (Formatter) clz.newInstance();
-            } catch (Exception innerE) {
-                // We got one of a variety of exceptions in creating the
-                // class or creating an instance.
-                // Drop through.
-            }
+            // We got one of a variety of exceptions in creating the
+            // class or creating an instance.
+            // Drop through.
         }
         // We got an exception.  Return the defaultValue.
         return defaultValue;
diff --git a/ojluni/src/main/java/java/util/logging/LogRecord.java b/ojluni/src/main/java/java/util/logging/LogRecord.java
index b42af29..f2cbeab4 100755
--- a/ojluni/src/main/java/java/util/logging/LogRecord.java
+++ b/ojluni/src/main/java/java/util/logging/LogRecord.java
@@ -511,9 +511,14 @@
             try {
                 resourceBundle = ResourceBundle.getBundle(resourceBundleName);
             } catch (MissingResourceException ex) {
-                // This is not a good place to throw an exception,
-                // so we simply leave the resourceBundle null.
-                resourceBundle = null;
+                try {
+                    resourceBundle = ResourceBundle.getBundle(resourceBundleName, Locale.getDefault(),
+                            Thread.currentThread().getContextClassLoader());
+                } catch (MissingResourceException innerE){
+                    // This is not a good place to throw an exception,
+                    // so we simply leave the resourceBundle null.
+                    resourceBundle = null;
+                }
             }
         }
 
diff --git a/ojluni/src/main/java/java/util/logging/XMLFormatter.java b/ojluni/src/main/java/java/util/logging/XMLFormatter.java
index 6b0a58a..d5250a9 100755
--- a/ojluni/src/main/java/java/util/logging/XMLFormatter.java
+++ b/ojluni/src/main/java/java/util/logging/XMLFormatter.java
@@ -151,6 +151,9 @@
             escape(sb, message);
             sb.append("</message>");
             sb.append("\n");
+        } else {
+            sb.append("<message/>");
+            sb.append("\n");
         }
 
         // If the message is being localized, output the key, resource
diff --git a/ojluni/src/main/java/sun/security/provider/Sun.java b/ojluni/src/main/java/sun/security/provider/Sun.java
deleted file mode 100755
index 20edc86..0000000
--- a/ojluni/src/main/java/sun/security/provider/Sun.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.provider;
-
-import java.util.*;
-import java.security.*;
-
-import sun.security.action.PutAllAction;
-
-/**
- * The SUN Security Provider.
- *
- */
-public final class Sun extends Provider {
-
-    private static final long serialVersionUID = 6440182097568097204L;
-
-    private static final String INFO = "SUN " +
-    "(DSA key/parameter generation; DSA signing; SHA-1, MD5 digests; " +
-    "SecureRandom; X.509 certificates; JKS keystore; PKIX CertPathValidator; " +
-    "PKIX CertPathBuilder; LDAP, Collection CertStores, JavaPolicy Policy; " +
-    "JavaLoginConfig Configuration)";
-
-    public Sun() {
-        /* We are the SUN provider */
-        super("SUN", 1.7, INFO);
-
-        // if there is no security manager installed, put directly into
-        // the provider. Otherwise, create a temporary map and use a
-        // doPrivileged() call at the end to transfer the contents
-        if (System.getSecurityManager() == null) {
-            SunEntries.putEntries(this);
-        } else {
-            // use LinkedHashMap to preserve the order of the PRNGs
-            Map<Object, Object> map = new LinkedHashMap<>();
-            SunEntries.putEntries(map);
-            AccessController.doPrivileged(new PutAllAction(this, map));
-        }
-    }
-
-}
diff --git a/ojluni/src/main/native/NetworkInterface.c b/ojluni/src/main/native/NetworkInterface.c
index ea52b5d..83ab1b8 100755
--- a/ojluni/src/main/native/NetworkInterface.c
+++ b/ojluni/src/main/native/NetworkInterface.c
@@ -50,7 +50,6 @@
 //#include <bits/ioctls.h>
 #include <sys/utsname.h>
 #include <stdio.h>
-#include <ifaddrs.h>
 #endif
 
 #ifdef __linux__
@@ -132,14 +131,11 @@
 static int     getFlags0(JNIEnv *env, jstring  ifname);
 
 static netif  *enumInterfaces(JNIEnv *env);
-
-#ifndef __linux__
 static netif  *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs);
 
 #ifdef AF_INET6
 static netif  *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs);
 #endif
-#endif
 
 static netif  *addif(JNIEnv *env, int sock, const char * if_name, netif *ifs, struct sockaddr* ifr_addrP, int family, short prefix);
 static void    freeif(netif *ifs);
@@ -748,95 +744,10 @@
   return netifObj;
 }
 
-#ifdef __linux__
-#ifdef AF_INET6
-/*
- * Determines the prefix for IPv6 interfaces.
- */
-static
-int prefix(void *val, int size) {
-  u_char *name = (u_char *)val;
-  int byte, bit, plen = 0;
-
-  for (byte = 0; byte < size && name[byte] == 0xff; byte++) {
-    plen += 8;
-  }
-  if (byte < size) {
-    for (bit = 7; bit > 0; bit--) {
-      if (name[byte] & (1 << bit)) plen++;
-    }
-  }
-  return plen;
-}
-#endif
-
 /*
  * Enumerates all interfaces
  */
 static netif *enumInterfaces(JNIEnv *env) {
-  netif *ifs = NULL;
-  struct ifaddrs *ifa, *origifa;
-
-  int sock = 0;
-  if ((sock = openSocket(env, AF_INET)) < 0 && (*env)->ExceptionOccurred(env)) {
-    return NULL;
-  }
-
-#ifdef AF_INET6
-  int sock6 = 0;
-  if (ipv6_available()) {
-    if ((sock6 = openSocket(env, AF_INET6)) < 0 && (*env)->ExceptionOccurred(env)) {
-      return NULL;
-    }
-  }
-#endif
-
-  if (getifaddrs(&origifa) != 0) {
-    NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException",
-                                 "getifaddrs() function failed");
-    return ifs;
-  }
-
-  for (ifa = origifa; ifa != NULL; ifa = ifa->ifa_next) {
-    if (ifa->ifa_addr != NULL) {
-      switch (ifa->ifa_addr->sa_family) {
-        case AF_PACKET:
-          ifs = addif(env, 0, ifa->ifa_name, ifs, 0, AF_PACKET, 0);
-          break;
-        case AF_INET:
-          ifs = addif(env, sock, ifa->ifa_name, ifs, ifa->ifa_addr, AF_INET, 0);
-          break;
-#ifdef AF_INET6
-        case AF_INET6:
-          if (ipv6_available()) {
-            struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ifa->ifa_addr;
-            ifs = addif(env, sock6, ifa->ifa_name, ifs, ifa->ifa_addr, AF_INET6,
-                        prefix(&sin6->sin6_addr, sizeof(struct in6_addr)));
-          }
-          break;
-#endif
-      }
-    }
-  }
-
-  if (close(sock) != 0 && (*env)->ExceptionOccurred(env)) {
-    freeif(ifs);
-    return NULL;
-  }
-
-#ifdef AF_INET6
-  if (ipv6_available()) {
-    if (close(sock6) != 0 && (*env)->ExceptionOccurred(env)) {
-      freeif(ifs);
-      return NULL;
-    }
-  }
-#endif
-
-  return ifs;
-}
-#else
-static netif *enumInterfaces(JNIEnv *env) {
   netif *ifs;
   int sock;
 
@@ -887,7 +798,6 @@
 
   return ifs;
 }
-#endif
 
 #define CHECKED_MALLOC3(_pointer,_type,_size) \
     do{ \
@@ -932,7 +842,7 @@
              short prefix)
 {
   netif *currif = ifs, *parent;
-  netaddr *addrP = NULL;
+  netaddr *addrP;
 
 #ifdef LIFNAMSIZ
   int ifnam_size = LIFNAMSIZ;
@@ -965,41 +875,29 @@
    */
   /*Allocate for addr and brdcast at once*/
 
-  switch(family) {
-    case AF_INET:
-      addr_size = sizeof(struct sockaddr_in);
-      break;
 #ifdef AF_INET6
-    case AF_INET6:
-      addr_size = sizeof(struct sockaddr_in6);
-      break;
+  addr_size = (family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6);
+#else
+  addr_size = sizeof(struct sockaddr_in);
 #endif
-    case AF_PACKET:
-      addr_size = 0;
-      break;
-    default:
-      return NULL;
-  }
 
-  if (addr_size > 0) {
-    CHECKED_MALLOC3(addrP, netaddr *, sizeof(netaddr)+2*addr_size);
-    addrP->addr = (struct sockaddr *)( (char *) addrP+sizeof(netaddr) );
-    memcpy(addrP->addr, ifr_addrP, addr_size);
+  CHECKED_MALLOC3(addrP, netaddr *, sizeof(netaddr)+2*addr_size);
+  addrP->addr = (struct sockaddr *)( (char *) addrP+sizeof(netaddr) );
+  memcpy(addrP->addr, ifr_addrP, addr_size);
 
-    addrP->family = family;
-    addrP->brdcast = NULL;
-    addrP->mask = prefix;
-    addrP->next = 0;
-    if (family == AF_INET) {
-      /*
-       * Deal with brodcast addr & subnet mask
-       */
-      struct sockaddr * brdcast_to = (struct sockaddr *) ((char *) addrP + sizeof(netaddr) + addr_size);
-      addrP->brdcast = getBroadcast(env, sock, name,  brdcast_to );
+  addrP->family = family;
+  addrP->brdcast = NULL;
+  addrP->mask = prefix;
+  addrP->next = 0;
+  if (family == AF_INET) {
+    /*
+     * Deal with brodcast addr & subnet mask
+     */
+    struct sockaddr * brdcast_to = (struct sockaddr *) ((char *) addrP + sizeof(netaddr) + addr_size);
+    addrP->brdcast = getBroadcast(env, sock, name,  brdcast_to );
 
-      if (addrP->brdcast && (mask = getSubnet(env, sock, name)) != -1) {
-        addrP->mask = mask;
-      }
+    if (addrP->brdcast && (mask = getSubnet(env, sock, name)) != -1) {
+      addrP->mask = mask;
     }
   }
 
@@ -1060,8 +958,7 @@
   /*
    * Finally insert the address on the interface
    */
-  if (addrP != NULL)
-    addrP->next = currif->addr;
+  addrP->next = currif->addr;
   currif->addr = addrP;
 
   parent = currif;
@@ -1170,6 +1067,109 @@
   return openSocket(env,AF_INET);
 }
 #endif
+
+static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) {
+  struct ifconf ifc;
+  struct ifreq *ifreqP;
+  char *buf;
+  int numifs;
+  unsigned i;
+
+
+  /* need to do a dummy SIOCGIFCONF to determine the buffer size.
+   * SIOCGIFCOUNT doesn't work
+   */
+  ifc.ifc_buf = NULL;
+  if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {
+    NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "ioctl SIOCGIFCONF failed");
+    return ifs;
+  }
+
+  CHECKED_MALLOC3(buf,char *, ifc.ifc_len);
+
+  ifc.ifc_buf = buf;
+  if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {
+    NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "ioctl SIOCGIFCONF failed");
+    (void) free(buf);
+    return ifs;
+  }
+
+  /*
+   * Iterate through each interface
+   */
+  ifreqP = ifc.ifc_req;
+  for (i=0; i<ifc.ifc_len/sizeof (struct ifreq); i++, ifreqP++) {
+    /*
+     * Add to the list
+     */
+    ifs = addif(env, sock, ifreqP->ifr_name, ifs, (struct sockaddr *) & (ifreqP->ifr_addr), AF_INET, 0);
+
+    /*
+     * If an exception occurred then free the list
+     */
+    if ((*env)->ExceptionOccurred(env)) {
+      free(buf);
+      freeif(ifs);
+      return NULL;
+    }
+  }
+
+  /*
+   * Free socket and buffer
+   */
+  free(buf);
+  return ifs;
+}
+
+
+/*
+ * Enumerates and returns all IPv6 interfaces on Linux
+ */
+
+#ifdef AF_INET6
+static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) {
+  FILE *f;
+  char addr6[40], devname[21];
+  char addr6p[8][5];
+  int plen, scope, dad_status, if_idx;
+  uint8_t ipv6addr[16];
+
+  if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) {
+    while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %08x %02x %02x %02x %20s\n",
+                  addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4], addr6p[5], addr6p[6], addr6p[7],
+                  &if_idx, &plen, &scope, &dad_status, devname) != EOF) {
+
+      struct netif *ifs_ptr = NULL;
+      struct netif *last_ptr = NULL;
+      struct sockaddr_in6 addr;
+
+      sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
+              addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
+      inet_pton(AF_INET6, addr6, ipv6addr);
+
+      memset(&addr, 0, sizeof(struct sockaddr_in6));
+      memcpy((void*)addr.sin6_addr.s6_addr, (const void*)ipv6addr, 16);
+
+      addr.sin6_scope_id = if_idx;
+
+      ifs = addif(env, sock, devname, ifs, (struct sockaddr *)&addr, AF_INET6, plen);
+
+
+      /*
+       * If an exception occurred then return the list as is.
+       */
+      if ((*env)->ExceptionOccurred(env)) {
+        fclose(f);
+        return ifs;
+      }
+    }
+    fclose(f);
+  }
+  return ifs;
+}
+#endif
+
+
 static int getIndex(int sock, const char *name){
   /*
    * Try to get the interface index
diff --git a/openjdk_java_files.mk b/openjdk_java_files.mk
index f066f03..3177c60b 100644
--- a/openjdk_java_files.mk
+++ b/openjdk_java_files.mk
@@ -1353,7 +1353,6 @@
     ojluni/src/main/java/sun/security/provider/NativeSeedGenerator.java \
     ojluni/src/main/java/sun/security/provider/SecureRandom.java \
     ojluni/src/main/java/sun/security/provider/SeedGenerator.java \
-    ojluni/src/main/java/sun/security/provider/Sun.java \
     ojluni/src/main/java/sun/security/provider/SunEntries.java \
     ojluni/src/main/java/sun/security/provider/VerificationProvider.java \
     ojluni/src/main/java/sun/security/provider/X509Factory.java \
diff --git a/support/src/test/java/org/apache/harmony/security/tests/support/SystemScope.java b/support/src/test/java/org/apache/harmony/security/tests/support/SystemScope.java
new file mode 100644
index 0000000..abb0507
--- /dev/null
+++ b/support/src/test/java/org/apache/harmony/security/tests/support/SystemScope.java
@@ -0,0 +1,160 @@
+/*
+ *  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.
+ */
+
+/**
+* @author Aleksei Y. Semenov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.support;
+
+import java.security.Identity;
+import java.security.IdentityScope;
+import java.security.KeyManagementException;
+import java.security.PublicKey;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+/**
+ * Provides full functionality. Currently used for testing only.
+ *
+ * @see java.security.IdentityScope
+ */
+
+public class SystemScope extends IdentityScope {
+
+    /**
+     * @serial
+     */
+    private static final long serialVersionUID = -4810285697932522607L;
+
+    // Identities hash: key is the identity name
+    private Hashtable names = new Hashtable();
+
+    // Identities hash: key is the public key
+    private Hashtable keys = new Hashtable();
+
+    /**
+     * @see java.security.IdentityScope#IdentityScope()
+     */
+    public SystemScope() {
+    }
+
+    /**
+     * @see java.security.IdentityScope#IdentityScope(String)
+     */
+    public SystemScope(String name) {
+        super(name);
+    }
+
+    /**
+     * @see java.security.IdentityScope#IdentityScope(String, IdentityScope)
+     */
+    public SystemScope(String name, IdentityScope scope)
+            throws KeyManagementException {
+        super(name, scope);
+    }
+
+    /**
+     * @see java.security.IdentityScope#size()
+     */
+    public int size() {
+        return names.size();
+    }
+
+    /**
+     * @see java.security.IdentityScope#getIdentity(java.lang.String)
+     */
+    public synchronized Identity getIdentity(String name) {
+        if (name == null) {
+            throw new NullPointerException("name == null");
+        }
+        return (Identity) names.get(name);
+    }
+
+    /**
+     * @see java.security.IdentityScope#getIdentity(java.security.PublicKey)
+     */
+    public synchronized Identity getIdentity(PublicKey key) {
+        if (key == null) {
+            return null;
+        }
+        return (Identity) keys.get(key);
+    }
+
+    /**
+     * @see java.security.IdentityScope#addIdentity(java.security.Identity)
+     */
+    public synchronized void addIdentity(Identity identity) throws KeyManagementException {
+        if (identity == null) {
+            throw new NullPointerException("identity == null");
+        }
+
+        String name = identity.getName();
+        if (names.containsKey(name)) {
+            throw new KeyManagementException("name '" + name + "' is already used");
+        }
+
+        PublicKey key = identity.getPublicKey();
+        if (key != null && keys.containsKey(key)) {
+            throw new KeyManagementException("key '" + key + "' is already used");
+        }
+
+        names.put(name, identity);
+        if (key != null) {
+            keys.put(key, identity);
+        }
+    }
+
+    /**
+     * @see java.security.IdentityScope#removeIdentity(java.security.Identity)
+     */
+    public synchronized void removeIdentity(Identity identity)
+            throws KeyManagementException {
+
+        //Exception caught = null;
+        if (identity == null) {
+            throw new NullPointerException("identity == null");
+        }
+
+        String name = identity.getName();
+        if (name == null) {
+            throw new NullPointerException("name == null");
+        }
+
+        boolean contains = names.containsKey(name);
+        names.remove(name);
+
+        PublicKey key = identity.getPublicKey();
+
+        if (key != null) {
+            contains = contains || keys.containsKey(key);
+            keys.remove(key);
+        }
+
+        if (!contains) {
+            throw new KeyManagementException("identity not found");
+        }
+    }
+
+    /**
+     * @see java.security.IdentityScope#identities()
+     */
+    public Enumeration identities() {
+        return names.elements();
+    }
+}