Since the last example of the new 'annotation-defined aspects' model in AspectWerkz seemed to have caused a lot of confusion and made people miss the point, I will in this post try to give a more detailed explaination of the previous 'Role-Based Security' example.
First I just want to stress that this new model of defining the aspects will NOT in any sense make the old pure XML based and the doclet based approaches obsolete. We are here simply providing a new option. A ticket out of deployment descriptor hell.
I also would like to mention that this new model is completely user-demand driven. It solely exists due to the fact that there is a high need for it. It basically solves three problems that the users have been complaining about:- Separation of implementation and definition. The implementation and the definition are defined in one single file (in the same bytecode). The aspect definition is thus not separated from the aspect implementation
- All advices and introductions needed to implement a concern can be implemented in one single class. The problem with the old approach was that you f.e. for a regular Aspect with two advices and an introduction needed four files. One for each advice and introductions as well as one for the definition. This felt like EJB all over again and the new model addresses this problem in a neat way allowing you to implement everything that is needed in one single class.
- Not pure Java. Even though XML is widely used in the J2EE community and intuitive to most users, it is not Java. It suffers from problems with refactoring, maintainance, reusability etc. This new model tries to address this as well. Even thought the current implementation, based on JavaDoc tags, is not pure Java, it is closer to it and it will be pure Java when we have Java 1.5. Which is what this new model is targetting.
/**
* @Aspect perThread
*/
public abstract class AbstractRoleBasedAccessController extends Aspect {
protected Subject m_subject = null;
protected final SecurityManager m_securityManager = ...
/** To be defined by the concrete aspect. */
Pointcut authenticationPoints;
/** To be defined by the concrete aspect. *
Pointcut authorizationPoints;
/**
* @Around authenticationPoints
*/
public Object authenticateUser(JoinPoint joinPoint) throws Throwable {
if (m_subject == null) {
// no subject => authentication required
Context ctx = ... // get the principals and credentials
m_subject = m_securityManager.authenticate(ctx); // throws an exception if not authenticated
}
Object result = Subject.doAsPrivileged(
m_subject, new PrivilegedExceptionAction() {
public Object run() throws Exception {
return joinPoint.proceed();
};
}, null
);
return result;
}
/**
* @Around authorizationPoints
*/
public Object authorizeUser(JoinPoint joinPoint) throws Throwable {
MethodJoinPoint jp = (MethodJoinPoint)joinPoint;
if (m_securityManager.checkPermission(
m_subject,
jp.getTargetClass(),
jp.getMethod())) {
// user is authorized => proceed
return joinPoint.proceed();
}
else {
throw new SecurityException(...);
}
}
}
/**
* @Aspect perThread
*/
public class RoleBasedAccessController extends AbstractRoleBasedAccessController {
/**
* @Execution * *..facade.*.*(..)
*/
Pointcut authenticationPoints;
/**
* @Execution * *..service.*.*(..)
*/
Pointcut authorizationPoints;
}
<aspectwerkz>
<system id="security-test">
<package name="example">
<use-aspect class="RoleBasedAccessController">
<param name="type" value="JAAS">
</use-aspect>
</package>
</system>
</aspectwerkz>
<aspectwerkz>
<system id="security-test">
<package name="example">
<use-aspect class="AbstractRoleBasedAccessController">
<pointcut-def name="authenticationPoints" type="execution" pattern="* *..facade.*.*(..)"/>
<pointcut-def name="authorizationPoints" type="execution" pattern="* *..service.*.*(..)"/>
</use-aspect>
</package>
</system>
</aspectwerkz>