Saturday, 7. January 2017
PatternTesting 1.7 released

Most changes of PatternTesting are under the hood: switch to Java 7, switch to Log4J-2 as logging framework and better exception handling in FileTester - if a file cannot be found, it is checked if it can be a case sensitive issue. This happens often if the build runs on a Linux server with case sensitive filenames.

A bigger change was the implementation of feature request 49. You will now be warned if you forget a commit after an database insert or update (see also blog entry from September).

Another change was the split of the ClasspathMonitor into ClasspathMonitor and ResourcepathMonitor. For more info about the ClasspathMonitor see the blog of August 2009.

... link (0 Kommentare)   ... comment


Monday, 2. January 2017
Happy New Year 2017
“Ich kann freilich nicht sagen, ob es besser wird, wenn es anders wird, aber soviel kann ich sagen: Es muss anders werden, wenn es gut werden soll.”
(Georg Christoph Lichtenberg)

... link (0 Kommentare)   ... comment


Friday, 23. September 2016
JDBC: Don't Forget to Commit
If you want to save something in a database with pure JDBC you would normally
  1. take a connection,
  2. create a statement with it,
  3. execute the statement and
  4. close the connection.
Have I something forgotten? Don't know - so lets try it. Point 1 could be done by asking the Driver class, a connection pool or another kind of provider:
Connection connection = connectionProvider.getConnection();
With this connection you can call a method which uses this connection to save e.g. an address:
private static void save(Address address,
        Connection connection) throws SQLException {
    PreparedStatement stmt = connection.prepareStatement(
            "INSERT INTO addressbook (email, name, "
            + "city) VALUES (?, ?, ?)");
    try {
        stmt.setString(1, address.getEmail());
        stmt.setString(2, address.getName());
        stmt.setString(3, address.getCity());
        int rc = stmt.executeUpdate();
        if (rc < 1) {
            throw new SQLWarning("cannot save " + address);
        }
    } finally {
        stmt.close();
    }
}
As last point you close the connection in the calling method:
connection.close();
Does it work? In most cases yes, because normally the auto-commit flag is on, if you get a connection. But what happens, if auto-commit is off?

Auto-Commit Off = Lost Data

If auto-commit for a connecion is off you must call excplicit the commit:
connection.commit();
If you don't do it your changes are lost (there are some exeptions from that rule - the Oracle DB does a commit before it closes the connection).

The problem with this "forgotten" commit is, that no warning or exceptions comes up and you do not notice the lost data. This makes it hard to find the error - especially if the auto-commit is off only in same special cases.

The PatternTesting Proxy-Driver

PatternTesting provides you a wrapper around the original driver which allows you to log SQL statements but which warns you also if you forgot the commit statement for a connection with auto-commit off:

1 entries were updated with 'INSERT INTO addressbook (email, name, city) VALUES ('ob@aosd.de', 'Oli B.', 'nowhere')' but not committed.

This is the message you will see in this case. You only have to change the JDBC-URL and put ":proxy" after the jdbc prefix:
DriverManager.getConnection("jdbc:proxy:hsqldb:mem:testdb")
This is the URL for an HSQL memory DB. For more information see the Wiki article about SQL Logging and Monitoring.

Happy Debugging...

... link (0 Kommentare)   ... comment


Thursday, 5. May 2016
Update auf Sonar 5.5 (Ubuntu 14.04)
Nach einem Udpate von SonarQube 5.4 auf 5.5 war mein Sonar-Server nicht mehr erreichbar. Was war passiert? Die Auswertung des Log-Files brachte folgende Zeile zu Tage:
    Unsupported mysql version: 5.5. 
    Minimal supported version is 5.6.
Dummerweise ist bei Ubuntu 14.04 LTS MySQL 5.5 die Default-Einstellung. Glücklicherweise läßt sich aber mit
    apt-get install mysql-server-5.6
MySQL 5.6 als Default einstellen - damit gab sich SonarQube zufrieden und verweigerte nicht länger seinen Dienst.

... link (0 Kommentare)   ... comment


Wednesday, 24. February 2016
First Law of Software Archaeology
Do you know that? You have to maintain some old programs and you are wondering what the hell is that piece of code doing. Why does it work? And where is the architecture of that damn software system you should adapt for the future?

Welcome to the world of software archaeology, also known as legacy code. The first law of software archaeology from Mitch Rosenberg (see Wikipedia) gives you good feeling about the trouble in digging in old rotten code:
Everything that is there is there for a reason, and there are 3 possible reasons:
  1. It used to need to be there but no longer does
  2. It never needed to be there and the person that wrote the code had no clue
  3. It still needs to be there and YOU have no clue
The corollary to this "law" is that, until you know which was the reason, you should not modify the code (or data).
And if you would like to learn some ancient language of the beginning of the computer stone age watch this video:

... link (0 Kommentare)   ... comment


Saturday, 20. February 2016
Datenschutz und Meinungsäußerung
Edward Snowdon:
"Zu sagen, man kümmere sich nicht um Datenschutz, weil man nichts zu verbergen habe, ist genauso, wie zu sagen, man kümmere sich nicht um das Recht auf freie Meinungsäußerung, weil man nichts zu sagen hat."

... link (0 Kommentare)   ... comment


Monday, 8. February 2016
gdv.xport 1.1
Nach Version 1.0 im letzten Jahr wurde dieses Wochenende die Version 1.1 ausgeliefert. Die Änderungen sind eher interner Natur (kleinere Refactorings bzw. Umbauten) und Rückmeldungen aus einigen Tests. So fehlten in der XML-Beschreibung einige Felder, die mit 1.1.0 über die Resouce "fehlendeFelder.xml" mitgeliefert werden (s.a. TeildatensatzXml).

... link (0 Kommentare)   ... comment


Friday, 8. January 2016
PatternTesting 1.6 released
PatternTesting 1.6 no longer supports Java 5 - you now need at least Java 6 if you want to use PatternTesting. On the other side the classloader of Tomcat 8 is now directy supported by the ClasspathMonitor.

Some deprecated classes and methods were removed now. And some tester were extended: the FileTester prints now the filename for files which differs (see feature request 47) and allows you to add a StringConverter as argument. This allows you e.g. to ignore white spaces or upper case letters.

The ClassTester checks now also static initializers to find dependency problems to other classes during the startup phase of a class.

... link (0 Kommentare)   ... comment


Friday, 1. January 2016
Happy New Year 2016
“Es gibt bereits alle guten Vorsätze, wir brauchen sie nur noch anzuwenden.”
(Blaise Pascal)

... link (0 Kommentare)   ... comment


Thursday, 24. December 2015
Advent, Advent
Die Adventszeit ist eine Zeit, in der man Zeit hat, darüber nachzudenken, wofür es sich lohnt, sich Zeit zu nehmen.

(Gudrun Kropp)

... link (0 Kommentare)   ... comment


Thursday, 19. November 2015
20 Jahre Java - und nun?
Bereits 2012 hatten wir bei der Java User Group Stuttgart uns einen Rückblick auf 20 Jahre Java gegönnt - reichen doch die Ursprünge von Java bis 1992 zurück. Inzwischen ist Java Mainstream geworden und entwickelt sich immer mehr zum COBOL der Neuzeit.

Von Entwicklung kann derzeit eigentlich kaum noch die Rede sein - man orakelt, dass hinter den Kulissen viele aktive Entwickler abgezogen wurden und viele Bereiche in der JDK- und JEE-Entwicklung jetzt brach liegen. Die spannenden Themen wie Mobile und IoT finden zunehmend woanders statt.

Aber auch wenn es in der Java-Szene kräftig rumort und einstige Zugpferde wie James Gosling oder Erich Gamma fehlen, so ist es an den meisten Universitäten die erste Wahl für objekt-orientierte Programmiersprachen. Und dies lässt hoffen für die Zukunft, dass sich Java trotz der derzeitigen Durststrecke weiterentwickeln und weiterhin für eine offen Welt stehen wird.

... link (0 Kommentare)   ... comment


Thursday, 3. September 2015
SW-Archäologie in Java aktuell
Es ist soweit - die Artikel-Serie über Software Archäologie, die auch Thema auf dem Java Forum Stuttgart 2015 war, ist jetzt im aktuellen Heft von Java aktuell zu lesen.

Wer meint, dass Altlasten (neudeutsch: Legacy) langweilig und nur etwas für zurückgebliebenen Entwickler ist, der irrt: zum einen ist Code spätestens nach 3 Monaten bereits Legacy Code (oftmals schon früher), zum anderen kann alter Code eine jede Menge erzählen: verschiedenen Firmen-Fusionen und Umbenennungen können an der Package-Struktur abgelesen werden, die Outsourcing- oder indische Area hat tiefe Spuren im Code hinterlassen, oder man entdeckt immer wieder neue Anti-Pattern, die man vorher nicht kannte.
Guter Code ist langweiliger Code!
Dies gilt auch für Legacy-Systeme. Ich kann Ihnen versichern, dass jede Menge interessanten Code in Altsystemen steckt ;-)

Die Zukunft war früher auch besser.
(Karl Valentin)

... link (0 Kommentare)   ... comment


Sunday, 12. July 2015
SW-Archäologie mit AspectJ (4)
3. Unterstützung durch AOP

4. Ausblick

Don't patch bad code - rewrite it.
The Elements of Programming Style
Der Aufwand, sich in unbekanntem Code einzuarbeiten, wird häufig unterschätzt. Langfristig ist es meist wirtschaftlicher, vorhandenen Code komplett neu zu entwickeln, wenn die Dokumentation veraltet ist, der Code an vielen Stellen ausgewuchert ist und auch die Testfälle nicht vorhanden oder von zweifelhafter Qualität sind.

Oftmals hat man aber keine andere Wahl, als auf den bestehenden Code aufzusetzen, weil er die einzig gültige Quelle der Dokumentation darstellt. Und hier bietet die Aspektorientierung eine Vielzahl von Möglichkeiten, um
  • zusätzliche Log-Möglichkeiten einzubauen,
  • Sequenz-Diagramme zu generieren,
  • Schnittstellen zu überwachen,
  • Objekt-Recorder zu implementieren und
  • implantieren,
  • die aufgenommenen Objekte wieder einzuspielen,
  • u.v.m.
Daraus lassen sich weitere Testfälle schreiben und neue Erkenntnisse gewinnen, um Refactoring-Maßnahmen einzuleiten oder sich für eine Neuentwicklung zu entschließen. Allerdings entbindet auch AOP nicht von der Aufgabe, bestehenden und neuen Code so zu gestalten und umzuformen, dass künftige Generationen damit glücklich werden.

... link (0 Kommentare)   ... comment


Saturday, 11. July 2015
SW-Archäologie mit AspectJ (3)
2. Abstecher in die Welt von AOP

3. Unterstützung durch AOP

Nach diesem Ausflug in die wunderbare Welt der Aspekte, die uns einen kleinen Einblick in die Denkweise ermöglichte, wenden wir uns wieder unserem Fundstück aus der Steinzeit des Java-Zeitalters zu. Der größte Manko bei Altanwendungen (und nicht nur dort) sind die Testfälle. Meistens fehlen sie oder sind genauso veraltet wie die Dokumentation. Ist die Anwendung noch in Betrieb, kann man versuchen, daraus Testfälle für die weitere Entwicklung abzuleiten. Und genau hier kann AOP helfen, fehlende Log-Informationen zu ergänzen oder die Kommunikation mit der Umgebung aufzuzeichnen.

3.1. Schnittstellen beobachten

Die interessanten Stellen sind vor allem die Schnittstellen zur Außenwelt. Bei J2EE-Applikationen sind dies meist andere Systeme wie Legacy-Anwendungen oder Datenbanken, die über das Netzwerk angebunden werden. Hier reicht es oft aus, die Anwendung ohne Netzwerkverbindung zu starten und zu beobachten, wo überall Exceptions auftreten:

java.net.SocketException: java.net.ConnectException: Connection refused
    at com.mysql.jdbc.StandardSocketFactory.connect(StandardSocketFactory.java:156)
    at com.mysql.jdbc.MysqlIO.(MysqlIO.java:283)
    at com.mysql.jdbc.Connection.createNewIO(Connection.java:2541)
    at com.mysql.jdbc.Connection.(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)
    …
Aus dieser Exception kann man erkennen, dass die Anwendung auf eine MySQL-Datenbank zugreift, aber kein Connection-Objekt vom DriverManager bekam. Mit diesem Wissen kann man sich alle Connection-Aufrufe genauer unter die Lupe nehmen:

after() returning(Object ret) : 
         call(* java.sql.Connection.*(..)) {
    log.debug(getAsString(thisJoinPoint) + " = " + ret);
}
Mit dieser Anweisung wird am Ende jedes Connection-Aufrufs der Aufruf selbst mitsamt seinen Parametern (z.B. SELECT-Statements) und Rückgabewert ausgegeben (über die getAsString()-Methode, hier nicht abgebildet). Ähnlich kann man bei Netz- bzw. Socket-Verbindungen verfahren: man erweitert die Stellen (im AOP-Jargon „Joinpoints“ genannt), über die Daten ausgetauscht werden.

Handelt es sich um eine interne Bibliothek oder Framework, das es zu betrachten gilt, sind vor allem die öffentlichen Schnittstellen von Interesse. Hier kann man mit Aspektorientierten Sprachmitteln all die Methodenaufrufe ermitteln, die tatsächlich von außerhalb aufgerufen werden – denn oft sind nicht alle Methoden, die als „public'“ deklariert sind, für den Aufruf von außen vorgesehen.

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);
}
Hier werden alle Methoden eines Bank-Frameworks (bank-Package) überwacht. Nur wenn der Aufruf nicht von innerhalb kam (!cflowbelow), wird vor der Ausführung der Methode oder Konstruktor der Aufrufer anhand des Stacktraces ermittelt (Methode getCaller(), hier nicht aufgelistet).

...
jsp.index_jsp._jspService(index_jsp.java:54) calls bank.Konto(int)
jsp.index_jsp._jspService(index_jsp.java:58) calls void bank.Konto.einzahlen(double)
jsp.index_jsp._jspService(index_jsp.java:60) calls double bank.Konto.abfragen()
...
Dies ist die Ausgabe, die den Aufruf aus einer JSP zeigt. Lässt man die Anwendung lang genug laufen, erhält man so alle Methoden, die von außerhalb aufgerufen werden.
3.1.1 Daten aufnehmen
Mit Java ist es relativ einfach möglich, Objekte abzuspeichern und wieder einzulesen. Damit lässt sich ein einfacher Objekt-Recorder bauen, um damit die Schnittstellen-Daten aufzunehmen:

after() returning(Object ret) : sqlCall() {
    objLogger.log(thisJoinPoint);
    objLogger.log(ret);
}
Hinter thisJoinPoint verbirgt sich der Kontext der Aufrufstelle, die der AspectJ-Compiler (eine AO-Sprache, die auf Java aufbaut, s.a. [1]) als Objekt bereitstellt.
3.1.2 Aufnahmedaten einspielen
Wenn man die notwendigen Schnittstellen-Daten gesammelt hat, kann man anhand dieser Daten einen (einfachen) Simulator bauen. Man kennt die Punkte, über die diese Daten hereingekommen sind, man muss jetzt lediglich an diesen Punkte die aufgezeichneten Daten wieder einspielen:

Object around() : sqlCall() {
    Object logged = logAnalyzer.getReturnValue(thisJoinPoint);
    return logged;
}
Hat man so die Anwendung von der Aussenwelt isoliert und durch Daten aus früheren Läufen simuliert, kann man das dynamische Verhalten der Anwendung genauer untersuchen. So kann man weitere Aspekte hinzufügen, die automatisch Sequenz-Diagramme erzeugen oder wichtige Programmzweige visualisieren (z.B. mit Hilfe der UMLGraph-Bibliothek). Damit erhält man neben der statischen Sicht durch Klassen-Diagrammen (die sich notfalls mittels Reverse-Engineering wiedergewinnen lassen) auch eine Visualisierung des dynamischen Verhaltens.

3.2. Code-Änderungen

Nach diesen Vorbereitungen kann mit den ersten Code-Änderungen (Refactorings) begonnen werden. Soll der Original-Code (noch) unverändert bleiben (was bei unbekannter Abdeckungen von vorhandenen Testfällen sinnvoll sein kann), liefert die Aspektorientierung die Möglichkeit, den Code getrennt vom Original abzulegen. Man kann sogar verschiedene Varianten einer Komponente vorhalten und diese während der Laufzeit austauschen. Auf diese Weise kann man experimentell verschiedene Varianten und Code-Manipulationen ausprobieren, um deren Verhalten auf die Gesamt-Anwendung studieren zu können.

4. Ausblick

... link (0 Kommentare)   ... comment