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 2006/04/26 07:42:37 UTC
svn commit: r397093 - in /tapestry/tapestry5/tapestry-core/trunk/src:
main/aspect/org/apache/tapestry/internal/aspects/
main/java/org/apache/tapestry/internal/transform/
main/java/org/apache/tapestry/util/
test/java/org/apache/tapestry/internal/aspects...
Author: hlship
Date: Tue Apr 25 22:42:35 2006
New Revision: 397093
URL: http://svn.apache.org/viewcvs?rev=397093&view=rev
Log:
Complete the Synchronization aspect
Begin work on supporting class hierarchies during component class transformation
Added:
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/ConstructorArg.java
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/aspects/SynchTargetWrapper.java
Modified:
tapestry/tapestry5/tapestry-core/trunk/src/main/aspect/org/apache/tapestry/internal/aspects/Synchronization.aj
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/InternalClassTransformation.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/InternalClassTransformationImpl.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/util/CollectionFactory.java
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/aspects/SynchronizationAspectTest.java
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/aspects/SynchronizationTarget.java
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/util/CollectionFactoryTest.java
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/aspect/org/apache/tapestry/internal/aspects/Synchronization.aj
URL: http://svn.apache.org/viewcvs/tapestry/tapestry5/tapestry-core/trunk/src/main/aspect/org/apache/tapestry/internal/aspects/Synchronization.aj?rev=397093&r1=397092&r2=397093&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/aspect/org/apache/tapestry/internal/aspects/Synchronization.aj (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/aspect/org/apache/tapestry/internal/aspects/Synchronization.aj Tue Apr 25 22:42:35 2006
@@ -4,6 +4,7 @@
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.apache.tapestry.internal.annotations.Synchronized;
+import org.aspectj.lang.JoinPoint;
/**
* Manages multi-threaded access to methods of an object instance using a
@@ -11,14 +12,16 @@
* {@link Synchronized.Read} and {@link Synchronized.Write} annotations. Methods that have the
* Synchronized.Read annotation witll be advised to obtain and release the read lock around their
* execution. Methods with the Synchronized.Write annotation will obtain and release the write lock
- * around their execution. Methods with Synchronized.Read that call a Synchronized.Write-ed method
- * (within the same instance) will release the read lock before invoking the Synchronized.Write-ed
+ * around their execution. Methods annotated with Synchronized.Read that call a method annotated
+ * with Synchronized.Write (within the same instance) will release the read lock before invoking the
* method.
* <p>
+ * This implementation makes use of a ThreadLocal to determine if the current thread has acquired
+ * the read lock (or not). This prevents the read lock from being re-locked, and allows the aspect
+ * to release the read lock temporarily when acquiring the write lock.
+ * <p>
* This aspect also enforces that the annotations are only applied to instance (not static) methods,
* and that a method may be either read or write, but not both.
- * <p>
- * TODO: read-into-write not yet implemented!
*
* @author Howard M. Lewis Ship
* @see org.apache.tapestry.internal.annotations.Synchronized
@@ -28,6 +31,21 @@
{
private final ReadWriteLock _lock = new ReentrantReadWriteLock();
+ private final ThreadLocal<Boolean> _threadHasReadLock = new ThreadLocal<Boolean>()
+ {
+ @Override
+ protected Boolean initialValue()
+ {
+ return false;
+ }
+ };
+
+ private void log(JoinPoint jp, String message)
+ {
+ if (false)
+ System.out.println(String.format("%s\n %s:\n %s\n", jp, _lock, message));
+ }
+
pointcut annotatedClasses() :
targetClasses() && within(@Synchronized *);
@@ -47,39 +65,76 @@
execution(@Synchronized.Read @Synchronized.Write * *(..)) :
"A method may be annotated with Synchronized.Read or with Synchronized.Write but not both.";
- pointcut readMethods() :
- execution(@Synchronized.Read * *(..)) && annotatedClasses();
-
pointcut writeMethods() :
- execution(@Synchronized.Write * *(..)) && annotatedClasses();
+ execution(@Synchronized.Write * *(..));
+
+ pointcut readMethods() :
+ execution(@Synchronized.Read * *(..));
- /** Before read lock methods, acquire the read lock. */
- before() : readMethods()
+ Object around() : readMethods()
{
- _lock.readLock().lock();
+ boolean locked = _threadHasReadLock.get();
+
+ if (!locked)
+ {
+ log(thisJoinPoint, "acquiring read lock");
+
+ _lock.readLock().lock();
+
+ _threadHasReadLock.set(true);
+ }
+
+ try
+ {
+ return proceed();
+ }
+ finally
+ {
+ if (!locked)
+ {
+ log(thisJoinPoint, "releasing read lock");
+
+ _lock.readLock().unlock();
+
+ _threadHasReadLock.set(false);
+ }
+ }
}
- /** After read lock methods (including thrown exceptions), release the read lock. */
- after() : readMethods()
+ Object around() : writeMethods()
{
- _lock.readLock().unlock();
- }
+ boolean locked = _threadHasReadLock.get();
- /**
- * Before write lock methods, acquire the write lock. Note that obtaining the write lock will
- * block indefinately if the current thread has a read lock, but we handle that as a special
- * case.
- */
+ if (locked)
+ {
+ log(thisJoinPoint, "releasing read lock (for upgrade)");
+
+ _lock.readLock().unlock();
+
+ _threadHasReadLock.set(false);
+ }
+
+ log(thisJoinPoint, "acquiring write lock");
- before(): writeMethods()
- {
_lock.writeLock().lock();
- }
- /** And release the write lock after the method completes (successfully, or with an exception). */
- after() : writeMethods()
- {
- _lock.writeLock().unlock();
+ try
+ {
+ return proceed();
+ }
+ finally
+ {
+ log(thisJoinPoint, "releasing write lock");
+ _lock.writeLock().unlock();
+
+ if (locked)
+ {
+ log(thisJoinPoint, "acquiring read lock (for downgrade)");
+
+ _lock.readLock().lock();
+
+ _threadHasReadLock.set(true);
+ }
+ }
}
-
}
Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/ConstructorArg.java
URL: http://svn.apache.org/viewcvs/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/ConstructorArg.java?rev=397093&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/ConstructorArg.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/ConstructorArg.java Tue Apr 25 22:42:35 2006
@@ -0,0 +1,45 @@
+package org.apache.tapestry.internal.transform;
+
+import javassist.CtClass;
+
+import org.apache.tapestry.internal.annotations.SuppressNullCheck;
+
+import static org.apache.tapestry.util.Defense.notNull;
+
+/**
+ * Stores transformation type data about one argument to a class constructor.
+ *
+ * @author Howard M. Lewis Ship
+ */
+public class ConstructorArg
+{
+ final CtClass _type;
+
+ final Object _value;
+
+ /**
+ * Constructs new instance.
+ *
+ * @param type
+ * type of the parameter to be created (may not be null)
+ * @param value
+ * value to be injected via the constructor (may be null)
+ */
+ @SuppressNullCheck
+ ConstructorArg(CtClass type, Object value)
+ {
+ _type = notNull(type, "type");
+ _value = value;
+ }
+
+ public CtClass getType()
+ {
+ return _type;
+ }
+
+ /** The value to be injected (may be null). */
+ public Object getValue()
+ {
+ return _value;
+ }
+}
\ No newline at end of file
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/InternalClassTransformation.java
URL: http://svn.apache.org/viewcvs/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/InternalClassTransformation.java?rev=397093&r1=397092&r2=397093&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/InternalClassTransformation.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/InternalClassTransformation.java Tue Apr 25 22:42:35 2006
@@ -14,8 +14,11 @@
package org.apache.tapestry.internal.transform;
+import java.util.List;
+
import org.apache.tapestry.transform.ClassTransformWorker;
import org.apache.tapestry.transform.ClassTransformation;
+import org.apache.tapestry.util.IdAllocator;
/**
* Extends {@link org.apache.tapestry.transform.ClassTransformation} with additional methods that
@@ -46,4 +49,15 @@
* @return the component's instantiator
*/
Instantiator createInstantiator(Class componentClass);
+
+ /**
+ * Returns a copy of the transformation's IdAllocator. Used when creating a child class
+ * transformation. May only be invoked on a frozen transformation.
+ */
+ IdAllocator getIdAllocator();
+
+ /**
+ * Returns a copy of the list of constructor arguments for this class.
+ */
+ List<ConstructorArg> getConstructorArgs();
}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/InternalClassTransformationImpl.java
URL: http://svn.apache.org/viewcvs/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/InternalClassTransformationImpl.java?rev=397093&r1=397092&r2=397093&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/InternalClassTransformationImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/InternalClassTransformationImpl.java Tue Apr 25 22:42:35 2006
@@ -31,14 +31,13 @@
import javassist.CtNewConstructor;
import javassist.CtNewMethod;
import javassist.NotFoundException;
-import javassist.expr.ExprEditor;
-import javassist.expr.FieldAccess;
import org.apache.tapestry.ComponentResources;
import org.apache.tapestry.events.ComponentLifecycle;
import org.apache.tapestry.internal.InternalComponentResources;
import org.apache.tapestry.internal.annotations.SuppressNullCheck;
import org.apache.tapestry.transform.MethodSignature;
+import org.apache.tapestry.util.CollectionFactory;
import org.apache.tapestry.util.IdAllocator;
import static java.lang.String.format;
@@ -62,11 +61,11 @@
private final ClassPool _classPool;
- private Set<CtMethod> _addedMethods = newSet();
+ // private Set<CtMethod> _addedMethods = newSet();
- private final IdAllocator _idAllocator = new IdAllocator();
+ private final IdAllocator _idAllocator;
- private final Map<CtField, FieldEncapsulation> _encapsulations = newMap();
+ // private final Map<CtField, FieldEncapsulation> _encapsulations = newMap();
/** Map from a field to the annotation objects for that field. */
private Map<String, Object[]> _fieldAnnotations = newMap();
@@ -80,15 +79,10 @@
private Object[] _classAnnotations;
- /** Contains the assembled Javassist code for the class' constructor. */
+ /** Contains the assembled Javassist code for the class' default constructor. */
private StringBuffer _constructor = new StringBuffer();
- // Argument #0 is always "this". We always add argument #1 (i.e., $1) to be the
- // InternalComponentResources. From there it all about injections.
-
- private int _constructorArgIndex = 0;
-
- private final List<ConstructorArg> _constructorArgs = newList();
+ private final List<ConstructorArg> _constructorArgs;
// All field/method names will have this value as a prefix
@@ -96,37 +90,20 @@
private final String _resourcesFieldName;
- private static class ConstructorArg
- {
- private final CtClass _type;
-
- private final Object _value;
-
- @SuppressNullCheck
- ConstructorArg(CtClass type, Object value)
- {
- _type = type;
- _value = value;
- }
-
- CtClass getType()
- {
- return _type;
- }
-
- Object getValue()
- {
- return _value;
- }
- }
-
+ /**
+ * This is a constructor for the root class, the class that directly contains the ComponentClass
+ * annotation.
+ */
public InternalClassTransformationImpl(CtClass ctClass)
{
_ctClass = ctClass;
_classPool = _ctClass.getClassPool();
+ _idAllocator = new IdAllocator();
+
preloadMemberNames();
+ _constructorArgs = newList();
_constructor.append("{\n");
addImplementedInterface(ComponentLifecycle.class);
@@ -141,6 +118,40 @@
extendMethod(sig, "return " + _resourcesFieldName + ";");
}
+ public InternalClassTransformationImpl(CtClass ctClass,
+ InternalClassTransformation parentTransformation)
+ {
+ _ctClass = ctClass;
+ _classPool = _ctClass.getClassPool();
+ _resourcesFieldName = parentTransformation.getResourcesFieldName();
+
+ _idAllocator = parentTransformation.getIdAllocator();
+
+ preloadMemberNames();
+
+ _constructorArgs = parentTransformation.getConstructorArgs();
+
+ int count = _constructorArgs.size();
+
+ // Build the call to the super-constructor.
+
+ _constructor.append("{ super(");
+
+ for (int i = 1; i <= count; i++)
+ {
+ if (i > 1)
+ _constructor.append(", ");
+
+ // $0 is implicitly self, so the 0-index ConstructorArg will be Javassisst
+ // pseudeo-variable $1, and so forth.
+
+ _constructor.append("$" + i);
+ }
+
+ _constructor.append(");\n");
+
+ }
+
public String getResourcesFieldName()
{
return _resourcesFieldName;
@@ -261,7 +272,7 @@
public String newMemberName(String suggested)
{
- checkFrozen();
+ failIfFrozen();
String memberName = createMemberName(notBlank(suggested, "suggested"));
@@ -271,7 +282,7 @@
/** Strips leading characters defined by {@link #NAME_PREFIX}. */
private String createMemberName(String memberName)
{
- checkFrozen();
+ failIfFrozen();
StringBuilder builder = new StringBuilder(memberName);
@@ -296,62 +307,63 @@
return builder.toString();
}
- public void addFieldEncapsulation(CtField field, String readMethodName, String writeMethodName)
- {
- checkFrozen();
-
- // TODO: Check if field already encapsulated
-
- FieldEncapsulation fe = new FieldEncapsulation(readMethodName, writeMethodName);
-
- _encapsulations.put(field, fe);
- }
-
- public void applyFieldEncapsulations()
- {
- checkFrozen();
-
- ExprEditor editor = new ExprEditor()
- {
-
- @Override
- public void edit(FieldAccess f) throws CannotCompileException
- {
- // Methods added as part of enhancement are NOT subject
- // to field encapsulation.
-
- if (_addedMethods.contains(f.where()))
- return;
-
- try
- {
- CtField field = f.getField();
- FieldEncapsulation fe = _encapsulations.get(field);
-
- if (fe != null)
- fe.encapsulate(f);
- }
- catch (NotFoundException ex)
- {
- throw new RuntimeException(ex);
- }
- }
-
- };
-
- try
- {
- _ctClass.instrument(editor);
- }
- catch (CannotCompileException ex)
- {
- throw new RuntimeException(ex);
- }
- }
+ // public void addFieldEncapsulation(CtField field, String readMethodName, String
+ // writeMethodName)
+ // {
+ // failIfFrozen();
+ //
+ // // TODO: Check if field already encapsulated
+ //
+ // FieldEncapsulation fe = new FieldEncapsulation(readMethodName, writeMethodName);
+ //
+ // _encapsulations.put(field, fe);
+ // }
+ //
+ // public void applyFieldEncapsulations()
+ // {
+ // failIfFrozen();
+ //
+ // ExprEditor editor = new ExprEditor()
+ // {
+ //
+ // @Override
+ // public void edit(FieldAccess f) throws CannotCompileException
+ // {
+ // // Methods added as part of enhancement are NOT subject
+ // // to field encapsulation.
+ //
+ // if (_addedMethods.contains(f.where()))
+ // return;
+ //
+ // try
+ // {
+ // CtField field = f.getField();
+ // FieldEncapsulation fe = _encapsulations.get(field);
+ //
+ // if (fe != null)
+ // fe.encapsulate(f);
+ // }
+ // catch (NotFoundException ex)
+ // {
+ // throw new RuntimeException(ex);
+ // }
+ // }
+ //
+ // };
+ //
+ // try
+ // {
+ // _ctClass.instrument(editor);
+ // }
+ // catch (CannotCompileException ex)
+ // {
+ // throw new RuntimeException(ex);
+ // }
+ // }
public void addImplementedInterface(Class interfaceClass)
{
- checkFrozen();
+ failIfFrozen();
String interfaceName = interfaceClass.getName();
@@ -460,7 +472,7 @@
{
notBlank(fieldName, "fieldName");
- checkFrozen();
+ failIfFrozen();
Object existing = _claimedFields.get(fieldName);
@@ -482,7 +494,7 @@
public void extendMethod(MethodSignature methodSignature, String methodBody)
{
- checkFrozen();
+ failIfFrozen();
CtMethod method = findMethod(methodSignature);
@@ -574,7 +586,7 @@
public String[] findUnclaimedFields()
{
- checkFrozen();
+ failIfFrozen();
List<String> names = newList();
@@ -623,7 +635,7 @@
public String addField(int modifiers, String type, String suggestedName)
{
- checkFrozen();
+ failIfFrozen();
String fieldName = newMemberName(suggestedName);
@@ -655,7 +667,7 @@
{
notNull(type, "type");
- checkFrozen();
+ failIfFrozen();
// TODO: Probably doesn't handle arrays and primitives.
@@ -672,10 +684,10 @@
String fieldName = addField(Modifier.PROTECTED, type.getName(), suggestedName);
- _constructor.append(format("%s = $%d;\n", fieldName, ++_constructorArgIndex));
-
_constructorArgs.add(new ConstructorArg(ctType, value));
+ _constructor.append(format("%s = $%d;\n", fieldName, _constructorArgs.size()));
+
return fieldName;
}
@@ -686,7 +698,7 @@
public void finish()
{
- checkFrozen();
+ failIfFrozen();
int count = _constructorArgs.size();
@@ -719,7 +731,7 @@
// Free up stuff we don't need after freezing.
- _addedMethods = null;
+ // _addedMethods = null;
_claimedFields = null;
_addedFieldNames = null;
_fieldAnnotations = null;
@@ -750,11 +762,33 @@
return new ReflectiveInstantiator(componentClass, parameters);
}
- private void checkFrozen()
+ private void failIfFrozen()
{
if (_frozen)
throw new IllegalStateException("The ClassTransformation instance (for "
+ _ctClass.getName()
+ ") has completed all transformations and may not be further modified.");
}
+
+ private void failIfNotFrozen()
+ {
+ if (!_frozen)
+ throw new IllegalStateException("The ClassTransformation instance (for "
+ + _ctClass.getName() + ") has not yet completed all transformations.");
+ }
+
+ public IdAllocator getIdAllocator()
+ {
+ failIfNotFrozen();
+
+ return _idAllocator;
+ }
+
+ public List<ConstructorArg> getConstructorArgs()
+ {
+ failIfNotFrozen();
+
+ return CollectionFactory.newList(_constructorArgs);
+ }
+
}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/util/CollectionFactory.java
URL: http://svn.apache.org/viewcvs/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/util/CollectionFactory.java?rev=397093&r1=397092&r2=397093&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/util/CollectionFactory.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/util/CollectionFactory.java Tue Apr 25 22:42:35 2006
@@ -27,7 +27,7 @@
/**
* Static factory methods to ease the creation of new collection types (when using generics). Most
* of these method leverage the compiler's ability to match generic types by return value. Typical
- * usage:
+ * usage (with a static import):
*
* <pre>
* Map<Foo, Bar> map = newMap();
@@ -70,6 +70,12 @@
public static <T> List<T> newList()
{
return new ArrayList<T>();
+ }
+
+ /** Constructs and returns a new {@link ArrayList} as a copy of the provided list. */
+ public static <T> List<T> newList(List<T> list)
+ {
+ return new ArrayList<T>(list);
}
/** Easy way to convert an array of like-typed values into a list. */
Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/aspects/SynchTargetWrapper.java
URL: http://svn.apache.org/viewcvs/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/aspects/SynchTargetWrapper.java?rev=397093&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/aspects/SynchTargetWrapper.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/aspects/SynchTargetWrapper.java Tue Apr 25 22:42:35 2006
@@ -0,0 +1,25 @@
+package org.apache.tapestry.internal.aspects;
+
+import org.apache.tapestry.internal.annotations.Synchronized;
+
+/**
+ * Class used to test the {@link Synchronization} aspect.
+ *
+ * @author Howard M. Lewis Ship
+ */
+@Synchronized
+public class SynchTargetWrapper implements Runnable
+{
+ private final SynchronizationTarget _target;
+
+ public SynchTargetWrapper(SynchronizationTarget target)
+ {
+ _target = target;
+ }
+
+ @Synchronized.Read
+ public void run()
+ {
+ _target.incrementCounter();
+ }
+}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/aspects/SynchronizationAspectTest.java
URL: http://svn.apache.org/viewcvs/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/aspects/SynchronizationAspectTest.java?rev=397093&r1=397092&r2=397093&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/aspects/SynchronizationAspectTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/aspects/SynchronizationAspectTest.java Tue Apr 25 22:42:35 2006
@@ -8,7 +8,6 @@
import static org.apache.tapestry.util.CollectionFactory.newList;
import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertTrue;
/** @author Howard M. Lewis Ship */
public class SynchronizationAspectTest extends TestBase
@@ -21,9 +20,9 @@
_target = new SynchronizationTarget();
}
- private static final int THREAD_COUNT = 1000;
+ private static final int THREAD_COUNT = 100;
- private static final int THREAD_BLOCK_SIZE = 50;
+ private static final int THREAD_BLOCK_SIZE = 5;
@Test
public void readLockThenWriteLock() throws Exception
@@ -32,12 +31,7 @@
{
public void run()
{
-
- int start = _target.getCounter();
-
_target.incrementCounter();
-
- assertTrue(_target.getCounter() > start);
}
};
@@ -51,25 +45,63 @@
{
public void run()
{
+ // Gets a write lock, then a read lock.
+ _target.incrementCounterHard();
+ }
+ };
- int start = _target.getCounter();
+ runOperation(operation);
+ }
- // Gets a write lock, then a read lock.
+ @Test(enabled = true)
+ public void writeLockInsideReadLock() throws Exception
+ {
+ Runnable operation = new Runnable()
+ {
+ public void run()
+ {
+ // A read lock method that upgrades to a write lock
- _target.incrementCounterHard();
+ _target.incrementIfNonNegative();
+ }
+ };
- // If we tried _target.incrementIfNonNegative() we would
- // hang!
+ runOperation(operation);
+ }
+
+ @Test(enabled = true)
+ public void testIndirection() throws Exception
+ {
+ Runnable operation = new Runnable()
+ {
+ public void run()
+ {
+
+ // Read lock method invokes other class, that invokes write method.
- assertTrue(_target.getCounter() > start);
+ _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 testMultipleObjects() throws Exception
+ {
+ Runnable operation = new SynchTargetWrapper(_target);
+
+ runOperation(operation);
+ }
+
private void runOperation(Runnable operation) throws InterruptedException
{
+ // System.out.println("** Start synchronization");
+
List<Thread> threads = newList();
List<Thread> running = newList();
@@ -92,6 +124,8 @@
t.join();
assertEquals(_target.getCounter(), THREAD_COUNT);
+
+ // System.out.println("** End synchronization");
}
private void startThreads(List<Thread> threads, List<Thread> running)
Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/aspects/SynchronizationTarget.java
URL: http://svn.apache.org/viewcvs/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/aspects/SynchronizationTarget.java?rev=397093&r1=397092&r2=397093&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/aspects/SynchronizationTarget.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/aspects/SynchronizationTarget.java Tue Apr 25 22:42:35 2006
@@ -3,7 +3,7 @@
import org.apache.tapestry.internal.annotations.Synchronized;
/**
- * Class used to test the {@link Synchorization} aspect.
+ * Class used to test the {@link Synchronization} aspect.
*
* @author Howard M. Lewis Ship
*/
@@ -12,6 +12,13 @@
{
private int _counter;
+ // Used to check if read locks accumulate when @Read calls @Read
+ @Synchronized.Read
+ public int readCounter()
+ {
+ return getCounter();
+ }
+
@Synchronized.Read
public int getCounter()
{
@@ -35,6 +42,20 @@
{
if (_counter >= 0)
incrementCounter();
+ }
+
+ @Synchronized.Read
+ public void incrementViaRunnable()
+ {
+ Runnable r = new Runnable()
+ {
+ public void run()
+ {
+ incrementCounter();
+ }
+ };
+
+ r.run();
}
@Synchronized.Write
Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/util/CollectionFactoryTest.java
URL: http://svn.apache.org/viewcvs/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/util/CollectionFactoryTest.java?rev=397093&r1=397092&r2=397093&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/util/CollectionFactoryTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/util/CollectionFactoryTest.java Tue Apr 25 22:42:35 2006
@@ -22,6 +22,7 @@
import java.util.Map;
import java.util.Set;
+import org.testng.Assert;
import org.testng.annotations.Test;
import static org.apache.tapestry.util.CollectionFactory.newList;
@@ -29,6 +30,7 @@
import static org.apache.tapestry.util.CollectionFactory.newSet;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotSame;
import static org.testng.Assert.assertTrue;
/**
@@ -84,5 +86,15 @@
assertEquals(actual, Arrays.asList(new String[]
{ "Fred", "Barney", "Wilma" }));
+ }
+
+ @Test
+ public void newListCopy()
+ {
+ List<String> start = newList("Fred", "Barney", "Wilma");
+ List<String> copy = newList(start);
+
+ assertNotSame(copy, start);
+ assertEquals(copy, start);
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-dev-help@jakarta.apache.org