AOP has a vocabulary for the solution model it provides. AOP requires that the functionality of the cross-cutting concern be developed in a module that is known as advice. Advice is run at the points where the cross-cutting advice is needed, i.e., pointcuts. In the code below, the aspect is SecurityAspect.aj. The aspect is the code that weaves the Authenticator (the advice) and the CheckingAccount.deposit() method (the pointcut) together.
This example weaves a security component, the Authenticator class, as an aspect into the domain logic. The aspect requires the user to supply his user-id and password before the deposit() methods is called. Note that AOP allows development of the business logic to proceed completely independently of the development of the security components.
In my aspectj.home folder I have aspectj-1.6.6.jar, aspectrt.jar and aspectjtools-1.5.3.jar.
build.xml
<project name="MessageCommunicator" default="run" basedir="."> <property name="src" location="src/main/java"/> <property name="test.src" location="src/test/java"/> <property name="build" location="build"/> <property name="build.classes" location="build/main/classes"/> <property name="test.classes" location="build/test/classes"/> <property name="aspectj.home" location="/users/greghelton/dev/lib/aspectj"/> <path id="project.classpath"> <pathelement location="${build.classes}"/> <fileset dir="${aspectj.home}"> <include name="**/*.jar"/> </fileset> </path> <target name="clean"> <delete dir="${build}"/> <delete dir="${test.classes}"/> </target> <target name="init" depends="clean"> <mkdir dir="${build.classes}"/> <mkdir dir="${test.classes}"/> </target> <taskdef resource="org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties"> <classpath> <pathelement location="${aspectj.home}/aspectjtools-1.5.3.jar"/> </classpath> </taskdef> <target name="compile" depends="init"> <iajc destdir="${build.classes}" source="1.5" srcdir="${src}"> <classpath refid="project.classpath" /> </iajc> </target> <target name="run" depends="compile"> <java classname="ajia.main.Main"> <classpath><path refid="project.classpath"/></classpath> </java> </target> </project>
package ajia.main; import ajia.banking.CheckingAccount; public class Main { public static void main(String[] args) { CheckingAccount account = new CheckingAccount(); account.deposit( 300 ); } }
package ajia.banking; public class CheckingAccount { public void deposit(int dollars) { System.out.println("Deposited $" + dollars); } }
package ajia.security; public class AuthenticationException extends RuntimeException { public AuthenticationException(String message) { super(message); } }
package ajia.security; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; public class Authenticator { private ThreadLocalauthenticatedUser = new ThreadLocal (); public void authenticate() { if (isAuthenticated()) { return; } String[] userNamePassword = getUserNamePassword(); if (!userNamePassword[0].equals(userNamePassword[1])) { throw new AuthenticationException("User/password didn't match"); } authenticatedUser.set(userNamePassword[0]); } public boolean isAuthenticated() { return authenticatedUser.get() != null; } public String[] getUserNamePassword() { boolean usePrintln = Boolean.getBoolean("ant.run"); String[] userNamePassword = new String[2]; try { if (usePrintln) { System.out.println("Username: "); } else { System.out.print("Username: "); } BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); userNamePassword[0] = in.readLine().trim(); if (usePrintln) { System.out.println("Password: "); } else { System.out.print("Password: "); } userNamePassword[1] = in.readLine().trim(); } catch (IOException ex) { // ignore... will return array of null strings } return userNamePassword; } }
package ajia.security; import ajia.banking.CheckingAccount; public aspect SecurityAspect { private Authenticator authenticator = new Authenticator(); pointcut secureAccess() : execution(* CheckingAccount.deposit(..)); before() : secureAccess() { System.out.println("Authenticating user"); authenticator.authenticate(); } }
[greg:aspect] ant Buildfile: build.xml clean: [delete] Deleting directory /Users/greghelton/dev/src/java/aspect/build init: [mkdir] Created dir: /Users/greghelton/dev/src/java/aspect/build/main/classes [mkdir] Created dir: /Users/greghelton/dev/src/java/aspect/build/test/classes compile: run: [java] Checking and authenticating user greg greg [java] Username: Password: Deposited $300 BUILD SUCCESSFUL Total time: 11 seconds