Author: ivaynberg
Date: Mon May 17 21:19:50 2010
New Revision: 945368
URL: http://svn.apache.org/viewvc?rev=945368&view=rev
Log:
wicket-ioc: non-performant Collections.synchronizedMap() should be replaced
with ConcurrentMap
Issue: WICKET-2741
Added:
wicket/branches/wicket-1.4.x/wicket/src/main/java/org/apache/wicket/util/collections/ClassMetaCache.java
(with props)
Modified:
wicket/branches/wicket-1.4.x/wicket-ioc/src/main/java/org/apache/wicket/injection/Injector.java
Modified:
wicket/branches/wicket-1.4.x/wicket-ioc/src/main/java/org/apache/wicket/injection/Injector.java
URL:
http://svn.apache.org/viewvc/wicket/branches/wicket-1.4.x/wicket-ioc/src/main/java/org/apache/wicket/injection/Injector.java?rev=945368&r1=945367&r2=945368&view=diff
==============================================================================
---
wicket/branches/wicket-1.4.x/wicket-ioc/src/main/java/org/apache/wicket/injection/Injector.java
(original)
+++
wicket/branches/wicket-1.4.x/wicket-ioc/src/main/java/org/apache/wicket/injection/Injector.java
Mon May 17 21:19:50 2010
@@ -18,17 +18,14 @@ package org.apache.wicket.injection;
import java.lang.reflect.Field;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
-import java.util.Map;
-import java.util.WeakHashMap;
-import java.util.concurrent.ConcurrentHashMap;
import org.apache.wicket.Component;
import org.apache.wicket.MarkupContainer;
import org.apache.wicket.Page;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.util.collections.ClassMetaCache;
/**
* Injector scans fields of an object instance and checks if the specified
@@ -40,9 +37,11 @@ import org.apache.wicket.markup.html.pan
*/
public class Injector
{
+ private static final Field[] EMPTY_FIELDS = new Field[0];
+
private static Injector instance = new Injector();
- private final Map<ClassLoader, ConcurrentHashMap<String, Field[]>>
cache = Collections.synchronizedMap(new WeakHashMap<ClassLoader,
ConcurrentHashMap<String, Field[]>>());
+ private final ClassMetaCache<Field[]> cache = new
ClassMetaCache<Field[]>();
/**
* @return static instance of ProxyInjector
@@ -85,24 +84,7 @@ public class Injector
{
final Class<?> clazz = object.getClass();
- Field[] fields = null;
-
- // try cache
- ConcurrentHashMap<String, Field[]> container =
cache.get(clazz.getClassLoader());
- if (container != null)
- {
- fields = container.get(clazz.getName());
- }
-
- if (fields == null)
- {
- fields = findFields(clazz, factory);
-
- // write to cache
- container = new ConcurrentHashMap<String, Field[]>();
- container.put(clazz.getName(), fields);
- cache.put(clazz.getClassLoader(), container);
- }
+ Field[] fields = getFields(clazz, factory);
for (int i = 0; i < fields.length; i++)
{
@@ -142,6 +124,28 @@ public class Injector
}
/**
+ * caches results of {...@link #getFields(Class, IFieldValueFactory)}
+ *
+ * @param clazz
+ * @param factory
+ * @return cached results as returned by {...@link #getFields(Class,
IFieldValueFactory)}
+ */
+ private Field[] getFields(Class<?> clazz, IFieldValueFactory factory)
+ {
+ Field[] fields = cache.get(clazz);
+
+ if (fields == null)
+ {
+ fields = findFields(clazz, factory);
+
+ // write to cache
+ cache.put(clazz, fields);
+ }
+
+ return fields;
+ }
+
+ /**
* Returns an array of fields that can be injected using the given
field value factory
*
* @param clazz
@@ -167,7 +171,6 @@ public class Injector
clazz = clazz.getSuperclass();
}
- return matched.toArray(new Field[matched.size()]);
+ return matched.size() == 0 ? EMPTY_FIELDS : matched.toArray(new
Field[matched.size()]);
}
-
}
Added:
wicket/branches/wicket-1.4.x/wicket/src/main/java/org/apache/wicket/util/collections/ClassMetaCache.java
URL:
http://svn.apache.org/viewvc/wicket/branches/wicket-1.4.x/wicket/src/main/java/org/apache/wicket/util/collections/ClassMetaCache.java?rev=945368&view=auto
==============================================================================
---
wicket/branches/wicket-1.4.x/wicket/src/main/java/org/apache/wicket/util/collections/ClassMetaCache.java
(added)
+++
wicket/branches/wicket-1.4.x/wicket/src/main/java/org/apache/wicket/util/collections/ClassMetaCache.java
Mon May 17 21:19:50 2010
@@ -0,0 +1,101 @@
+package org.apache.wicket.util.collections;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.WeakHashMap;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * This class wraps a WeakHashMap that holds one ConcurrentHashMap per
ClassLoader. In the rare
+ * event of a previously unmapped ClassLoader, the WeakHashMap is replaced by
a new one. This avoids
+ * any synchronization overhead, much like a {...@link
java.util.concurrent.CopyOnWriteArrayList}
+ *
+ * @param <T>
+ * type of objects stored in cache
+ */
+public class ClassMetaCache<T>
+{
+ private volatile Map<ClassLoader, ConcurrentHashMap<String, T>> cache =
Collections.emptyMap();
+
+ /**
+ * Puts value into cache
+ *
+ * @param key
+ * @param value
+ * @return value previously stored in cache for this key, or {...@code
null} if none
+ */
+ public T put(Class<?> key, T value)
+ {
+ ConcurrentHashMap<String, T> container =
getClassLoaderCache(key.getClassLoader(), true);
+ return container.put(key(key), value);
+ }
+
+ /**
+ * Gets value from cache or returns {...@code null} if not in cache
+ *
+ * @param key
+ * @return value stored in cache or {...@code null} if none
+ */
+ public T get(Class<?> key)
+ {
+ ConcurrentHashMap<String, T> container =
getClassLoaderCache(key.getClassLoader(), false);
+ if (container == null)
+ {
+ return null;
+ }
+ else
+ {
+ return container.get(key(key));
+ }
+ }
+
+ /**
+ * @param classLoader
+ * @param create
+ * @return a {...@link ConcurrentHashMap} mapping class names to
injectable fields, never
+ * <code>null</code>
+ */
+ private ConcurrentHashMap<String, T> getClassLoaderCache(ClassLoader
classLoader, boolean create)
+ {
+ ConcurrentHashMap<String, T> container = cache.get(classLoader);
+ if (container == null)
+ {
+ if (!create)
+ {
+ return container;
+ }
+
+ // only lock in rare event of unknown ClassLoader
+ synchronized (this)
+ {
+ // check again inside lock
+ container = cache.get(classLoader);
+ if (container == null)
+ {
+ container = new
ConcurrentHashMap<String, T>();
+
+ /*
+ * don't write to current cache, copy
instead
+ */
+ Map<ClassLoader,
ConcurrentHashMap<String, T>> newCache = new WeakHashMap<ClassLoader,
ConcurrentHashMap<String, T>>(
+ cache);
+ newCache.put(classLoader, container);
+ cache =
Collections.unmodifiableMap(newCache);
+ }
+ }
+ }
+ return container;
+ }
+
+ /**
+ * converts class into a key used by the cache
+ *
+ * @param clazz
+ *
+ * @return string representation of the clazz
+ */
+ private static String key(Class<?> clazz)
+ {
+ return clazz.getName();
+ }
+}
\ No newline at end of file
Propchange:
wicket/branches/wicket-1.4.x/wicket/src/main/java/org/apache/wicket/util/collections/ClassMetaCache.java
------------------------------------------------------------------------------
svn:mime-type = text/plain