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);
}
}