You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2006/10/27 17:24:37 UTC

svn commit: r468412 - in /tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src: main/aspect/org/apache/tapestry/internal/aspects/ main/java/org/apache/tapestry/internal/ main/java/org/apache/tapestry/internal/annotations/ main/ja...

Author: hlship
Date: Fri Oct 27 08:24:36 2006
New Revision: 468412

URL: http://svn.apache.org/viewvc?view=rev&rev=468412
Log:
Remove support for the @Concurrence annotation, replace with explicit use of the ConcurrentBarrier utility (or use concurrent collections internally).

Added:
    tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/util/ConcurrentBarrier.java
    tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/util/Holder.java
    tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/util/Invokable.java
    tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/test/java/org/apache/tapestry/internal/util/ConcurrentBarrierTest.java
    tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/test/java/org/apache/tapestry/internal/util/ConcurrentTarget.java
      - copied, changed from r468391, tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/test/java/org/apache/tapestry/internal/aspects/ConcurrentTarget.java
    tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/test/java/org/apache/tapestry/internal/util/ConcurrentTargetWrapper.java
      - copied, changed from r468391, tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/test/java/org/apache/tapestry/internal/aspects/ConcurrentTargetWrapper.java
Removed:
    tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/aspect/org/apache/tapestry/internal/aspects/Concurrence.aj
    tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/aspect/org/apache/tapestry/internal/aspects/InternalConcurrence.aj
    tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/annotations/Concurrent.java
    tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/test/java/org/apache/tapestry/internal/aspects/ConcurrenceAspectTest.java
    tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/test/java/org/apache/tapestry/internal/aspects/ConcurrentTarget.java
    tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/test/java/org/apache/tapestry/internal/aspects/ConcurrentTargetWrapper.java
Modified:
    tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/MessagesImpl.java
    tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/ioc/services/PropertyAccessImpl.java
    tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/services/CheckForUpdatesFilter.java
    tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/services/ComponentClassTransformerImpl.java
    tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/services/ComponentTemplateSourceImpl.java
    tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/services/InfrastructureImpl.java
    tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/test/java/org/apache/tapestry/services/SyncCostBench.java

Modified: tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/MessagesImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/MessagesImpl.java?view=diff&rev=468412&r1=468411&r2=468412
==============================================================================
--- tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/MessagesImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/MessagesImpl.java Fri Oct 27 08:24:36 2006
@@ -14,8 +14,8 @@
 
 package org.apache.tapestry.internal;
 
-import static org.apache.tapestry.util.CollectionFactory.newMap;
 import static org.apache.tapestry.util.CollectionFactory.newSet;
+import static org.apache.tapestry.util.CollectionFactory.newThreadSafeMap;
 
 import java.util.Enumeration;
 import java.util.Locale;
@@ -25,15 +25,11 @@
 
 import org.apache.tapestry.MessageFormatter;
 import org.apache.tapestry.Messages;
-import org.apache.tapestry.internal.annotations.Concurrent;
 
 /**
  * Implementation of {@link org.apache.tapestry.Messages} based around a
  * {@link java.util.ResourceBundle}.
- * 
- * 
  */
-@Concurrent
 public class MessagesImpl implements Messages
 {
     private final ResourceBundle _bundle;
@@ -41,7 +37,7 @@
     private final Set<String> _keys = newSet();
 
     /** String key to MF instance. */
-    private Map<String, MessageFormatter> _cache = newMap();
+    private Map<String, MessageFormatter> _cache = newThreadSafeMap();
 
     /**
      * Finds the messages for a given Messages utility class. Strings the trailing "Messages" and
@@ -87,26 +83,24 @@
         return "[" + key.toUpperCase() + "]";
     }
 
-    @Concurrent.Read
     public MessageFormatter getFormatter(String key)
     {
         MessageFormatter result = _cache.get(key);
 
         if (result == null)
-            result = fillInCache(key);
+        {
+            result = buildMessageFormatter(key);
+            _cache.put(key, result);
+        }
 
         return result;
     }
 
-    @Concurrent.Write
-    private MessageFormatter fillInCache(String key)
+    private MessageFormatter buildMessageFormatter(String key)
     {
         String format = get(key);
-        MessageFormatter result = new MessageFormatterImpl(format);
 
-        _cache.put(key, result);
-
-        return result;
+        return new MessageFormatterImpl(format);
     }
 
     public String format(String key, Object... args)

Modified: tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/ioc/services/PropertyAccessImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/ioc/services/PropertyAccessImpl.java?view=diff&rev=468412&r1=468411&r2=468412
==============================================================================
--- tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/ioc/services/PropertyAccessImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/ioc/services/PropertyAccessImpl.java Fri Oct 27 08:24:36 2006
@@ -14,24 +14,19 @@
 
 package org.apache.tapestry.internal.ioc.services;
 
-import static org.apache.tapestry.util.CollectionFactory.newMap;
+import static org.apache.tapestry.util.CollectionFactory.newThreadSafeMap;
 
 import java.beans.BeanInfo;
 import java.beans.Introspector;
 import java.util.Map;
 
-import org.apache.tapestry.internal.annotations.Concurrent;
 import org.apache.tapestry.internal.annotations.SuppressNullCheck;
 import org.apache.tapestry.ioc.services.ClassPropertyAdapter;
 import org.apache.tapestry.ioc.services.PropertyAccess;
 
-/**
- * 
- */
-@Concurrent
 public class PropertyAccessImpl implements PropertyAccess
 {
-    private final Map<Class, ClassPropertyAdapter> _adapters = newMap();
+    private final Map<Class, ClassPropertyAdapter> _adapters = newThreadSafeMap();
 
     @SuppressNullCheck
     public Object get(Object instance, String propertyName)
@@ -45,10 +40,12 @@
         getAdapter(instance).set(instance, propertyName, value);
     }
 
-    @Concurrent.Write
-    public void clearCache()
+    /** Clears the cache of adapters and asks the Introspector to clear its cache. */
+    public synchronized void clearCache()
     {
         _adapters.clear();
+
+        Introspector.flushCaches();
     }
 
     public ClassPropertyAdapter getAdapter(Object instance)
@@ -56,13 +53,15 @@
         return getAdapter(instance.getClass());
     }
 
-    @Concurrent.Read
     public ClassPropertyAdapter getAdapter(Class forClass)
     {
         ClassPropertyAdapter result = _adapters.get(forClass);
 
         if (result == null)
+        {
             result = buildAdapter(forClass);
+            _adapters.put(forClass, result);
+        }
 
         return result;
     }
@@ -72,8 +71,7 @@
      * adapter cache, but also serializes access to the Java Beans Introspector, which is not thread
      * safe.
      */
-    @Concurrent.Write
-    private ClassPropertyAdapter buildAdapter(Class forClass)
+    private synchronized ClassPropertyAdapter buildAdapter(Class forClass)
     {
         // In some race conditions, we may hit this method for the same class multiple times.
         // We just let it happen, replacing the old ClassPropertyAdapter with a new one.
@@ -82,12 +80,7 @@
         {
             BeanInfo info = Introspector.getBeanInfo(forClass);
 
-            ClassPropertyAdapter adapter = new ClassPropertyAdapterImpl(forClass, info
-                    .getPropertyDescriptors());
-
-            _adapters.put(forClass, adapter);
-
-            return adapter;
+            return new ClassPropertyAdapterImpl(forClass, info.getPropertyDescriptors());
         }
         catch (Exception ex)
         {

Modified: tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/services/CheckForUpdatesFilter.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/services/CheckForUpdatesFilter.java?view=diff&rev=468412&r1=468411&r2=468412
==============================================================================
--- tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/services/CheckForUpdatesFilter.java (original)
+++ tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/services/CheckForUpdatesFilter.java Fri Oct 27 08:24:36 2006
@@ -16,7 +16,9 @@
 
 import java.io.IOException;
 
-import org.apache.tapestry.internal.annotations.Concurrent;
+import org.apache.tapestry.internal.util.ConcurrentBarrier;
+import org.apache.tapestry.internal.util.Holder;
+import org.apache.tapestry.internal.util.Invokable;
 import org.apache.tapestry.services.WebRequest;
 import org.apache.tapestry.services.WebRequestFilter;
 import org.apache.tapestry.services.WebRequestHandler;
@@ -27,10 +29,9 @@
  * {@link org.apache.tapestry.internal.services.UpdateListenerHub} to check for updates to files.
  * The UpdateListenerHub is invoked from a write method, meaning that when it is called, all other
  * threads will be blocked.
- * 
- * 
+ * <p>
+ * TODO: Allow the check interval to be configurable, to reflect a production environment
  */
-@Concurrent
 public class CheckForUpdatesFilter implements WebRequestFilter
 {
     private long _lastCheck = 0;
@@ -39,37 +40,70 @@
 
     private final UpdateListenerHub _updateListenerHub;
 
+    private final ConcurrentBarrier _barrier = new ConcurrentBarrier();
+
     public CheckForUpdatesFilter(UpdateListenerHub updateListenerHub)
     {
         _updateListenerHub = updateListenerHub;
     }
 
-    @Concurrent.Read
-    public boolean service(WebRequest request, WebResponse response, WebRequestHandler handler)
-            throws IOException
+    public boolean service(final WebRequest request, final WebResponse response,
+            final WebRequestHandler handler) throws IOException
     {
-        if (System.currentTimeMillis() - _lastCheck >= _checkInterval)
-            runCheck();
+        final Holder<IOException> exceptionHolder = new Holder<IOException>();
 
-        return handler.service(request, response);
-    }
+        Invokable<Boolean> invokable = new Invokable<Boolean>()
+        {
+            public Boolean invoke()
+            {
+                if (System.currentTimeMillis() - _lastCheck >= _checkInterval)
+                    runCheck();
+
+                try
+                {
+                    return handler.service(request, response);
+                }
+                catch (IOException ex)
+                {
+                    exceptionHolder.put(ex);
+                    return false;
+                }
+            }
+        };
 
-    /** The write lock ensures that only a single thread is active, all others are blocked. */
-    @Concurrent.Write
-    private void runCheck()
-    {
-        // On a race condition, multiple threads may hit this method briefly. If we've already
-        // done a check, don't run it again.
+        boolean result = _barrier.withRead(invokable);
 
-        if (System.currentTimeMillis() - _lastCheck < _checkInterval)
-            return;
+        IOException ex = exceptionHolder.get();
 
-        // Fire the update event which will force a number of checks and then corresponding
-        // invalidation events.
+        if (ex != null)
+            throw ex;
 
-        _updateListenerHub.fireUpdateEvent();
+        return result;
+    }
+
+    private void runCheck()
+    {
+        Runnable runnable = new Runnable()
+        {
+            public void run()
+            {
+                // On a race condition, multiple threads may hit this method briefly. If we've
+                // already done a check, don't run it again.
+
+                if (System.currentTimeMillis() - _lastCheck >= _checkInterval)
+                {
+
+                    // Fire the update event which will force a number of checks and then
+                    // corresponding invalidation events.
+
+                    _updateListenerHub.fireUpdateEvent();
+
+                    _lastCheck = System.currentTimeMillis();
+                }
+            }
+        };
 
-        _lastCheck = System.currentTimeMillis();
+        _barrier.withWrite(runnable);
     }
 
 }

Modified: tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/services/ComponentClassTransformerImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/services/ComponentClassTransformerImpl.java?view=diff&rev=468412&r1=468411&r2=468412
==============================================================================
--- tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/services/ComponentClassTransformerImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/services/ComponentClassTransformerImpl.java Fri Oct 27 08:24:36 2006
@@ -14,7 +14,7 @@
 
 package org.apache.tapestry.internal.services;
 
-import static org.apache.tapestry.util.CollectionFactory.newMap;
+import static org.apache.tapestry.util.CollectionFactory.newThreadSafeMap;
 
 import java.util.Map;
 
@@ -26,7 +26,6 @@
 import org.apache.tapestry.annotations.ComponentClass;
 import org.apache.tapestry.events.InvalidationListener;
 import org.apache.tapestry.internal.ClasspathResource;
-import org.apache.tapestry.internal.annotations.Concurrent;
 import org.apache.tapestry.internal.model.MutableComponentModelImpl;
 import org.apache.tapestry.ioc.LogSource;
 import org.apache.tapestry.model.ComponentModel;
@@ -36,14 +35,13 @@
 /**
  * Implementation of {@link org.apache.tapestry.internal.services.ComponentClassTransformer}.
  */
-@Concurrent
 public class ComponentClassTransformerImpl implements ComponentClassTransformer,
         InvalidationListener
 {
     /** Map from class name to class transformation. */
-    private final Map<String, InternalClassTransformation> _nameToClassTransformation = newMap();
+    private final Map<String, InternalClassTransformation> _nameToClassTransformation = newThreadSafeMap();
 
-    private final Map<String, ComponentModel> _nameToComponentModel = newMap();
+    private final Map<String, ComponentModel> _nameToComponentModel = newThreadSafeMap();
 
     private final ComponentClassTransformWorker _workerChain;
 
@@ -64,14 +62,12 @@
      * Clears the cache of {@link InternalClassTransformation} instances whenever the class loader
      * is invalidated.
      */
-    @Concurrent.Write
     public void objectWasInvalidated()
     {
         _nameToClassTransformation.clear();
         _nameToComponentModel.clear();
     }
 
-    @Concurrent.Write
     public void transformComponentClass(CtClass ctClass, ClassLoader classLoader)
     {
         String classname = ctClass.getName();
@@ -129,7 +125,6 @@
         _nameToComponentModel.put(classname, model);
     }
 
-    @Concurrent.Read
     public Instantiator createInstantiator(Class componentClass)
     {
         String className = componentClass.getName();

Modified: tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/services/ComponentTemplateSourceImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/services/ComponentTemplateSourceImpl.java?view=diff&rev=468412&r1=468411&r2=468412
==============================================================================
--- tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/services/ComponentTemplateSourceImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/services/ComponentTemplateSourceImpl.java Fri Oct 27 08:24:36 2006
@@ -14,7 +14,7 @@
 
 package org.apache.tapestry.internal.services;
 
-import static org.apache.tapestry.util.CollectionFactory.newMap;
+import static org.apache.tapestry.util.CollectionFactory.newThreadSafeMap;
 
 import java.util.Locale;
 import java.util.Map;
@@ -22,17 +22,13 @@
 import org.apache.tapestry.Resource;
 import org.apache.tapestry.events.UpdateListener;
 import org.apache.tapestry.internal.ClasspathResource;
-import org.apache.tapestry.internal.annotations.Concurrent;
 import org.apache.tapestry.internal.event.InvalidationEventHubImpl;
 import org.apache.tapestry.internal.parser.ComponentTemplate;
 import org.apache.tapestry.internal.util.URLChangeTracker;
 
 /**
  * Service implementation that manages a cache of parsed component templates.
- * 
- * 
  */
-@Concurrent
 public final class ComponentTemplateSourceImpl extends InvalidationEventHubImpl implements
         ComponentTemplateSource, UpdateListener
 {
@@ -46,12 +42,12 @@
      * parsed from the same "foo.html" resource). The resource may end up being null, meaning the
      * template does not exist in any locale.
      */
-    private final Map<String, Resource> _templateResources = newMap();
+    private final Map<String, Resource> _templateResources = newThreadSafeMap();
 
     /**
      * Cache of parsed templates, keyed on resource.
      */
-    private final Map<Resource, ComponentTemplate> _templates = newMap();
+    private final Map<Resource, ComponentTemplate> _templates = newThreadSafeMap();
 
     private final URLChangeTracker _tracker = new URLChangeTracker();
 
@@ -71,7 +67,6 @@
      * (the combination of component name and locale is resolved to a resource). The localized
      * resource is used as the key to a cache of {@link ComponentTemplate}s.
      */
-    @Concurrent.Read
     public ComponentTemplate getTemplate(String componentName, Locale locale)
     {
         String key = componentName + ":" + locale.toString();
@@ -95,7 +90,6 @@
         return _templates.get(resource);
     }
 
-    @Concurrent.Write
     private void parseTemplate(Resource r)
     {
         // In a race condition, we may parse the same template more than once. This will likely add
@@ -108,7 +102,6 @@
         _templates.put(r, template);
     }
 
-    @Concurrent.Write
     private void locateTemplateResource(String componentName, Locale locale, String key)
     {
         // TODO: Currently hard-coded to a ".html" extension! Need to locate the
@@ -121,7 +114,8 @@
         // In a race condition, we may hit this method a couple of times, and overrite previous
         // results with identical new results.
 
-        _templateResources.put(key, localized);
+        if (localized != null)
+            _templateResources.put(key, localized);
     }
 
     /**
@@ -129,7 +123,6 @@
      * cleared, and an invalidation event is fired. This is brute force ... a more targetted
      * dependency management strategy may come later.
      */
-    @Concurrent.Write
     public void checkForUpdates()
     {
         if (_tracker.containsChanges())

Modified: tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/services/InfrastructureImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/services/InfrastructureImpl.java?view=diff&rev=468412&r1=468411&r2=468412
==============================================================================
--- tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/services/InfrastructureImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/services/InfrastructureImpl.java Fri Oct 27 08:24:36 2006
@@ -16,18 +16,15 @@
 
 import java.util.Map;
 
-import org.apache.tapestry.internal.annotations.Concurrent;
 import org.apache.tapestry.ioc.ObjectProvider;
 import org.apache.tapestry.ioc.ServiceLocator;
 import org.apache.tapestry.services.Infrastructure;
 import org.apache.tapestry.services.InfrastructureManager;
+import org.apache.tapestry.util.Defense;
 
 /**
  * TODO: Extra configuration to support application overrides.
- * 
- * 
  */
-@Concurrent
 public class InfrastructureImpl implements Infrastructure, ObjectProvider
 {
     private InfrastructureManager _manager;
@@ -51,25 +48,15 @@
     // Probably don't need to make this concurrent, since it executes at startup,
     // before multithreading takes hold.
 
-    @Concurrent.Write
-    public void setMode(String mode)
+    public synchronized void setMode(String mode)
     {
-        _mode = mode;
+        _mode = Defense.notNull(mode, "mode");
+
+        deriveProperties();
     }
 
-    @Concurrent.Write
     private void deriveProperties()
     {
-        // In a race condition between two or more threads, the first one will create
-        // the properties, the later ones will gain access later and see that
-        // the properties already exist.
-
-        if (_properties != null)
-            return;
-
-        if (_mode == null)
-            throw new RuntimeException(ServicesMessages.infrastructureModeNotSet());
-
         _properties = _manager.getContributionsForMode(_mode);
 
         // Don't need this again.
@@ -77,13 +64,10 @@
         _manager = null;
     }
 
-    @Concurrent.Read
     public <T> T provide(String expression, Class<T> objectType, ServiceLocator locator)
     {
-        // Lazily create the _properties
-
         if (_properties == null)
-            deriveProperties();
+            throw new RuntimeException(ServicesMessages.infrastructureModeNotSet());
 
         Object object = _properties.get(expression);
 

Added: tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/util/ConcurrentBarrier.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/util/ConcurrentBarrier.java?view=auto&rev=468412
==============================================================================
--- tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/util/ConcurrentBarrier.java (added)
+++ tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/util/ConcurrentBarrier.java Fri Oct 27 08:24:36 2006
@@ -0,0 +1,141 @@
+package org.apache.tapestry.internal.util;
+
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ * A barrier used to execute code in a context where it is guarded by read/write locks.
+ */
+public class ConcurrentBarrier
+{
+    private final ReadWriteLock _lock = new ReentrantReadWriteLock();
+
+    /**
+     * This is, of course, a bit of a problem. We don't have an avenue for ensuring that this
+     * ThreadLocal is destroyed at the end of the request, and that means a thread can hold a
+     * reference to the class and the class loader which loaded it. This may cause redeployment
+     * problems (leaked classes and class loaders). Apparently JDK 1.6 provides the APIs to check to
+     * see if the current thread has a read lock. So, we tend to remove the TL, rather than set its
+     * value to false.
+     */
+    public static class ThreadBoolean extends ThreadLocal<Boolean>
+    {
+        @Override
+        protected Boolean initialValue()
+        {
+            return false;
+        }
+    }
+
+    private final ThreadBoolean _threadHasReadLock = new ThreadBoolean();
+
+    /**
+     * Invokes the object after acquiring the read lock (if necessary). If invoked when the read
+     * lock has not yet been acquired, then the lock is acquired for the duration of the call. If
+     * the lock has already been acquired, then the status of the lock is not changed.
+     * <p>
+     * TODO: Check to see if the write lock is acquired and <em>not</em> acquire the read lock in
+     * that situation.
+     * 
+     * @param <T>
+     * @param invokable
+     * @return the result of invoking the invokable
+     */
+    public <T> T withRead(Invokable<T> invokable)
+    {
+        boolean readLockedAtEntry = _threadHasReadLock.get();
+
+        if (!readLockedAtEntry)
+        {
+            _lock.readLock().lock();
+
+            _threadHasReadLock.set(true);
+        }
+
+        try
+        {
+            return invokable.invoke();
+        }
+        finally
+        {
+            if (!readLockedAtEntry)
+            {
+                _lock.readLock().unlock();
+
+                _threadHasReadLock.remove();
+            }
+        }
+    }
+
+    public void withRead(final Runnable runnable)
+    {
+        Invokable<Void> invokable = new Invokable<Void>()
+        {
+            public Void invoke()
+            {
+                runnable.run();
+
+                return null;
+            }
+        };
+
+        withRead(invokable);
+    }
+
+    /**
+     * Acquires the single write lock before invoking the Invokable. If the current thread has a
+     * read lock, it is released before attempting to acquire the write lock, and re-acquired after
+     * the write lock is released.
+     * 
+     * @param <T>
+     * @param invokable
+     */
+    public <T> T withWrite(Invokable<T> invokable)
+    {
+        boolean readLockedAtEntry = _threadHasReadLock.get();
+
+        if (readLockedAtEntry)
+        {
+            _lock.readLock().unlock();
+
+            _threadHasReadLock.set(false);
+        }
+
+        _lock.writeLock().lock();
+
+        try
+        {
+            return invokable.invoke();
+        }
+        finally
+        {
+            _lock.writeLock().unlock();
+
+            if (readLockedAtEntry)
+            {
+                _lock.readLock().lock();
+
+                _threadHasReadLock.set(true);
+            }
+            else
+            {
+                _threadHasReadLock.remove();
+            }
+        }
+    }
+
+    public void withWrite(final Runnable runnable)
+    {
+        Invokable<Void> invokable = new Invokable<Void>()
+        {
+            public Void invoke()
+            {
+                runnable.run();
+
+                return null;
+            }
+        };
+
+        withWrite(invokable);
+    }
+}

Added: tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/util/Holder.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/util/Holder.java?view=auto&rev=468412
==============================================================================
--- tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/util/Holder.java (added)
+++ tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/util/Holder.java Fri Oct 27 08:24:36 2006
@@ -0,0 +1,22 @@
+package org.apache.tapestry.internal.util;
+
+/**
+ * An object that holds some type of other object. This is useful for communicating information from
+ * an inner class to the containing method.
+ * 
+ * @param <T>
+ */
+public class Holder<T>
+{
+    private T _held;
+
+    public void put(T object)
+    {
+        _held = object;
+    }
+
+    public T get()
+    {
+        return _held;
+    }
+}

Added: tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/util/Invokable.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/util/Invokable.java?view=auto&rev=468412
==============================================================================
--- tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/util/Invokable.java (added)
+++ tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/main/java/org/apache/tapestry/internal/util/Invokable.java Fri Oct 27 08:24:36 2006
@@ -0,0 +1,14 @@
+package org.apache.tapestry.internal.util;
+
+/**
+ * Similiar to {@link Runnable} execpt that it returns a value. Used by {@link ConcurrentBarrier} to
+ * identify the block of code to execute with read/write lock protection.
+ * 
+ * @param <T>
+ *            the return value type
+ */
+public interface Invokable<T>
+{
+    /** Called to produce a value. */
+    T invoke();
+}

Added: tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/test/java/org/apache/tapestry/internal/util/ConcurrentBarrierTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/test/java/org/apache/tapestry/internal/util/ConcurrentBarrierTest.java?view=auto&rev=468412
==============================================================================
--- tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/test/java/org/apache/tapestry/internal/util/ConcurrentBarrierTest.java (added)
+++ tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/test/java/org/apache/tapestry/internal/util/ConcurrentBarrierTest.java Fri Oct 27 08:24:36 2006
@@ -0,0 +1,152 @@
+// Copyright 2006 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.tapestry.internal.util;
+
+import static org.apache.tapestry.util.CollectionFactory.newList;
+
+import java.util.List;
+
+import org.apache.tapestry.test.TestBase;
+import org.testng.annotations.Test;
+
+/**
+ * Test is structured a bit oddly, since it evolved from when the Concurrence annotation and aspect
+ * evolved into the {@link ConcurrentBarrier} utility class.
+ */
+@Test(sequential = true)
+public class ConcurrentBarrierTest extends TestBase
+{
+    private ConcurrentTarget _target = new ConcurrentTarget();
+
+    private static final int THREAD_COUNT = 100;
+
+    private static final int THREAD_BLOCK_SIZE = 5;
+
+    @Test
+    public void read_lock_then_write_lock() throws Exception
+    {
+        Runnable operation = new Runnable()
+        {
+            public void run()
+            {
+                _target.incrementCounter();
+            }
+        };
+
+        runOperation(operation);
+    }
+
+    @Test
+    public void read_lock_inside_write_lock() throws Exception
+    {
+        Runnable operation = new Runnable()
+        {
+            public void run()
+            {
+                // Gets a write lock, then a read lock.
+                _target.incrementCounterHard();
+            }
+        };
+
+        runOperation(operation);
+    }
+
+    @Test(enabled = true)
+    public void write_lock_inside_read_lock() throws Exception
+    {
+        Runnable operation = new Runnable()
+        {
+            public void run()
+            {
+                // A read lock method that upgrades to a write lock
+
+                _target.incrementIfNonNegative();
+            }
+        };
+
+        runOperation(operation);
+    }
+
+    @Test(enabled = true)
+    public void indirection_between_read_method_and_write_method() throws Exception
+    {
+        Runnable operation = new Runnable()
+        {
+            public void run()
+            {
+
+                // Read lock method invokes other class, that invokes write method.
+
+                _target.incrementViaRunnable();
+            }
+        };
+
+        runOperation(operation);
+    }
+
+    /**
+     * Test that locking, especially read lock upgrade and downgrade, work properly when there's
+     * more than one object involved.
+     */
+    @Test
+    public void multiple_synchronized_objects() throws Exception
+    {
+        Runnable operation = new ConcurrentTargetWrapper(_target);
+
+        runOperation(operation);
+    }
+
+    private void runOperation(Runnable operation) throws InterruptedException
+    {
+        // System.out.println("** Start synchronization");
+
+        List<Thread> threads = newList();
+        List<Thread> running = newList();
+
+        _target.setCounter(0);
+
+        for (int i = 0; i < THREAD_COUNT; i++)
+        {
+
+            Thread t = new Thread(operation);
+
+            threads.add(t);
+
+            if (threads.size() >= THREAD_BLOCK_SIZE)
+                startThreads(threads, running);
+        }
+
+        startThreads(threads, running);
+
+        for (Thread t : running)
+            t.join();
+
+        assertEquals(_target.getCounter(), THREAD_COUNT);
+
+        // System.out.println("** End synchronization");
+    }
+
+    private void startThreads(List<Thread> threads, List<Thread> running)
+    {
+        for (Thread t : threads)
+        {
+            t.start();
+            running.add(t);
+        }
+
+        threads.clear();
+    }
+
+}

Copied: tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/test/java/org/apache/tapestry/internal/util/ConcurrentTarget.java (from r468391, tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/test/java/org/apache/tapestry/internal/aspects/ConcurrentTarget.java)
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/test/java/org/apache/tapestry/internal/util/ConcurrentTarget.java?view=diff&rev=468412&p1=tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/test/java/org/apache/tapestry/internal/aspects/ConcurrentTarget.java&r1=468391&p2=tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/test/java/org/apache/tapestry/internal/util/ConcurrentTarget.java&r2=468412
==============================================================================
--- tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/test/java/org/apache/tapestry/internal/aspects/ConcurrentTarget.java (original)
+++ tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/test/java/org/apache/tapestry/internal/util/ConcurrentTarget.java Fri Oct 27 08:24:36 2006
@@ -12,69 +12,101 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package org.apache.tapestry.internal.aspects;
+package org.apache.tapestry.internal.util;
 
-import org.apache.tapestry.internal.annotations.Concurrent;
+import org.apache.tapestry.internal.util.ConcurrentBarrier;
+import org.apache.tapestry.internal.util.Invokable;
 
-/**
- * Class used to test the {@link Synchronization} aspect.
- * 
- * 
- */
-@Concurrent
 public class ConcurrentTarget
 {
+    private final ConcurrentBarrier _barrier = new ConcurrentBarrier();
+
     private int _counter;
 
-    // Used to check if read locks accumulate when @Read calls @Read
-    @Concurrent.Read
+    // Used to check if read locks accumulate when a read lock method calls another read lock method
     public int readCounter()
     {
-        return getCounter();
+        return _barrier.withRead(new Invokable<Integer>()
+        {
+            public Integer invoke()
+            {
+                return getCounter();
+            }
+        });
     }
 
-    @Concurrent.Read
     public int getCounter()
     {
-        return _counter;
+        return _barrier.withRead(new Invokable<Integer>()
+        {
+            public Integer invoke()
+            {
+                return _counter;
+            }
+        });
     }
 
-    @Concurrent.Write
     public void incrementCounter()
     {
-        _counter++;
+        _barrier.withWrite(new Runnable()
+        {
+            public void run()
+            {
+                _counter++;
+            }
+        });
     }
 
-    @Concurrent.Write
-    public void setCounter(int counter)
+    public void setCounter(final int counter)
     {
-        _counter = counter;
+        _barrier.withWrite(new Runnable()
+        {
+            public void run()
+            {
+                _counter = counter;
+            }
+        });
     }
 
-    @Concurrent.Read
     public void incrementIfNonNegative()
     {
-        if (_counter >= 0)
-            incrementCounter();
+        _barrier.withRead(new Runnable()
+        {
+            public void run()
+            {
+                if (_counter >= 0)
+                    incrementCounter();
+            }
+        });
     }
 
-    @Concurrent.Read
     public void incrementViaRunnable()
     {
-        Runnable r = new Runnable()
+        _barrier.withRead(new Runnable()
         {
             public void run()
             {
-                incrementCounter();
-            }
-        };
+                Runnable r = new Runnable()
+                {
+                    public void run()
+                    {
+                        incrementCounter();
+                    }
+                };
 
-        r.run();
+                r.run();
+            }
+        });
     }
 
-    @Concurrent.Write
     public void incrementCounterHard()
     {
-        _counter = getCounter() + 1;
+        _barrier.withWrite(new Runnable()
+        {
+            public void run()
+            {
+                _counter = getCounter() + 1;
+            }
+        });
     }
 }

Copied: tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/test/java/org/apache/tapestry/internal/util/ConcurrentTargetWrapper.java (from r468391, tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/test/java/org/apache/tapestry/internal/aspects/ConcurrentTargetWrapper.java)
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/test/java/org/apache/tapestry/internal/util/ConcurrentTargetWrapper.java?view=diff&rev=468412&p1=tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/test/java/org/apache/tapestry/internal/aspects/ConcurrentTargetWrapper.java&r1=468391&p2=tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/test/java/org/apache/tapestry/internal/util/ConcurrentTargetWrapper.java&r2=468412
==============================================================================
--- tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/test/java/org/apache/tapestry/internal/aspects/ConcurrentTargetWrapper.java (original)
+++ tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/test/java/org/apache/tapestry/internal/util/ConcurrentTargetWrapper.java Fri Oct 27 08:24:36 2006
@@ -12,18 +12,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package org.apache.tapestry.internal.aspects;
+package org.apache.tapestry.internal.util;
 
-import org.apache.tapestry.internal.annotations.Concurrent;
+import org.apache.tapestry.internal.util.ConcurrentBarrier;
 
-/**
- * Class used to test the {@link Synchronization} aspect.
- * 
- * 
- */
-@Concurrent
 public class ConcurrentTargetWrapper implements Runnable
 {
+    private final ConcurrentBarrier _barrier = new ConcurrentBarrier();
+
     private final ConcurrentTarget _target;
 
     public ConcurrentTargetWrapper(ConcurrentTarget target)
@@ -31,9 +27,14 @@
         _target = target;
     }
 
-    @Concurrent.Read
     public void run()
     {
-        _target.incrementCounter();
+        _barrier.withRead(new Runnable()
+        {
+            public void run()
+            {
+                _target.incrementCounter();
+            }
+        });
     }
 }

Modified: tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/test/java/org/apache/tapestry/services/SyncCostBench.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/test/java/org/apache/tapestry/services/SyncCostBench.java?view=diff&rev=468412&r1=468411&r2=468412
==============================================================================
--- tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/test/java/org/apache/tapestry/services/SyncCostBench.java (original)
+++ tapestry/tapestry5/tapestry-core/branches/hlship-20061027-removeaspectj/src/test/java/org/apache/tapestry/services/SyncCostBench.java Fri Oct 27 08:24:36 2006
@@ -20,7 +20,7 @@
 import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
-import org.apache.tapestry.internal.annotations.Concurrent;
+import org.apache.tapestry.internal.util.ConcurrentBarrier;
 
 /**
  * Tests single-thread synchronization overhead using different techniques. Note that we're fudging
@@ -35,6 +35,8 @@
  * ... for example, ReadWriteLockRunner is consistently slower than ReadWriteLockAspectRunner (one
  * would expect it to be the other way around ... must be something about how AspectJ weaves the
  * code ... and it's use of static methods in many cases).
+ * <p>
+ * Well, the Concurrent aspect is gone, replaced with the {@link ConcurrentBarrier} utility.
  */
 public class SyncCostBench
 {
@@ -85,9 +87,10 @@
         }
     }
 
-    @Concurrent
     static class ReadWriteLockAspectRunner implements Runnable
     {
+        private final ConcurrentBarrier _barrier = new ConcurrentBarrier();
+
         private final Runnable _delegate;
 
         public ReadWriteLockAspectRunner(Runnable delegate)
@@ -95,10 +98,9 @@
             _delegate = delegate;
         }
 
-        @Concurrent.Read
         public void run()
         {
-            _delegate.run();
+            _barrier.withRead(_delegate);
         }
     }