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 2012/06/06 19:08:15 UTC

[1/2] git commit: TAP5-1929: Convert more synchronized blocks to ReentrantReadWriteLock

Updated Branches:
  refs/heads/5.3 63fe85d14 -> bb940c080


TAP5-1929: Convert more synchronized blocks to ReentrantReadWriteLock


Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/bb940c08
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/bb940c08
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/bb940c08

Branch: refs/heads/5.3
Commit: bb940c080f77856b520fd39b28c38d38b5609c1f
Parents: 15477fd
Author: Howard M. Lewis Ship <hl...@apache.org>
Authored: Wed Jun 6 10:08:02 2012 -0700
Committer: Howard M. Lewis Ship <hl...@apache.org>
Committed: Wed Jun 6 10:08:02 2012 -0700

----------------------------------------------------------------------
 .../internal/services/ContextResource.java         |    7 +-
 .../ioc/internal/services/TypeCoercerImpl.java     |  168 ++++++++++-----
 .../ioc/internal/util/AbstractResource.java        |   30 +---
 .../ioc/internal/util/ClasspathResource.java       |    6 +-
 .../tapestry5/ioc/internal/util/LockSupport.java   |   85 ++++++++
 .../tapestry5/ioc/internal/util/OneShotLock.java   |   36 +++-
 .../tapestry5/ioc/services/CoercionTuple.java      |   30 ++--
 .../tapestry5/ioc/services/TapestryIOCModule.java  |    4 +-
 8 files changed, 251 insertions(+), 115 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/bb940c08/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ContextResource.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ContextResource.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ContextResource.java
index 681424f..f5337b2 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ContextResource.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ContextResource.java
@@ -1,4 +1,4 @@
-// Copyright 2006, 2008, 2010 The Apache Software Foundation
+// Copyright 2006, 2008, 2010, 2012 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -62,8 +62,7 @@ public class ContextResource extends AbstractResource
     {
         try
         {
-            lock.readLock().lock();
-
+            acquireReadLock();
             if (!urlResolved)
             {
                 resolveURL();
@@ -73,7 +72,7 @@ public class ContextResource extends AbstractResource
 
         } finally
         {
-            lock.readLock().unlock();
+            releaseReadLock();
         }
     }
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/bb940c08/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java
index f92f88c..ba40500 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007, 2008, 2010 The Apache Software Foundation
+// Copyright 2006, 2007, 2008, 2010, 2012 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -14,28 +14,23 @@
 
 package org.apache.tapestry5.ioc.internal.services;
 
-import java.util.Collection;
-import java.util.Collections;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.WeakHashMap;
-
 import org.apache.tapestry5.func.F;
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
 import org.apache.tapestry5.ioc.internal.util.InheritanceSearch;
 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-import org.apache.tapestry5.ioc.services.ClassFabUtils;
+import org.apache.tapestry5.ioc.internal.util.LockSupport;
 import org.apache.tapestry5.ioc.services.Coercion;
 import org.apache.tapestry5.ioc.services.CoercionTuple;
 import org.apache.tapestry5.ioc.services.TypeCoercer;
 import org.apache.tapestry5.ioc.util.AvailableValues;
 import org.apache.tapestry5.ioc.util.UnknownValueException;
+import org.apache.tapestry5.plastic.PlasticUtils;
 import org.apache.tapestry5.util.StringToEnumCoercion;
 
+import java.util.*;
+
 @SuppressWarnings("all")
-public class TypeCoercerImpl implements TypeCoercer
+public class TypeCoercerImpl extends LockSupport implements TypeCoercer
 {
     // Constructed from the service's configuration.
 
@@ -62,19 +57,19 @@ public class TypeCoercerImpl implements TypeCoercer
 
         Object coerce(Object input)
         {
-
-            Class sourceType = input != null ? input.getClass() : void.class;
+            Class sourceType = input != null ? input.getClass() : Void.class;
 
             if (type.isAssignableFrom(sourceType))
+            {
                 return input;
+            }
 
             Coercion c = getCoercion(sourceType);
 
             try
             {
                 return type.cast(c.coerce(input));
-            }
-            catch (Exception ex)
+            } catch (Exception ex)
             {
                 throw new RuntimeException(ServiceMessages.failedCoercion(input, type, c, ex), ex);
             }
@@ -94,6 +89,7 @@ public class TypeCoercerImpl implements TypeCoercer
                 c = findOrCreateCoercion(sourceType, type);
                 cache.put(sourceType, c);
             }
+
             return c;
         }
     }
@@ -139,10 +135,13 @@ public class TypeCoercerImpl implements TypeCoercer
     public Object coerce(Object input, Class targetType)
     {
         assert targetType != null;
-        Class effectiveTargetType = ClassFabUtils.getWrapperType(targetType);
+        Class effectiveTargetType = PlasticUtils.toWrapperType(targetType);
 
         if (effectiveTargetType.isInstance(input))
+        {
             return input;
+        }
+
 
         return getTargetCoercion(effectiveTargetType).coerce(input);
     }
@@ -152,11 +151,13 @@ public class TypeCoercerImpl implements TypeCoercer
     {
         assert sourceType != null;
         assert targetType != null;
-        Class effectiveSourceType = ClassFabUtils.getWrapperType(sourceType);
-        Class effectiveTargetType = ClassFabUtils.getWrapperType(targetType);
+        Class effectiveSourceType = PlasticUtils.toWrapperType(sourceType);
+        Class effectiveTargetType = PlasticUtils.toWrapperType(targetType);
 
         if (effectiveTargetType.isAssignableFrom(effectiveSourceType))
+        {
             return NO_COERCION;
+        }
 
         return getTargetCoercion(effectiveTargetType).getCoercion(effectiveSourceType);
     }
@@ -166,43 +167,78 @@ public class TypeCoercerImpl implements TypeCoercer
     {
         assert sourceType != null;
         assert targetType != null;
-        Class effectiveTargetType = ClassFabUtils.getWrapperType(targetType);
-        Class effectiveSourceType = ClassFabUtils.getWrapperType(sourceType);
+        Class effectiveTargetType = PlasticUtils.toWrapperType(targetType);
+        Class effectiveSourceType = PlasticUtils.toWrapperType(sourceType);
 
         // Is a coercion even necessary? Not if the target type is assignable from the
         // input value.
 
         if (effectiveTargetType.isAssignableFrom(effectiveSourceType))
+        {
             return "";
+        }
 
-        return getTargetCoercion(targetType).explain(sourceType);
+        return getTargetCoercion(effectiveTargetType).explain(effectiveSourceType);
     }
 
-    private synchronized TargetCoercion getTargetCoercion(Class targetType)
+    private TargetCoercion getTargetCoercion(Class targetType)
     {
-        TargetCoercion tc = typeToTargetCoercion.get(targetType);
+        try
+        {
+            acquireReadLock();
 
-        if (tc == null)
+            TargetCoercion tc = typeToTargetCoercion.get(targetType);
+
+            return tc != null ? tc : createAndStoreNewTargetCoercion(targetType);
+        } finally
         {
-            tc = new TargetCoercion(targetType);
-            typeToTargetCoercion.put(targetType, tc);
+            releaseReadLock();
         }
-
-        return tc;
     }
 
-    public synchronized void clearCache()
+    private TargetCoercion createAndStoreNewTargetCoercion(Class targetType)
     {
-        // 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.
+        try
+        {
+            upgradeReadLockToWriteLock();
+
+            // Inner check since some other thread may have beat us to it.
+
+            TargetCoercion tc = typeToTargetCoercion.get(targetType);
+
+            if (tc == null)
+            {
+                tc = new TargetCoercion(targetType);
+                typeToTargetCoercion.put(targetType, tc);
+            }
 
-        for (TargetCoercion tc : typeToTargetCoercion.values())
+            return tc;
+        } finally
         {
-            // Can tc ever be null?
+            downgradeWriteLockToReadLock();
+        }
+    }
+
+    public void clearCache()
+    {
+        try
+        {
+            acquireReadLock();
+
+            // 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.
 
-            tc.clearCache();
+            for (TargetCoercion tc : typeToTargetCoercion.values())
+            {
+                // Can tc ever be null?
+
+                tc.clearCache();
+            }
+        } finally
+        {
+            releaseReadLock();
         }
     }
 
@@ -219,13 +255,13 @@ public class TypeCoercerImpl implements TypeCoercer
      * tuples are added to the queue, there are two factors: size (the number of steps in the coercion) and
      * "class distance" (that is, number of steps up the inheritance hiearchy). All the appropriate 1 step coercions
      * will be considered first, in class distance order. Along the way, we'll queue up all the 2 step coercions, again
-     * in class distance order. By the time we reach some of those, we'll have begun queing up the 3 step coercions, and
+     * in class distance order. By the time we reach some of those, we'll have begun queueing up the 3 step coercions, and
      * so forth, until we run out of input tuples we can use to fabricate multi-step compound coercions, or reach a
      * final response.
      * <p/>
      * This does create a good number of short lived temporary objects (the compound tuples), but that's what the GC is
      * really good at.
-     * 
+     *
      * @param sourceType
      * @param targetType
      * @return coercer from sourceType to targetType
@@ -233,8 +269,10 @@ public class TypeCoercerImpl implements TypeCoercer
     @SuppressWarnings("unchecked")
     private Coercion findOrCreateCoercion(Class sourceType, Class targetType)
     {
-        if (sourceType == void.class)
+        if (sourceType == Void.class)
+        {
             return searchForNullCoercion(targetType);
+        }
 
         // These are instance variables because this method may be called concurrently.
         // On a true race, we may go to the work of seeking out and/or fabricating
@@ -259,7 +297,9 @@ public class TypeCoercerImpl implements TypeCoercer
             Class tupleTargetType = tuple.getTargetType();
 
             if (targetType.isAssignableFrom(tupleTargetType))
+            {
                 return tuple.getCoercion();
+            }
 
             // So .. this tuple doesn't get us directly to the target type.
             // However, it *may* get us part of the way. Each of these
@@ -281,14 +321,14 @@ public class TypeCoercerImpl implements TypeCoercer
      * Coercion from null is special; we match based on the target type and its not a spanning
      * search. In many cases, we
      * return a pass-thru that leaves the value as null.
-     * 
+     *
      * @param targetType
-     *            desired type
+     *         desired type
      * @return the coercion
      */
     private Coercion searchForNullCoercion(Class targetType)
     {
-        List<CoercionTuple> tuples = getTuples(void.class, targetType);
+        List<CoercionTuple> tuples = getTuples(Void.class, targetType);
 
         for (CoercionTuple tuple : tuples)
         {
@@ -325,7 +365,7 @@ public class TypeCoercerImpl implements TypeCoercer
      * Seeds the pool with the initial set of coercions for the given type.
      */
     private void seedQueue(Class sourceType, Class targetType, Set<CoercionTuple> consideredTuples,
-            LinkedList<CoercionTuple> queue)
+                           LinkedList<CoercionTuple> queue)
     {
         // Work from the source type up looking for tuples
 
@@ -334,7 +374,9 @@ public class TypeCoercerImpl implements TypeCoercer
             List<CoercionTuple> tuples = getTuples(c, targetType);
 
             if (tuples == null)
+            {
                 continue;
+            }
 
             for (CoercionTuple tuple : tuples)
             {
@@ -345,8 +387,10 @@ public class TypeCoercerImpl implements TypeCoercer
             // Don't pull in Object -> type coercions when doing
             // a search from null.
 
-            if (sourceType == void.class)
+            if (sourceType == Void.class)
+            {
                 return;
+            }
         }
     }
 
@@ -354,23 +398,23 @@ public class TypeCoercerImpl implements TypeCoercer
      * Creates and adds to the pool a new set of coercions based on an intermediate tuple. Adds
      * compound coercion tuples
      * to the end of the queue.
-     * 
+     *
      * @param sourceType
-     *            the source type of the coercion
+     *         the source type of the coercion
      * @param targetType
-     *            TODO
+     *         TODO
      * @param intermediateTuple
-     *            a tuple that converts from the source type to some intermediate type (that is not
-     *            assignable to the target type)
+     *         a tuple that converts from the source type to some intermediate type (that is not
+     *         assignable to the target type)
      * @param consideredTuples
-     *            set of tuples that have already been added to the pool (directly, or as a compound
-     *            coercion)
+     *         set of tuples that have already been added to the pool (directly, or as a compound
+     *         coercion)
      * @param queue
-     *            the work queue of tuples
+     *         the work queue of tuples
      */
     @SuppressWarnings("unchecked")
     private void queueIntermediates(Class sourceType, Class targetType, CoercionTuple intermediateTuple,
-            Set<CoercionTuple> consideredTuples, LinkedList<CoercionTuple> queue)
+                                    Set<CoercionTuple> consideredTuples, LinkedList<CoercionTuple> queue)
     {
         Class intermediateType = intermediateTuple.getTargetType();
 
@@ -379,7 +423,9 @@ public class TypeCoercerImpl implements TypeCoercer
             for (CoercionTuple tuple : getTuples(c, targetType))
             {
                 if (consideredTuples.contains(tuple))
+                {
                     continue;
+                }
 
                 Class newIntermediateType = tuple.getTargetType();
 
@@ -389,7 +435,9 @@ public class TypeCoercerImpl implements TypeCoercer
                 // eventually be considered and discarded.
 
                 if (sourceType.isAssignableFrom(newIntermediateType))
+                {
                     continue;
+                }
 
                 // The intermediateTuple coercer gets from S --> I1 (an intermediate type).
                 // The current tuple's coercer gets us from I2 --> X. where I2 is assignable
@@ -413,11 +461,11 @@ public class TypeCoercerImpl implements TypeCoercer
 
     /**
      * Returns a non-null list of the tuples from the source type.
-     * 
+     *
      * @param sourceType
-     *            used to locate tuples
+     *         used to locate tuples
      * @param targetType
-     *            used to add synthetic tuples
+     *         used to add synthetic tuples
      * @return non-null list of tuples
      */
     private List<CoercionTuple> getTuples(Class sourceType, Class targetType)
@@ -425,17 +473,21 @@ public class TypeCoercerImpl implements TypeCoercer
         List<CoercionTuple> tuples = sourceTypeToTuple.get(sourceType);
 
         if (tuples == null)
+        {
             tuples = Collections.emptyList();
+        }
 
         // So, when we see String and an Enum type, we add an additional synthetic tuple to the end
         // of the real list. This is the easiest way to accomplish this is a thread-safe and class-reloading
         // safe way (i.e., what if the Enum is defined by a class loader that gets discarded?  Don't want to cause
         // memory leaks by retaining an instance). In any case, there are edge cases where we may create
         // the tuple unnecessarily (such as when an explicit string-to-enum coercion is part of the TypeCoercer
-        // configuration), but on the whole, this is cheap at works.
-        
+        // configuration), but on the whole, this is cheap and works.
+
         if (sourceType == String.class && Enum.class.isAssignableFrom(targetType))
+        {
             tuples = extend(tuples, new CoercionTuple(sourceType, targetType, new StringToEnumCoercion(targetType)));
+        }
 
         return tuples;
     }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/bb940c08/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/AbstractResource.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/AbstractResource.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/AbstractResource.java
index f873eec..d382ba2 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/AbstractResource.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/AbstractResource.java
@@ -22,13 +22,12 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
 import java.util.Locale;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 /**
  * Abstract implementation of {@link Resource}. Subclasses must implement the abstract methods {@link Resource#toURL()}
  * and {@link #newResource(String)} as well as toString(), hashCode() and equals().
  */
-public abstract class AbstractResource implements Resource
+public abstract class AbstractResource extends LockSupport implements Resource
 {
     private class Localization
     {
@@ -48,11 +47,6 @@ public abstract class AbstractResource implements Resource
 
     private final String path;
 
-    /**
-     * A lock used to when lazily computing other values.
-     */
-    protected final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
-
     // Guarded by Lock
     private boolean exists, existsComputed;
 
@@ -129,7 +123,7 @@ public abstract class AbstractResource implements Resource
     {
         try
         {
-            lock.readLock().lock();
+            acquireReadLock();
 
             for (Localization l = firstLocalization; l != null; l = l.next)
             {
@@ -142,7 +136,7 @@ public abstract class AbstractResource implements Resource
             return populateLocalizationCache(locale);
         } finally
         {
-            lock.readLock().unlock();
+            releaseReadLock();
         }
     }
 
@@ -174,20 +168,6 @@ public abstract class AbstractResource implements Resource
         }
     }
 
-    protected final void upgradeReadLockToWriteLock()
-    {
-        lock.readLock().unlock();
-        // This is that instant where another thread may grab the write lock. Very rare, but possible.
-        lock.writeLock().lock();
-    }
-
-    protected final void downgradeWriteLockToReadLock()
-    {
-
-        lock.readLock().lock();
-        lock.writeLock().unlock();
-    }
-
     private Resource findLocalizedResource(Locale locale)
     {
         for (String path : new LocalizedNameGenerator(this.path, locale))
@@ -231,7 +211,7 @@ public abstract class AbstractResource implements Resource
     {
         try
         {
-            lock.readLock().lock();
+            acquireReadLock();
 
             if (!existsComputed)
             {
@@ -241,7 +221,7 @@ public abstract class AbstractResource implements Resource
             return exists;
         } finally
         {
-            lock.readLock().unlock();
+            releaseReadLock();
         }
     }
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/bb940c08/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/ClasspathResource.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/ClasspathResource.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/ClasspathResource.java
index a6d21ae..a7e613d 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/ClasspathResource.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/ClasspathResource.java
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007, 2008 The Apache Software Foundation
+// Copyright 2006, 2007, 2008, 2012 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -54,7 +54,7 @@ public final class ClasspathResource extends AbstractResource
     {
         try
         {
-            lock.readLock().lock();
+            acquireReadLock();
 
             if (!urlResolved)
             {
@@ -64,7 +64,7 @@ public final class ClasspathResource extends AbstractResource
             return url;
         } finally
         {
-            lock.readLock().unlock();
+            releaseReadLock();
         }
     }
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/bb940c08/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/LockSupport.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/LockSupport.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/LockSupport.java
new file mode 100644
index 0000000..5b1cc4f
--- /dev/null
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/LockSupport.java
@@ -0,0 +1,85 @@
+// Copyright 2012 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.ioc.internal.util;
+
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ * Base class for classes that need to manage a  ReadWriteLock.
+ */
+public abstract class LockSupport
+{
+    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
+
+    private final Lock readLock = lock.readLock();
+
+    private final Lock writeLock = lock.writeLock();
+
+    /**
+     * Locks the shared read lock. Any number of threads may lock the read lock at the same time.
+     */
+    protected final void acquireReadLock()
+    {
+        readLock.lock();
+    }
+
+    /**
+     * Takes the exclusive write lock. Once started, no other thread lock the read or write lock. When this method returns,
+     * this thread will have locked the write lock and no other thread will have either the read or write lock.
+     * Note that this thread must first drop the read lock (if it has it) before attempting to take the write lock, or this method will block forever.
+     */
+    protected final void takeWriteLock()
+    {
+        writeLock.lock();
+    }
+
+    /**
+     * Releases the shared read lock.
+     */
+    protected final void releaseReadLock()
+    {
+        readLock.unlock();
+    }
+
+    /**
+     * Releases the  exclusive read lock.
+     */
+    protected final void releaseWriteLock()
+    {
+        writeLock.unlock();
+    }
+
+    /**
+     * Releases the read lock, then takes the write lock. There's a short window where the thread will have neither lock:
+     * during that window, some other thread may have a chance to take the write lock. In code, you'll often see a second check
+     * inside the code that has the write lock to see if the update to perform is still necessary.
+     */
+    protected final void upgradeReadLockToWriteLock()
+    {
+        releaseReadLock();
+        // This is that instant where another thread may grab the write lock. Very rare, but possible.
+        takeWriteLock();
+    }
+
+    /**
+     * Takes the read lock then releases the write lock.
+     */
+    protected final void downgradeWriteLockToReadLock()
+    {
+        acquireReadLock();
+        releaseWriteLock();
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/bb940c08/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/OneShotLock.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/OneShotLock.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/OneShotLock.java
index 059f258..1b27341 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/OneShotLock.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/OneShotLock.java
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007, 2008, 2009 The Apache Software Foundation
+// Copyright 2006, 2007, 2008, 2009, 2012 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -18,18 +18,27 @@ package org.apache.tapestry5.ioc.internal.util;
  * Logic for handling one shot semantics for classes; classes that include a method (or methods) that "locks down" the
  * instance, to prevent it from being used again in the future.
  */
-public class OneShotLock
+public class OneShotLock extends LockSupport
 {
     private boolean lock;
 
     /**
      * Checks to see if the lock has been set (via {@link #lock()}).
      *
-     * @throws IllegalStateException if the lock is set
+     * @throws IllegalStateException
+     *         if the lock is set
      */
-    public synchronized void check()
+    public void check()
     {
-        innerCheck();
+        try
+        {
+            acquireReadLock();
+
+            innerCheck();
+        } finally
+        {
+            releaseReadLock();
+        }
     }
 
     private void innerCheck()
@@ -38,12 +47,13 @@ public class OneShotLock
         {
             // The depth to find the caller of the check() or lock() method varies between JDKs.
 
-
             StackTraceElement[] elements = Thread.currentThread().getStackTrace();
 
             int i = 0;
             while (!elements[i].getMethodName().equals("innerCheck"))
+            {
                 i++;
+            }
 
             throw new IllegalStateException(UtilMessages.oneShotLock(elements[i + 2]));
         }
@@ -52,10 +62,18 @@ public class OneShotLock
     /**
      * Checks the lock, then sets it.
      */
-    public synchronized void lock()
+    public void lock()
     {
-        innerCheck();
+        try
+        {
+            takeWriteLock();
+
+            innerCheck();
 
-        lock = true;
+            lock = true;
+        } finally
+        {
+            releaseWriteLock();
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/bb940c08/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/CoercionTuple.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/CoercionTuple.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/CoercionTuple.java
index bfc146d..8658686 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/CoercionTuple.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/CoercionTuple.java
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007, 2008, 2010, 2011 The Apache Software Foundation
+// Copyright 2006, 2007, 2008, 2010, 2011, 2012 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -14,6 +14,8 @@
 
 package org.apache.tapestry5.ioc.services;
 
+import org.apache.tapestry5.plastic.PlasticUtils;
+
 /**
  * An immutable object that represents a mapping from one type to another. This is also the contribution type when
  * building the {@link org.apache.tapestry5.ioc.services.TypeCoercer} service. Wraps a
@@ -21,11 +23,11 @@ package org.apache.tapestry5.ioc.services;
  * describe
  * the input and output types of the coercion, needed when searching for an appropriate coercion (or sequence of
  * coercions).
- * 
+ *
  * @param <S>
- *            source (input) type
+ *         source (input) type
  * @param <T>
- *            target (output) type
+ *         target (output) type
  */
 public final class CoercionTuple<S, T>
 {
@@ -61,10 +63,10 @@ public final class CoercionTuple<S, T>
 
     private String convert(Class type)
     {
-        if (void.class.equals(type))
+        if (Void.class.equals(type))
             return "null";
 
-        String name = ClassFabUtils.toJavaClassName(type);
+        String name = PlasticUtils.toTypeName(type);
 
         int dotx = name.lastIndexOf('.');
 
@@ -86,7 +88,7 @@ public final class CoercionTuple<S, T>
 
     /**
      * Convenience constructor to help with generics.
-     * 
+     *
      * @since 5.2.0
      */
     public static <S, T> CoercionTuple<S, T> create(Class<S> sourceType, Class<T> targetType, Coercion<S, T> coercion)
@@ -96,15 +98,15 @@ public final class CoercionTuple<S, T>
 
     /**
      * Internal-use constructor.
-     * 
+     *
      * @param sourceType
-     *            the source (or input) type of the coercion
+     *         the source (or input) type of the coercion, may be Void.class to indicate a coercion from null
      * @param targetType
-     *            the target (or output) type of the coercion
+     *         the target (or output) type of the coercion
      * @param coercion
-     *            the object that performs the coercion
+     *         the object that performs the coercion
      * @param wrap
-     *            if true, the coercion is wrapped to provide a useful toString()
+     *         if true, the coercion is wrapped to provide a useful toString()
      */
     @SuppressWarnings("unchecked")
     public CoercionTuple(Class<S> sourceType, Class<T> targetType, Coercion<S, T> coercion, boolean wrap)
@@ -113,8 +115,8 @@ public final class CoercionTuple<S, T>
         assert targetType != null;
         assert coercion != null;
 
-        this.sourceType = ClassFabUtils.getWrapperType(sourceType);
-        this.targetType = ClassFabUtils.getWrapperType(targetType);
+        this.sourceType = PlasticUtils.toWrapperType(sourceType);
+        this.targetType = PlasticUtils.toWrapperType(targetType);
         this.coercion = wrap ? new CoercionWrapper<S, T>(coercion) : coercion;
     }
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/bb940c08/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/TapestryIOCModule.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/TapestryIOCModule.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/TapestryIOCModule.java
index c809520..25e9231 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/TapestryIOCModule.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/TapestryIOCModule.java
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007, 2008, 2009, 2010, 2011 The Apache Software Foundation
+// Copyright 2006-2012 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -313,7 +313,7 @@ public final class TapestryIOCModule
             }
         });
 
-        add(configuration, void.class, Boolean.class, new Coercion<Void, Boolean>()
+        add(configuration, Void.class, Boolean.class, new Coercion<Void, Boolean>()
         {
             public Boolean coerce(Void input)
             {