You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2008/12/19 03:48:37 UTC
svn commit: r727901 -
/tapestry/tapestry5/branches/hlship-5.0-perf/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java
Author: hlship
Date: Thu Dec 18 18:48:37 2008
New Revision: 727901
URL: http://svn.apache.org/viewvc?rev=727901&view=rev
Log:
TAP5-417: Tapestry 5.0 Performance Improvements
- Rework how TypeCoercer organizes its internal caches
Modified:
tapestry/tapestry5/branches/hlship-5.0-perf/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java
Modified: tapestry/tapestry5/branches/hlship-5.0-perf/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/branches/hlship-5.0-perf/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java?rev=727901&r1=727900&r2=727901&view=diff
==============================================================================
--- tapestry/tapestry5/branches/hlship-5.0-perf/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java (original)
+++ tapestry/tapestry5/branches/hlship-5.0-perf/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java Thu Dec 18 18:48:37 2008
@@ -15,8 +15,8 @@
package org.apache.tapestry5.ioc.internal.services;
import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import static org.apache.tapestry5.ioc.internal.util.CollectionFactory.*;
-import static org.apache.tapestry5.ioc.internal.util.Defense.notNull;
+import static org.apache.tapestry5.ioc.internal.util.CollectionFactory.newList;
+import org.apache.tapestry5.ioc.internal.util.Defense;
import org.apache.tapestry5.ioc.internal.util.InheritanceSearch;
import org.apache.tapestry5.ioc.internal.util.InternalUtils;
import org.apache.tapestry5.ioc.services.ClassFabUtils;
@@ -28,53 +28,75 @@
public class TypeCoercerImpl implements TypeCoercer
{
- // Read only after constructor
+ // Constructed from the service's configuration.
private final Map<Class, List<CoercionTuple>> sourceTypeToTuple = CollectionFactory.newMap();
- // Access to the cache must be thread safe
-
- private final Map<CacheKey, Coercion> cache = CollectionFactory.newConcurrentMap();
-
- static class CacheKey
+ /**
+ * A coercion to a specific target type. Manages a cache of coercions to specific types.
+ */
+ private class TargetCoercion
{
- private final Class sourceClass;
+ private final Class type;
- private final Class targetClass;
+ private final Map<Class, Coercion> cache = CollectionFactory.newConcurrentMap();
- CacheKey(final Class sourceClass, final Class targetClass)
+ TargetCoercion(Class type)
{
- this.sourceClass = sourceClass;
- this.targetClass = targetClass;
+ this.type = type;
}
- @Override
- public boolean equals(Object obj)
+ void clearCache()
{
- if (obj == null) return false;
+ cache.clear();
+ }
- if (!(obj instanceof CacheKey)) return false;
+ Object coerce(Object input)
+ {
+
+ Class sourceType = input != null ? input.getClass() : void.class;
+
+ if (type.isAssignableFrom(sourceType)) return input;
- CacheKey other = (CacheKey) obj;
+ Coercion c = getCoercion(sourceType);
- return sourceClass.equals(other.sourceClass)
- && targetClass.equals(other.targetClass);
+ try
+ {
+ return type.cast(c.coerce(input));
+ }
+ catch (Exception ex)
+ {
+ throw new RuntimeException(ServiceMessages.failedCoercion(
+ input,
+ type,
+ c,
+ ex), ex);
+ }
}
- @Override
- public int hashCode()
+ String explain(Class sourceType)
{
- return sourceClass.hashCode() * 27 % targetClass.hashCode();
+ return getCoercion(sourceType).toString();
}
- @Override
- public String toString()
+ private Coercion getCoercion(Class sourceType)
{
- return String.format("CacheKey[%s --> %s]", sourceClass.getName(), targetClass
- .getName());
+ Coercion c = cache.get(sourceType);
+
+ if (c == null)
+ {
+ c = findOrCreateCoercion(sourceType, type);
+ cache.put(sourceType, c);
+ }
+ return c;
}
}
+ /**
+ * Map from a target type to a TargetCoercion for that type.
+ */
+ private final Map<Class, TargetCoercion> typeToTargetCoercion = new WeakHashMap<Class, TargetCoercion>();
+
private static final Coercion COERCION_NULL_TO_OBJECT = new Coercion<Void, Object>()
{
public Object coerce(Void input)
@@ -102,49 +124,20 @@
@SuppressWarnings("unchecked")
public Object coerce(Object input, Class targetType)
{
- notNull(targetType, "targetType");
-
- // Treat null as void in terms of locating a coercion.
-
- Class sourceType = input != null ? input.getClass() : void.class;
-
- // The caller may ask for the value in a primitive type, but the best we can do is the
- // equivalent wrapper type.
+ Defense.notNull(targetType, "targetType");
Class effectiveTargetType = ClassFabUtils.getWrapperType(targetType);
- // Is a coercion even necessary? Not if the target type is assignable from the
- // input value.
-
- if (effectiveTargetType.isAssignableFrom(sourceType)) return input;
+ if (effectiveTargetType.isInstance(input)) return input;
- Coercion coercion = findCoercion(sourceType, effectiveTargetType);
-
- Object result;
-
- try
- {
- result = coercion.coerce(input);
- }
- catch (Exception ex)
- {
- throw new RuntimeException(ServiceMessages.failedCoercion(
- input,
- targetType,
- coercion,
- ex), ex);
- }
-
- // Double check that the coercer provided a result of the correct type
-
- return effectiveTargetType.cast(result);
+ return getTargetCoercion(effectiveTargetType).coerce(input);
}
@SuppressWarnings("unchecked")
public <S, T> String explain(Class<S> inputType, Class<T> targetType)
{
- notNull(inputType, "inputType");
- notNull(targetType, "targetType");
+ Defense.notNull(inputType, "inputType");
+ Defense.notNull(targetType, "targetType");
Class effectiveTargetType = ClassFabUtils.getWrapperType(targetType);
@@ -153,29 +146,35 @@
if (effectiveTargetType.isAssignableFrom(inputType)) return "";
- Coercion coercion = findCoercion(inputType, effectiveTargetType);
-
- return coercion.toString();
+ return getTargetCoercion(targetType).explain(inputType);
}
- private Coercion findCoercion(Class sourceType, Class targetType)
+ private synchronized TargetCoercion getTargetCoercion(Class targetType)
{
- CacheKey key = new CacheKey(sourceType, targetType);
-
- Coercion result = cache.get(key);
+ TargetCoercion tc = typeToTargetCoercion.get(targetType);
- if (result == null)
+ if (tc == null)
{
- result = findOrCreateCoercion(sourceType, targetType);
- cache.put(key, result);
+ tc = new TargetCoercion(targetType);
+ typeToTargetCoercion.put(targetType, tc);
}
- return result;
+ return tc;
}
- public void clearCache()
+ public synchronized void clearCache()
{
- cache.clear();
+ // There's no need to clear the typeToTargetCoercion map, as it is a WeakHashMap and
+ // will release the keys for classes that are no longer in existence. On the other hand,
+ // there's likely all sorts of references to unloaded classes inside each TargetCoercion's
+ // individual cache, so clear all those.
+
+ for (TargetCoercion tc : typeToTargetCoercion.values())
+ {
+ // Can tc ever be null?
+
+ tc.clearCache();
+ }
}
/**
@@ -211,8 +210,8 @@
// a tuple twice, but it's more likely that different threads are looking
// for different source/target coercions.
- Set<CoercionTuple> consideredTuples = newSet();
- LinkedList<CoercionTuple> queue = newLinkedList();
+ Set<CoercionTuple> consideredTuples = CollectionFactory.newSet();
+ LinkedList<CoercionTuple> queue = CollectionFactory.newLinkedList();
seedQueue(sourceType, consideredTuples, queue);
@@ -378,5 +377,4 @@
}
}
}
-
}