SW-Archäologie mit AspectJ Ausgrabungen vergangener SW-Architekturen Java Forum Stuttgart 2015 oliver.boehm@aosd.de 1
Agenda. 1.0 2.0 3.0 4.0 5.0 Die klassische Herangehensweise Ein kleiner Ausflug mit AOP Herangehensweise mit AOP Fazit Diskussion Es gibt zwei Arten von Programmen: Die einen laufen nicht, und die anderen sind veraltet. 09/24/13 2
1.0 Die klassische Herangehensweise Eigentlich waren wir noch nicht fertig, aber wir mussten liefern. 3
Wunsch! die Anwendung ist dokumentiert! die Doku ist aktuell! Test-System vorhanden! Unit-Tests u. Integrationstests! Testergebnisse reproduzierbar! Know-How vorhanden
Wunsch und Realität! die Anwendung ist dokumentiert! die Doku ist aktuell! Test-System vorhanden! Unit-Tests u. Integrationstests! Testergebnisse reproduzierbar! Know-How vorhanden! Doku? Welche Doku?! Doku wurde nie aktualisiert! Test-System = Produktivsystem! viele rote JUnit-Tests! agile Test-Daten! ehem. Entwickler verschwunden
Einstieg Dokumentation! Pflichtenheft! Architektur-Dokumente! hilfreich: Übersicht über die Architektur! Klassendiagramme und andere UML-Diagramme! Infrastruktur! beteiligte Systeme! Firewalls
https://www.flickr.com/photos/98640399@n08/10030588973/ Für wen? Aktualität? Wo? Ansprechpartner?
Realität Die aktuell gültige Quelle ist der Source-Code!
Alles was mir hilft, den Sourcecode zu verstehen, hilft mir das System zu verstehen. streng vertraulich, vertraulich, intern, öffentlich Autor / Thema der Präsentation 09/24/13 9
Testsysteme vorhanden? https://www.flickr.com/photos/astrablog/5243795143/
Testfälle dokumentieren die dynamische Sicht des Systems 09/24/13 11
2.0 Ein kleiner Ausflug mit AOP Wir haben s nochmal neu geschrieben, weil 1.0 nicht wartbar war. 12
Ein kleiner Abstecher in AOP
public class Konto { private double kontostand = 0.0; public double abfragen() { return kontostand; public void einzahlen(double betrag) { kontostand = kontostand + betrag; public void abheben(double betrag) { kontostand = kontostand - betrag; public void ueberweisen(double betrag, Konto andereskonto) { abheben(betrag); andereskonto.einzahlen(betrag);
public class Konto { private double kontostand = 0.0; alle Kontobewegungen müssen protokolliert werden public double abfragen() { return kontostand; public void einzahlen(double betrag) { kontostand = kontostand + betrag; public void abheben(double betrag) { kontostand = kontostand - betrag; public void ueberweisen(double betrag, Konto andereskonto) { abheben(betrag); andereskonto.einzahlen(betrag);
public class Konto { private static Logger log = Logger.getLogger(Konto.class); private double kontostand = 0.0; werden public double abfragen() { return kontostand; public void einzahlen(double betrag) { kontostand = kontostand + betrag; log.info("neuer Kontostand: " + kontostand); public void abheben(double betrag) { kontostand = kontostand - betrag; alle Kontobewegungen müssen protokolliert public void ueberweisen(double betrag, Konto andereskonto) { abheben(betrag); andereskonto.einzahlen(betrag); log.info("neuer Kontostand: " + kontostand);
fachliche Concerns Einzahlung Auszahlung Überweisung Dauerauftrag technische Concerns Authorisierung Sicherheit Logging GUI Transaktionen
fachliche Concerns Einzahlung Auszahlung Überweisung Dauerauftrag technische Concerns Authorisierung Sicherheit Logging GUI Transaktionen Konto kontostand abfragen einzahlen + logging abheben + logging überweisen
fachliche Concerns Einzahlung Auszahlung Überweisung Dauerauftrag technische Concerns Authorisierung Sicherheit Logging GUI Transaktionen Konto kontostand abfragen einzahlen abheben überweisen LogAspect logging
public aspect LogAspect { wenn sich der Kontostand ändert, gib eine Log- Meldung aus private static Logger log = Logger.getLogger(LogAspect.class); pointcut setkontostand() : set(double bank.konto.kontostand); after(double neu) : setkontostand() && args(neu) { log.info("neuer Kontostand: " + neu);
Program Execution JoinPoints
Pointcuts Program Execution JoinPoints
Pointcuts Program Execution Advice
JoinPoints können sein call execution initialization set/get handler
Konto konto = new Konto(); konto.einzahlen(500.0); 1. call 2. initialization 3. call 4.execution
pointcut setkontostand() : set(double bank.konto.kontostand); pointcut callbankmethods() : call(* bank.*konto.*(*)) call(* bank..*konto.*(..));
Program Execution before Advice after Advice around Advice
after(double neu) : setkontostand() && args(neu) { log.info("neuer Kontostand von " + thisjoinpoint.getthis() + ": " + neu); before() : callbankmethods() { log.debug("test: " + thisjoinpoint);
Object around() : loginrequiredexecutions() { if (!AccessControl.loggedIn()) { log.info("anmeldung notwendig"); try { AccessControl.login(); catch (LoginException e) { throw new AccessControlException("login failed"); return proceed();
public aspect AccessControlAspect { pointcut loginrequiredexecutions() : execution(@loginrequired * bank.konto.*(..));
private double kontostand = 0.0; Konto public void einzahlen(double betrag) { kontostand = kontostand + betrag; public void abheben(double betrag) { kontostand = kontostand - betrag; public void ueberweisen(double betrag, Konto andereskonto) { this.auszahlen(betrag); andereskonto.einzahlen(betrag); KontoAspect pointcut kontobewegung(double betrag): (call(public void bank.konto.einzahlen(double)) call(public void bank.konto.abheben(double))) && args(betrag); before(double betrag) : kontobewegung(betrag) { if (betrag < 0) { throw new IllegalArgumentException("negativer Betrag"); Konto.class private double kontostand = 0.0; public void einzahlen(doube betrag) { if (betrag < 0) { throw new IllegalArgumentException("negativer Betrag"); kontostand = kontostand + betrag; public void abheben(double betrag) { if (betrag < 0) { throw new IllegalArgumentException("negativer Betrag"); kontostand = kontostand - betrag; public void ueberweisen(double betrag, Konto andereskonto) { this.auszahlen(betrag); andereskonto.einzahlen(betrag);
3.0 Herangehensweise mit AOP Jetzt kann man damit arbeiten.
https://www.flickr.com/photos/cadencrawford/8422302030/ Herangehensweise mit AOP Schnittstellen beobachten
https://www.flickr.com/photos/cadencrawford/8422302030/ Schnittstellen beobachten Webbrowser Blackbox System X DB-Host java.net.socketexception: Übersicht java.net.connectexception: (Beispiel) Connection refused at com.mysql.jdbc.standardsocketfactory.connect(standardsocketfactory.java:156) at com.mysql.jdbc.mysqlio.<init>(mysqlio.java:283) at com.mysql.jdbc.connection.createnewio(connection.java:2541) at com.mysql.jdbc.connection.<init>(connection.java:1474) at com.mysql.jdbc.nonregisteringdriver.connect(nonregisteringdriver.java:264) at java.sql.drivermanager.getconnection(drivermanager.java:525) at java.sql.drivermanager.getconnection(drivermanager.java:193) at bank.archiv.init(archiv.java:25)...
https://www.flickr.com/photos/cadencrawford/8422302030/ DB-Verbindungen after() returning(object ret) : call(* java.sql.*.*(..)) { log.trace(joinpointhelper.getasstring(thisjoinpoint) + " = " + ret); java.sql.drivermanager.getconnection("jdbc:mysql://miniserver07:3306/test") = com.mysql.jdbc.connection@16a9d42 java.sql.connection.preparestatement("select kontostand from konto WHERE kontonr =?") = com.mysql.jdbc.serverpreparedstatement[1] - SELECT kontostand from konto WHERE kontonr = nu java.sql.preparedstatement.setint(1, 1) = (null) java.sql.preparedstatement.executequery() = com.mysql.jdbc.resultset@183f74d java.sql.resultset.next() = true java.sql.resultset.getdouble(1) = 5055.94 java.sql.resultset.close() = (null)
https://www.flickr.com/photos/cadencrawford/8422302030/ Aufruf von außen (1) public pointcut executepublic() : (execution(public * bank..*.*(..)) execution(public bank..*.new(..))) &&!within(environmentaspect); public pointcut executeframework() : execution(* bank..*.*(..)) execution(bank..*.new(..)); public pointcut calledfromoutside() : executepublic() &&!cflowbelow(executeframework()); before() : calledfromoutside() { Signature sig = thisjoinpoint.getsignature(); String caller = getcaller(thread.currentthread().getstacktrace(), sig); log.info(caller + " calls " + sig);
https://www.flickr.com/photos/cadencrawford/8422302030/ Aufruf von außen (2) Webbrowser org.apache.jsp.index_jsp._jspservice(index_jsp.java:54) calls bank.konto(int) org.apache.jsp.index_jsp._jspservice(index_jsp.java:58) calls void bank.konto.einzahlen(double) org.apache.jsp.index_jsp._jspservice(index_jsp.java:60) calls double bank.konto.abfragen() org.apache.jsp.index_jsp._jspservice(index_jsp.java:54) calls bank.konto(int) org.apache.jsp.index_jsp._jspservice(index_jsp.java:58) calls void bank.konto.einzahlen(double) org.apache.jsp.index_jsp._jspservice(index_jsp.java:60) calls double bank.konto.abfragen() Blackbox System X Übersicht (Beispiel) DB-Host
Daten-Recorder (Objekt-Log aufzeichnen) after() returning(object ret) : sqlcall() { objlogger.log(thisjoinpoint, ret); https://www.flickr.com/photos/mattblaze/2695044170/
Daten-Recorder (Objekt-Log einspielen) Object around() : sqlcall() { Object logged = loganalyzer.getreturnvalue(thisjoinpoint); return logged; https://www.flickr.com/photos/mattblaze/2695044170/
Demo? http://www.flickr.com/photos/dhaun/4926434047
Ergebnis! zusätzliches Logging! Tests laufen ohne DB! Auslagerung von Code-Änderungen https://www.flickr.com/photos/maxbell/4008717429/
UMLGraph BankRepositoryTest 0:Account 1:Account BankRepository getbalance() 0 transfer(account 1, Account 0... transfer(200, Account 0) debit(200) deposit(200) getbalance() 200
4.0 Fazit Wir halten uns an den Standard.
https://www.flickr.com/photos/thepositiveaboutnegatives/8636477712/ Fazit! Dokumentation ist Teil des Problems! Source ist die einzig aktuelle Dokumentation! Einarbeiten heißt Ausprobieren! Testfälle = Problemfälle! zusätzliche Erkenntnisse durch AOP
AOP kann helfen! beim Logging! beim Capture & Replay! beim Zeit zurückdrehen! Trennung Code - Änderungen aber: AOP kann keine Tests ersetzen AOP ist kein Allheilmittel https://www.flickr.com/photos/engine_lover_2/6465986755/
Links & Literatur! Oliver Böhm Aspektorientierte Programmierung mit AspectJ 5 http://www.aosd.de/buecher/aop_aspectj/! Media-Streamer in Java ein Fallbeispiel mit AOP http://www.jugs.de/protokolle/2005-02-17/jmf.pdf! UMLGraph http://www.umlgraph.org/! websequence diagrams https://www.websequencediagrams.com/! ObjectRecorder, SequenceGrapher http://patterntesting.org/! Java aktuell
Fragen! 5.0 Fragen? Oliver Böhm (o.boehm@optica.de) http://oli.blogger.de/20150628/ http://patterntesting.org