[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[aspectj-users] (no subject)

I'm writing some synchronization aspects now.

I want to annotation methods with @ReadLock or @WriteLock and have the
annotation manage the lock.

So far, so good:

package org.apache.tapestry.internal.aspects;

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import org.apache.tapestry.internal.annotations.ReadLock;
import org.apache.tapestry.internal.annotations.WriteLock;

/**
 * Associates a {@link java.util.concurrent.locks.ReadWriteLock} with
an object instance; the
 * {@link ReadLock} and {@link WriteLock} annotations drive this.
Methods that have the ReadLock
 * annotation witll be advised to obtain and release the read lock
around their execution. Methods
 * with the WriteLock annotation will obtain and release the write
lock around their execution.
 * Methods with ReadLock that call a WriteLock-ed method (within the
same instance) will release the
 * read lock before invoking the WriteLock-ed method.
 * <p>
 * This aspect also enforces that the annotations are only applied to
instance (not static) methods.
 *
 * @author Howard M. Lewis Ship
 */
public abstract aspect Synchronization extends AbstractClassTargetting
perthis(readLockMethods() || writeLockMethods())
{
    private final ReadWriteLock _lock = new ReentrantReadWriteLock();

    declare error :
        targetClasses() &&
        execution(@(ReadLock || WriteLock) static * *(..)) :
            "ReadLock and WriteLock annotations may only be applied to
instance methods.";

    declare error :
        targetClasses() &&
        execution(@ReadLock @WriteLock * *(..)) :
            "A method may be annotated with ReadLock or with WriteLock
but not both.";

    pointcut readLockMethods() :
        targetClasses() &&
        execution(@ReadLock * *(..));

    pointcut writeLockMethods() :
        targetClasses() &&
        execution(@WriteLock * *(..));

    /** Before read lock methods, acquire the read lock. */
    before() : readLockMethods()
    {
        _lock.readLock().lock();
    }

    /** After read lock methods (including thrown exceptions), release
the read lock. */
    after() : readLockMethods()
    {
        _lock.readLock().unlock();
    }

    /**
     * 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.
     */

    before(): writeLockMethods()
    {
        _lock.writeLock().lock();
    }

    /** And release the write lock after the method completes
(successfully, or with an exception). */
    after() : writeLockMethods()
    {
        _lock.writeLock().unlock();
    }

}


Here's my new issues:

1. Using perthis() creates the aspect instance dynamically, but I'm
worried that it uses a synchronized block that will serialize my
methods after all the effort I've put in to make them highly parallel
(using the readwrite lock).

2. One very important case is not coverred:

If a method with @ReadLock invokes a method OF THE SAME INSTANCE with
@WriteLock, then we need to release the read lock before we invoke the
write lock method, then re-obtain the read lock afterwards.  This
feels like something you would do with cflow(), but I can't figure out
how to bind to an instance, rather than a type.

BTW, I'm finding the combintation of Aspects and Annotations to be
very powerful.
Using annotations to mark types or methods works well in combintaion
with a base aspect that defines an abstract targetClasses() pointcut. 
Concrete aspects provide a specific set of classes for targetClasses()
and the annotation matching does the rest.

Thanks in advance!
--
Howard M. Lewis Ship
Independent J2EE / Open-Source Java Consultant
Creator, Jakarta Tapestry
Creator, Jakarta HiveMind

Professional Tapestry training, mentoring, support
and project work.  http://howardlewisship.com