geronimo-scm mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rmannibu...@apache.org
Subject svn commit: r1760332 - in /geronimo/specs/trunk/geronimo-json_1.0_spec: ./ src/main/java/javax/json/spi/ src/test/ src/test/java/ src/test/java/javax/ src/test/java/javax/json/ src/test/java/javax/json/spi/ src/test/resources/ src/test/resources/META-I...
Date Mon, 12 Sep 2016 10:32:14 GMT
Author: rmannibucau
Date: Mon Sep 12 10:32:14 2016
New Revision: 1760332

URL: http://svn.apache.org/viewvc?rev=1760332&view=rev
Log:
ensuring using Json class doesn't lead to perf issues caching the provider per classloader
(we can't do better without being specific)

Added:
    geronimo/specs/trunk/geronimo-json_1.0_spec/src/test/
    geronimo/specs/trunk/geronimo-json_1.0_spec/src/test/java/
    geronimo/specs/trunk/geronimo-json_1.0_spec/src/test/java/javax/
    geronimo/specs/trunk/geronimo-json_1.0_spec/src/test/java/javax/json/
    geronimo/specs/trunk/geronimo-json_1.0_spec/src/test/java/javax/json/spi/
    geronimo/specs/trunk/geronimo-json_1.0_spec/src/test/java/javax/json/spi/JsonProviderTest.java
    geronimo/specs/trunk/geronimo-json_1.0_spec/src/test/resources/
    geronimo/specs/trunk/geronimo-json_1.0_spec/src/test/resources/META-INF/
    geronimo/specs/trunk/geronimo-json_1.0_spec/src/test/resources/META-INF/services/
    geronimo/specs/trunk/geronimo-json_1.0_spec/src/test/resources/META-INF/services/javax.json.spi.JsonProvider
Modified:
    geronimo/specs/trunk/geronimo-json_1.0_spec/pom.xml
    geronimo/specs/trunk/geronimo-json_1.0_spec/src/main/java/javax/json/spi/JsonProvider.java

Modified: geronimo/specs/trunk/geronimo-json_1.0_spec/pom.xml
URL: http://svn.apache.org/viewvc/geronimo/specs/trunk/geronimo-json_1.0_spec/pom.xml?rev=1760332&r1=1760331&r2=1760332&view=diff
==============================================================================
--- geronimo/specs/trunk/geronimo-json_1.0_spec/pom.xml (original)
+++ geronimo/specs/trunk/geronimo-json_1.0_spec/pom.xml Mon Sep 12 10:32:14 2016
@@ -68,6 +68,15 @@
     </repository>
   </repositories>
 
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.12</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
   <build>
     <plugins>
       <plugin>

Modified: geronimo/specs/trunk/geronimo-json_1.0_spec/src/main/java/javax/json/spi/JsonProvider.java
URL: http://svn.apache.org/viewvc/geronimo/specs/trunk/geronimo-json_1.0_spec/src/main/java/javax/json/spi/JsonProvider.java?rev=1760332&r1=1760331&r2=1760332&view=diff
==============================================================================
--- geronimo/specs/trunk/geronimo-json_1.0_spec/src/main/java/javax/json/spi/JsonProvider.java
(original)
+++ geronimo/specs/trunk/geronimo-json_1.0_spec/src/main/java/javax/json/spi/JsonProvider.java
Mon Sep 12 10:32:14 2016
@@ -35,102 +35,30 @@ import java.io.InputStreamReader;
 import java.io.OutputStream;
 import java.io.Reader;
 import java.io.Writer;
+import java.lang.ref.WeakReference;
 import java.lang.reflect.Method;
 import java.net.URL;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
-import java.util.ArrayList;
 import java.util.Enumeration;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.ServiceLoader;
+import java.util.WeakHashMap;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 public abstract class JsonProvider {
     private static final String DEFAULT_PROVIDER = "org.apache.johnzon.core.JsonProviderImpl";
 
+    private static final Cache CACHE = new Cache();
+
     protected JsonProvider() {
         // no-op
     }
 
     public static JsonProvider provider() {
-        if (System.getSecurityManager() != null) {
-            return AccessController.doPrivileged(new PrivilegedAction<JsonProvider>()
{
-                public JsonProvider run() {
-                    return doLoadProvider();
-                }
-            });
-        }
-        return doLoadProvider();
-    }
-
-    private static JsonProvider doLoadProvider() throws JsonException {
-        final ClassLoader tccl = Thread.currentThread().getContextClassLoader();
-        try {
-            final Class<?> clazz = Class.forName("org.apache.geronimo.osgi.locator.ProviderLocator");
-            final Method getServices = clazz.getDeclaredMethod("getServices", String.class,
Class.class, ClassLoader.class);
-            final List<JsonProvider> osgiProviders = (List<JsonProvider>) getServices.invoke(null,
JsonProvider.class.getName(), JsonProvider.class, tccl);
-            if (osgiProviders != null && !osgiProviders.isEmpty()) {
-                return osgiProviders.iterator().next();
-            }
-        } catch (final Throwable e) {
-            // locator not available, try normal mode
-        }
-
-        // don't use Class.forName() to avoid to bind class to tccl if thats a classloader
facade
-        // so implementing a simple SPI when ProviderLocator is not here
-        final String name = "META-INF/services/" + JsonProvider.class.getName();
-        try {
-            Enumeration<URL> configs;
-            if (tccl == null) {
-                configs = ClassLoader.getSystemResources(name);
-            } else {
-                configs = tccl.getResources(name);
-            }
-
-            if (configs.hasMoreElements()) {
-                InputStream in = null;
-                BufferedReader r = null;
-                final List<String> names = new ArrayList<String>();
-                try {
-                    in = configs.nextElement().openStream();
-                    r = new BufferedReader(new InputStreamReader(in, "utf-8"));
-                    String l;
-                    while ((l = r.readLine()) != null) {
-                        if (l.startsWith("#")) {
-                            continue;
-                        }
-                        return JsonProvider.class.cast(tccl.loadClass(l).newInstance());
-                    }
-                } catch (final IOException x) {
-                    // no-op
-                } finally {
-                    try {
-                        if (r != null) {
-                            r.close();
-                        }
-                    } catch (final IOException y) {
-                        // no-op
-                    }
-                    try {
-                        if (in != null) {
-                            in.close();
-                        }
-                    } catch (final IOException y) {
-                        // no-op
-                    }
-                }
-            }
-        } catch (final Exception ex) {
-            // no-op
-        }
-
-        try {
-            final Class<?> clazz = tccl.loadClass(DEFAULT_PROVIDER);
-            return JsonProvider.class.cast(clazz.newInstance());
-        } catch (final Throwable cnfe) {
-            throw new JsonException(DEFAULT_PROVIDER + " not found", cnfe);
-        }
+        return CACHE.get();
     }
 
     public abstract JsonParser createParser(Reader reader);
@@ -162,5 +90,138 @@ public abstract class JsonProvider {
     public abstract JsonArrayBuilder createArrayBuilder();
 
     public abstract JsonBuilderFactory createBuilderFactory(Map<String, ?> config);
+
+    private static class Cache {
+        private final WeakHashMap<ClassLoader, WeakReference<JsonProvider>> cachingProviders
= new WeakHashMap<ClassLoader, WeakReference<JsonProvider>>();
+        private final ReadWriteLock lock = new ReentrantReadWriteLock();
+
+        private JsonProvider get() { // in term of synchro we don't prevent to load multiple
times the provider
+            ClassLoader key = Thread.currentThread().getContextClassLoader();
+            if (key == null) {
+                key = ClassLoader.getSystemClassLoader();
+            }
+
+            final WeakReference<JsonProvider> reference;
+            final Lock readLock = this.lock.readLock();
+            readLock.lock();
+            try {
+                reference = cachingProviders.get(key);
+            } finally {
+                readLock.unlock();
+            }
+
+            JsonProvider provider = null;
+            if (reference != null) {
+                provider = reference.get();
+            }
+            if (provider != null) {
+                return provider;
+            }
+
+            if (System.getSecurityManager() != null) {
+                provider = AccessController.doPrivileged(new PrivilegedAction<JsonProvider>()
{
+                    public JsonProvider run() {
+                        return doLoadProvider();
+                    }
+                });
+            } else {
+                provider = doLoadProvider();
+            }
+
+            final Lock writeLock = this.lock.writeLock();
+            writeLock.lock();
+            try {
+                boolean put = true;
+                final WeakReference<JsonProvider> existing = cachingProviders.get(key);
+                if (existing != null) {
+                    final JsonProvider p = existing.get();
+                    if (p != null) {
+                        provider = p;
+                        put = false;
+                    }
+                }
+                if (put) {
+                    cachingProviders.put(key, new WeakReference<JsonProvider>(provider));
+                }
+            } finally {
+                writeLock.unlock();
+            }
+
+            return provider;
+        }
+
+        private static JsonProvider doLoadProvider() throws JsonException {
+            ClassLoader tccl = Thread.currentThread().getContextClassLoader();
+            if (tccl == null) {
+                tccl = ClassLoader.getSystemClassLoader();
+            }
+            try {
+                final Class<?> clazz = Class.forName("org.apache.geronimo.osgi.locator.ProviderLocator");
+                final Method getServices = clazz.getDeclaredMethod("getServices", String.class,
Class.class, ClassLoader.class);
+                final List<JsonProvider> osgiProviders = (List<JsonProvider>)
getServices.invoke(null, JsonProvider.class.getName(), JsonProvider.class, tccl);
+                if (osgiProviders != null && !osgiProviders.isEmpty()) {
+                    return osgiProviders.iterator().next();
+                }
+            } catch (final Throwable e) {
+                // locator not available, try normal mode
+            }
+
+            final String className = System.getProperty(JsonProvider.class.getName());
+            if (className != null) {
+                try {
+                    return JsonProvider.class.cast(tccl.loadClass(className.trim()).newInstance());
+                } catch (final Exception e) {
+                    throw new JsonException("Specified provider as system property can't
be loaded: " + className, e);
+                }
+            }
+
+            // don't use Class.forName() to avoid to bind class to tccl if thats a classloader
facade
+            // so implementing a simple SPI when ProviderLocator is not here
+            final String name = "META-INF/services/" + JsonProvider.class.getName();
+            try {
+                final Enumeration<URL> configs = tccl.getResources(name);
+                if (configs.hasMoreElements()) {
+                    InputStream in = null;
+                    BufferedReader r = null;
+                    try {
+                        in = configs.nextElement().openStream();
+                        r = new BufferedReader(new InputStreamReader(in, "utf-8"));
+                        String l;
+                        while ((l = r.readLine()) != null) {
+                            if (l.startsWith("#")) {
+                                continue;
+                            }
+                            return JsonProvider.class.cast(tccl.loadClass(l).newInstance());
+                        }
+                    } catch (final IOException x) {
+                        // no-op
+                    } finally {
+                        try {
+                            if (r != null) {
+                                r.close();
+                            }
+                        } catch (final IOException y) {
+                            // no-op
+                        }
+                        try {
+                            if (in != null) {
+                                in.close();
+                            }
+                        } catch (final IOException y) {
+                            // no-op
+                        }
+                    }
+                }
+            } catch (final Exception ex) {
+                // no-op
+            }
+
+            try {
+                return JsonProvider.class.cast(tccl.loadClass(DEFAULT_PROVIDER).newInstance());
+            } catch (final Throwable cnfe) {
+                throw new JsonException(DEFAULT_PROVIDER + " not found", cnfe);
+            }
+        }
+    }
 }
 

Added: geronimo/specs/trunk/geronimo-json_1.0_spec/src/test/java/javax/json/spi/JsonProviderTest.java
URL: http://svn.apache.org/viewvc/geronimo/specs/trunk/geronimo-json_1.0_spec/src/test/java/javax/json/spi/JsonProviderTest.java?rev=1760332&view=auto
==============================================================================
--- geronimo/specs/trunk/geronimo-json_1.0_spec/src/test/java/javax/json/spi/JsonProviderTest.java
(added)
+++ geronimo/specs/trunk/geronimo-json_1.0_spec/src/test/java/javax/json/spi/JsonProviderTest.java
Mon Sep 12 10:32:14 2016
@@ -0,0 +1,148 @@
+/*
+ * 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.json.spi;
+
+import org.junit.Test;
+
+import javax.json.JsonArrayBuilder;
+import javax.json.JsonBuilderFactory;
+import javax.json.JsonObjectBuilder;
+import javax.json.JsonReader;
+import javax.json.JsonReaderFactory;
+import javax.json.JsonWriter;
+import javax.json.JsonWriterFactory;
+import javax.json.stream.JsonGenerator;
+import javax.json.stream.JsonGeneratorFactory;
+import javax.json.stream.JsonParser;
+import javax.json.stream.JsonParserFactory;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.Writer;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Map;
+
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+
+public class JsonProviderTest {
+    @Test
+    public void cache() {
+        final JsonProvider provider = JsonProvider.provider();
+        for (int i = 0; i < 10; i++) {
+            final JsonProvider reload = JsonProvider.provider();
+            assertSame(provider, reload);
+        }
+    }
+
+    @Test
+    public void cacheByClassLoader() {
+        final JsonProvider provider = JsonProvider.provider();
+
+        final Thread thread = Thread.currentThread();
+        final URLClassLoader loader = new URLClassLoader(new URL[0], thread.getContextClassLoader());
+        thread.setContextClassLoader(loader);
+        try {
+            final JsonProvider subLoaderProvider = JsonProvider.provider();
+            for (int i = 0; i < 10; i++) {
+                final JsonProvider reload = JsonProvider.provider();
+                assertNotSame(provider, reload);
+                assertSame(subLoaderProvider, reload);
+            }
+        } finally {
+            thread.setContextClassLoader(loader.getParent());
+        }
+    }
+
+    public static class AProvider extends JsonProvider {
+        @Override
+        public JsonParser createParser(final Reader reader) {
+            return null;
+        }
+
+        @Override
+        public JsonParser createParser(final InputStream in) {
+            return null;
+        }
+
+        @Override
+        public JsonParserFactory createParserFactory(final Map<String, ?> config) {
+            return null;
+        }
+
+        @Override
+        public JsonGenerator createGenerator(final Writer writer) {
+            return null;
+        }
+
+        @Override
+        public JsonGenerator createGenerator(final OutputStream out) {
+            return null;
+        }
+
+        @Override
+        public JsonGeneratorFactory createGeneratorFactory(final Map<String, ?> config)
{
+            return null;
+        }
+
+        @Override
+        public JsonReader createReader(final Reader reader) {
+            return null;
+        }
+
+        @Override
+        public JsonReader createReader(final InputStream in) {
+            return null;
+        }
+
+        @Override
+        public JsonWriter createWriter(final Writer writer) {
+            return null;
+        }
+
+        @Override
+        public JsonWriter createWriter(final OutputStream out) {
+            return null;
+        }
+
+        @Override
+        public JsonWriterFactory createWriterFactory(final Map<String, ?> config) {
+            return null;
+        }
+
+        @Override
+        public JsonReaderFactory createReaderFactory(final Map<String, ?> config) {
+            return null;
+        }
+
+        @Override
+        public JsonObjectBuilder createObjectBuilder() {
+            return null;
+        }
+
+        @Override
+        public JsonArrayBuilder createArrayBuilder() {
+            return null;
+        }
+
+        @Override
+        public JsonBuilderFactory createBuilderFactory(final Map<String, ?> config)
{
+            return null;
+        }
+    }
+}

Added: geronimo/specs/trunk/geronimo-json_1.0_spec/src/test/resources/META-INF/services/javax.json.spi.JsonProvider
URL: http://svn.apache.org/viewvc/geronimo/specs/trunk/geronimo-json_1.0_spec/src/test/resources/META-INF/services/javax.json.spi.JsonProvider?rev=1760332&view=auto
==============================================================================
--- geronimo/specs/trunk/geronimo-json_1.0_spec/src/test/resources/META-INF/services/javax.json.spi.JsonProvider
(added)
+++ geronimo/specs/trunk/geronimo-json_1.0_spec/src/test/resources/META-INF/services/javax.json.spi.JsonProvider
Mon Sep 12 10:32:14 2016
@@ -0,0 +1 @@
+javax.json.spi.JsonProviderTest$AProvider



Mime
View raw message