/* Aspect Oriented Bank Accounts */ import javax.swing.*; // for simple io // classic oop base program: class account { private double balance; private String owner; public account(double x, String s) { balance=x; owner=s; } public String owner() { return owner; } public void withdraw(double a) { balance -= a; } public void deposit(double a) { balance += a; } public double inquiry() { return balance; } } // account // test public class aopbank { public static void main(String[] args) { account a1 = new account(2000,"good student"); account a2 = new account(1000,"evil professor"); a1.deposit(400); a2.withdraw(-500000); // trying to cheat System.out.println("a1 balance is "+a1.inquiry()); System.out.println("a2 balance is "+a2.inquiry()); System.exit(0); } } // aopbank /* Now I want to organize the software development process into several components, each component is *oriented* towards some particular aspect of the software to be developed. The word "aspect" sounds vague because it is meant to convey flexibility in how the development of software is to be organized */ // The "auditor" aspects makes sure that inputs to withdraw/deposit are // valid (e.g, can't withdraw a negative amount) // A privileged aspect can acess any class'es private elements: privileged aspect auditor { // A before or after advice won't prevent the original method from // being called (unless an error is thrown). We need an "around" // advice if we want to dynamically modify the behavior of a method void around(double a) : call(void account.deposit(double)) && args(a) { if (a<0) System.out.println("You can't deposit a negative amount!"); else proceed(a); // continue with call } void around(account A, double x) : call(void account.withdraw(..)) && args(x) && target(A) { if (x>A.balance || x<0) System.out.println("Invalid withdraw amount: "+x); else proceed(A,x); // proceed takes same args as advice } } // auditor aspect // The "gouge" aspect gouges customers by charging a fee for every // transaction. Transactions initiated internally, from "within" // the account class, or through an "adviceexeuction", are exempt. privileged aspect gouge { before(account A) : target(A) && call(public * account.*(..)) && !within(account) && !adviceexecution() { A.balance += 2; // charge 2 bucks for every transaction } } // The security aspect dynamically modifies the account class to include // a secret password, and modifies other methods to make use of the // password privileged aspect passwordsecurity { // new element: "private" is relative to the aspect, not account: private String account.passwd; pointcut openaccount(account A) : execution(account.new(..)) && target(A); after(account A) returning : openaccount(A) { A.passwd = JOptionPane.showInputDialog(null, A.owner+", enter a password and don't tell any bad people:"); } pointcut transaction(account A) : target(A) && !within(account) && !within(passwordsecurity) && !adviceexecution(); void around (account A) : transaction(A) && (call(void account.withdraw(..)) || call(void account.deposit(..))) { String s = JOptionPane.showInputDialog(null, A.owner+", enter your password:"); if (A.passwd.equals(s)) proceed(A); else JOptionPane.showMessageDialog(null,"Bad password!"); } // need a similar advice to handle inquiry, owner() } // password security aspec /* You might have thought that, instead of using "around" advice inside objects we could have created a new subclass with overriding methods. We also would not have had to modify the original code. However, we would still have the problem of "weaving" different subclasses together - that is, how would we integrate the security "subclass" with the "auditor" subclass? Also, the code relevant to security may require modifications to several existing classes, and we would be hard-pressed to localize all the security code in one, or even several classes. This would be what's referred to as a "cross-cutting concern" in the AOP literature. Object-orientation (aka data-orientation) lets us structure our programs around the data and the algorithms we must write for the data. AOP will not change the fact that algorithms still must be written, but it does allow us to structure our programs at a more conceptual level, by organizing it around arbitrary "concerns" or "aspects" such as security. */ /* PART OF AOP PROGRAMMING ASSIGNMENT Now you do one: Write an aspect that stores a transaction record for every account. Dynamically add a new method (inside an aspect) that prints out the record. Here's linked list class to help you (each account needs to store one of these lists: */ class record { private String transaction; private record previous; // pointer to previous transaction. public record(String t, record r) { transaction=t; previous = r; } public void printrecord() { for(record i=this;i!=null;i=i.previous) System.out.println(i.transaction); } } /* The structure is used like a stack, so the top of the list represent the most recent transaction (you can reverse it if you want, but usually that's for normal people. Real geeks love stacks even though it means we have to think in reverse sometimes. If you want to be normal, that's fine, we'll try not to laugh. :) To add a new transaction to the record, just do myrecord = new("withdrew $50",myrecord); */