Gabi und Sascha
Tags - Kategorien : Alle | Berlin | Bücher | Java | Linkhalde | Weichware | Verfassung

Für internationalisierte (I10N) Implementierungen verwende ich gerne das CAL10N API. Das API erreicht eine Compiler Assisted Localization durch den Einsatz von Java enums. Der Name des Enumerationsfeldes ist der Schlüssel in einer entsprechenden Properties Datei. Hierdurch wird der Schlüssel innerhalb des Java-Code nicht mehr als String hinterlegt. Durch ein Maven Plugin können die Properties-Dateien überprüft werden. Ich empfehle jedem Java Entwickler sich das API einmal anzuschauen.

Ich habe den Ansatz für den Einsatz in meinen privaten Projekten und bei bei Zimory erweitert. Durch den Einsatz von enums können auch Annotationen zum Einsatz kommen. Zwei Annotationen habe ich definiert. Eine für den enum Typen und eine für die enum Felder. Beide haben als einzigen Wert einen String:


    @Target(TYPE)
    @Retention(RUNTIME)
    public @interface SystemId {
        String value();
    }


    @Target(FIELD)
    @Retention(RUNTIME)
    public @interface MessageId {
        String value();
    }

@SystemId definiert grobgranular das Modul/Subsystem – oder wie auch immer die Systemunterteilung namentlich genannt wird – für die Messages. @MessageId definiert eine spezielle feingranulare ID für z.B. einen Fehlerzustand innerhalb eines Moduls. Der Sourcecode einer Message enum sieht dann in etwa so aus:


    import ch.qos.cal10n.LocaleData;
    import ch.qos.cal10n.Locale;
    import ch.qos.cal10n.BaseName;

    @SystemId("RT")
    @BaseName("messages")
    @LocaleData({@Locale("en")})
    public enum Messages {
        /** Indicates a login failure. */
        @MessageId("001001") LOGIN_VALIDATION_FAILED;
    }

Für die Auswertung haben ich einen eigenen MessageProducer geschrieben. Dieser kapselt eine Implementierung des CAL10Ns IMessageConveyor Interface. Ausserdem analyisert er per Reflection die Annotationen und baut aus den Werten eine ID zusammen. Diese ID wird vor die internationalisierte Nachricht gestellt. Daneben übernimmt die Implementierung noch einige Dinge wie Caching usw. Eine erzeugte Nachricht sieht in etwa wie die Folgende aus:

    RT-001001: Login failed for user "foobar".

Solche IDs sind nicht nur für die Analyse von Fehlermeldungen sinnvoll. Sie bieten auch einen einfachen Ansatz für die Fehlerpropagierung in Systemen, in denen bisher kein durchgängiges Exceptionframework existierte. Damit auch nicht Entwickler die Fehlermeldungen verstehen, haben ich eine Doclet-Implementierung geschrieben. Diese analyisert alle enum Klassen mit @SystemId und generiert aus dem Wert der Annotation, der Javadoc Klassendokumentation, dem Wert von @MessageId und der Javadoc Felddokumentation eine XML Datei mit einer Zusammenfassung der Daten. Durch einfache XSLT Skripte wird das XML Dokument in Docbook und Xdoc umgewandelt und kann somit für die Anwenderdokumentation weiter verarbeitet werden. Da alles aus einer Quelle kommt, werden Fehler durch cut 'n paste reduziert.

Voll reingelaufen. Priorität: low, no workaround. Und ich muss jetzt eine Lösung finden :-(

Money Quote:

Introspecting returns incorrect PropertyDescriptor for overriden getter in case when child getter has more specific return type. In this case PropertyDescriptor of parent class is returned instead.

Bis Java 1.6.0_18 kein Fix. In Java 7 (b80) gefixt. Leider kann ich mir dafür gar nichts kaufen.

Da denkst du dir ein elegantes REST API aus. CRUD auf PUT, POST, GET und DELETE abgebildet. Und dann sagt der Kunde dir, der Client basiert auf Flex. Und das Flex beim Kunden kann nur POST und GET.

Meine Einstellung zu Flex und dem ganzen anderen Dreck von Adobe, war noch nie positiv. Und sowas hebt nicht gerade meine Stimmung.

Für meinen Job bei Zimory habe ein wenig mit Weld SE gespielt. Weld ist die CDI Referenz­implementierung und Weld SE eine Anpassung für die Java SE Welt.

Die eigentliche Implementierung war recht einfach. Allerdings wurde beim Ausführen immer eine UnsatisfiedResolutionException geworfen. Die Nachricht war WELD-001308 Unable to resolve managed beans for…. Nach kurzer Suche war klar, dass Weld eine leere "META-INF/beans.xml" Datei benötigt. Nachdem die Datei angelegt war, funktionierte das Beispiel problemlos.

Es lässt sich streiten, ob die CDI Referenzdokument in Kapitel 12.1 eine solche Datei zwingend vorschreibt. Ich habe es dort nicht heraus gelesen.

Download: Sourcecode (7.897 Bytes)

javac scheint bei package Annotationen nicht zu überprüfen, ob die Annotationen den deklarierten Regeln folgen. Eben habe ich einer solchen Annotation den default Wert weggenommen. Die Verwendung auf type Ebene warf Compiler Fehler. Ist der Wert in der package-info.java Datei nicht vorhanden, läuft der compile Prozess ohne Probleme durch. Die falsche Verwendung auf package Ebene wurde durch nicht angepassten Unit-Test entdeckt. Eine IncompleteAnnotationException wird geworfen, wenn ich den Wert über das Reflection API auslese.

Vorher:


    @Documented
    @Retention(RUNTIME)
    @Target({PACKAGE, TYPE})
    public @interface CommandHolder {
        String value() default "";
    }

Nacher:


    @Documented
    @Retention(RUNTIME)
    @Target({PACKAGE, TYPE})
    public @interface CommandHolder {
        String value();
    }

Verhalten tritt auf mit javac 1.6.0_16 und javac 1.7.0-ea (b80) auf einem aktuellen AMD64 Ubuntu 9.10.

Vielleicht wühle ich mich später mal durch die Spezifikationen.

Ich implementiere gerade privat ein REST API. In dem API werden XML Daten mittels JAXB gewandelt. Dabei habe ich einfach POJOs verwendet und mit den JAXB Annotationen versehen. Eigentlich ganz einfach. Eigentlich… Bis zu dem Zeitpunkt an denen Collections ins Spiel kommen. Naiv wie ich war – he, wer liesst schon Spezifikationen – habe ich Collection Properties einfach annotiert. Und weil ich ein pfiffiger Entwickler bin, habe ich bei den Gettern eine leere Collection (Collections.emptyXyz()) zurück gegeben, wenn die Referenz null war. Ergebniss: unmarshall(…) warf eine UnsupportedOperationException. Das Problem: JAXB erwartet eine mutable Collection. Collections.emptyXyz() liefert aber immutable Objekte. JAXB ruft darauf dann clean() auf und füllt die Collection neu – die Refernzimplementierung mittels add(E). Eine null Referenz wird auch nicht akzeptiert und führt ebenfalls zu einer Ausnahme.

Ich habe mir dann doch mal die JAXB 2.2 Spezifikation von 2009-12-10 durchgelesen. Unter Punkt 5.5.2.2 wird das Verhalten spezifiziert. Mit einer Einschränkung: sie gilt nur für Collections vom Typ List. Die JAXB 2.2 Referenzimplementierung kommt aber auch mit Sets und dem Collection Interface selbst zurecht.

Der Code sieht jetzt so aus:


    @Valid
    @NotNull
    @Size(min=0, max=5)
    @OneToMany(fetch=EAGER)
    @XmlElement(name=ANSWER_XML_NAME)
    @XmlElementWrapper(name=POSSIBLE_ANSWERS_XML_NAME)
    public List<Answer> getPossibleAnswers() {
        if (this.possibleAnswers != null) {
            return this.possibleAnswers;
        }
        return new ArrayList();
    }

Kann man aktuell noch hier im zweiten Beitrag bewundern.

Nachtrag: Leider gibt es diese vollkommen bescheuerte Regelung in diesem Land, dass öffenlich rechtliche Sender ihre selbst produzierten Sendungen nach 7 Tagen nicht mehr online anbieten dürfen. Deswegen ist der Film jetzt weg.

Dieser Inhalt wurde aus einer weiteren Quelle zusammengefügt. Mehr...

Für kleine Diagramme muss es nicht immer ein ausgereiftes UML Tool sein. Mit websequencediagrams können kleine Dinge auch schnell geskribelt werden. Die Sprache ist schnell erlernbar, die Ergebnisse ausreichend, wenn nicht gerade Codegenerierung oder gar Round-Trip-Engineering benötigt wird.

Mit yUML können auch Klassen- Aktivitäten und Use-Case Diagramme erstellt werden.

Ein kurz aufleuchtender Star am Suchsystemhimmel ist verglüht. Heute wird der letzte siechende Tag im Leben der Vionto GmbH (AZ: 36v IN 4850/09, Amtsgericht Charlottenburg) sein. Es folgt der unrühmliche Tod durch Insolvenz. Innerhalb eines Jahres aufgestiegen und dann jäh abgestürzt. Diesmal bleibt nichts übrig. Götterdämmerung.

Preise hatte Vionto letztes Jahr einige gewonnen: SuMa-Award, Red Herring Europe Top 100 2009 Award, den eco Internet Award und noch einige mehr. Es hat nichts genützt. Ideen – technisch hervorragend umgesetzt – konnten oder wollten nicht in Geld umwandelt werden. War das Fundament zu wackelig, ohne Substanz, gepaart mit Unvermögen und Arroganz? Eine Mischung wird es gewesen sein. Der Tod, er war schon im Frühjahr 2009 absehbar. Da war die Vionto gerade einmal 5 Monate alt. Entstanden aus den wirtschaftlichen Trümmern der semgine GmbH (AZ: 36s IN 4162/08, Amtsgericht Charlottenburg). Alte Mannschaft, neue Investoren und in der Führung ein Neuer: Ralf von Grafenstein. Nach kurzer Zeit war auch wieder der ehemalige semgine Geschäftsführer mit an Bord: Dr. Martin Christian Hirsch – als Geschäftsführer.

Zum Ende der semgine möchte ich nicht viel schreiben. Ich war als Mitarbeiter involviert. Nur soviel: der Eyeplorer, das System auf dem die Vionto basiert, wurde in den letzten Monaten der semgine entwickelt. Er sollte als Neuanfang dienen und neue Investoren anfixen. Die alten Investoren waren verbrannt.

Ich konnte das kurze aufblühen und verglühen der Vionto aus naher Distanz beobachten. Ich habe mitbekommen, wie die Ergebnisse des Eyeplorers nicht wirklich besser wurden, aber immer neue Funktionen hinzu kamen. Funktionen, die mit Suche nichts zu tun haben. Bei 13.000 Anfragen am Tag wurde ein Tool zur Ergebnissverwaltung für angemeldete Benutzer aufgebaut. Es wird sogut wie nie benutzt. Das Produktmanagement wollte es nicht wirklich. Die Entwickler sahen keinen grossen Sinn darin. Trotzdem ist es da.

Ich habe mitbekommen, wie Mitte 2009 erste Unruhe aufkam. Wie Kurzarbeit angemeldet wurde für ein Unternehmen, welches praktisch keine Kunden hatte und nur durch sein Portal bekannt war. Dem aussen stehenden Betrachter stellte sich sofort die Frage: und wer entwickelt jetzt das Portal weiter? Die Kurzarbeit war nach knapp einer Woche wieder vorbei – auch weil niemand da war als Besuch im Haus herum geführt wurde. Kurz nach der Kurzarbeit drei Mitarbeiter entlassen: zwei Entwickler und ein SysAdmin. Es blieben zwei Geschäftsführer, zwei bis drei Produktmanager (so genau habe ich das nie durchschaut), eine Sekretärin, ein Admin, vier Entwickler und einige Praktikanten.

Die Entlassungen waren dann wohl der berühmte Tropfen. Schon zur Zeit der Kurzarbeit suchten zwei Entwickler aktiv nach einem neuen Job – nicht die später Entlassenen. Nach den Entlassungen waren es dann drei. Mitarbeiter haben ein gutes Gespür und sind bei einer Insolvenz meistens bereit dem Unternehmen zu helfen. Trotzdem gibt es immer wieder Eintagesurlaube, mitten in der Woche :-) Als die Vionto Insolvenz anmeldete gab es diesmal kein Halten mehr. Das Team brach in kurzer Zeit auseinander. Das endgültige Ende eines kleinen Softwareunternehmens.

Die Ruinen sind heute noch unter der Eyeplorer-Domain zu bewundern. Sehr SEO lastig. Ich verlinke nicht, weil ich nicht weiss wie lange die Domain noch existiert. Die rauchenden Trümmer basieren auf einer komplexen Technologie. Mehrere 100.000 Zeilen Quelltext für die heute kein Entwickler mehr zuständig ist der sich auskennt. Der Quellcode ist damit so gut wie wertlos. Trotzdem will Dr. Martin C. Hirsch wohl erneut weiter machen – mit dem Google-Herausforderer.

Stay tuned.

Wem JAD nicht mehr genügt, weil er nur bis Java 1.4 sinnvoll decompiliert (kein Generics Support), mag sich JD anschauen. Kein Problem mit inneren Klassen, synthetischen oder Brigde-Methoden/Typen. Annotationen werden aufgelöst und enum Typen decompiliert. Der erzeugte Quellcode ist gut lesbar - ist ja der kniffelige Part bei Decompilern. Wird bei mir JAD ablösen.

Und ich frage mich, warum die Decompiler Jungs immer C++ verwenden.

Ach herrje. Es gipfelt mal wieder: IT-Gipfel. Die üblichen Verdächtigen.

Stolz wird ein konkreter Theseus Output präsentiert – endlich einmal. Wieviel Steuermillionen sind dafür versenkt worden? Aus eigener Erfahrung mag ich gar nicht daran denken, was damit alles quersubventioniert wurde. Und sowas wird als Leuchturmprojekt dargestellt.

Und dann natürlich die glorreiche Idee verseuchte Rechner mittels Netzwerkdatenanalyse zu identifizieren. Das ist nicht nur ein echter Brüller. Es zeigt auch, wie sich Politik und die ihr ergebenen Lobbyverbände die Zukunft der vernetzen Gesellschaft vorstellen: ähnlich wie die unsägliche Sperrdebatte – oberflächlich schauen und dabei die Freiheit mit Füssen treten. Botnetze arbeiten im Verborgenen. Bots nisten sich auf Rechnern ein und versuchen nicht entdeckt zu werden. Aktuell mögen sie vielleicht etwas offen kommunizieren. Was wird aber passieren, wenn durch eine wie auch immer geartete totale Analyse des gesamten Netzverkehrs durch Provider, dieser Datenverkehr bekämpft werden soll? Richtig: die Kommunikation wird ⒜ verschleiert und die Kommunikation wird ⒝ über Overlaynetzwerke abgewickelt. Mit dem Ergebniss: die alten und schwachen werden gefunden und der Benutzer wiegt sich in trügerischer Sicherheit. Selbstverständlich geht es auch um Sanktionen. Der Benutzer soll, so er nicht freiwillig mitmacht, gezwungen werden. Menschen überzeugen? Nicht doch. Zwang ist überhaupt wohl das Einzige, was in diesem Land verstanden wird. Was bei mir wiederum die Frage aufkommen lässt: wer haftet wenn mal was nicht so hinhaut wie es soll? Daten unwiderbringlich verloren sind? Die ISPs?

Es scheint sich aber ein Trend abzuzeichnen: Provider und ISPs werden stärker eingebunden in die totale Überwachung des Datenverkehrs. Provider und ISPs müssen heute schon die Daten für die Vorratsdatenspeicherung sammeln, in Frankreich und Großbritannien sind sie der verlängerte Arm der Contentindustrie (Stichwort: Three-Strikes-Out). Der Provider und ISP: mein Blockwart.

Und unser neuer Innenminister? Thomas de Maizière gibt sich scheinbar selbstkritisch wenn er sagt dass der Staat seine Bürger mit einem Generalverdacht belegt hat. Seine Aufgabe sei es diese Kluft zu überwinden. Scheinbar kein Wort darüber, die Gesetze, in denen dieser Generalverdacht mündet, zu überarbeiten und abzuschaffen. Stattdessen solle ein Dialog des Vertrauens geschaffen werden. Wie immer also: reden und weitermachen wie bisher – darüber etwas nettere Polit-PR giessen.

Einzige Hoffnung: bisher haben diese IT-Gipfel heisse Luft produziert.

Manchmal muss es ein grober Klotz sein. Ein Klasse die ich entwickelt hatte, hatte eine bestimmte Signatur. Nix wildes, beispielsweise war die Klasse final. Wenn eine Klasse final ist, muss ich mich nicht um die Probleme kümmern, die Vererbung mit sich bringen kann. Das final war plötzlich verschwunden. Grund: in einem Test wurde eine abgeleitete Version benötigt. Leider wurde nur das final entfernt. Die Klasse aber nicht hinsichtlich Vererbung angepasst. Z.B. habe ich in der equals Methode noch den instanceof Operator verwendet. Geht bei final Klassen. Bei Klassen, die nicht final sind ist das grob fahrlässig.

Ich habe den Test umgeschrieben – es geht auch einfach ohne Vererbung mit nur einer Zeile Code mehr und dann die Tests erweitert. Bisher habe ich immer nur die Erzeugung eines Exemplars über den Konstruktor getestet. Jetzt teste ich auch die Signatur. Den Test habe ich mit einem Kommentar versehen. Hoffentlich hilft es.


    @Test
    public void creation() {
        // If you must change these tests go into yourself and check:
        // are the changes are really needed?
        new Notifier();

        final Constructor[] cons = Notifier.class.getDeclaredConstructors();
        assertThat(cons.length, is(equalTo(1)));
        assertThat(Modifier.isPublic(cons[0].getModifiers()), is(equalTo(true)));

        final int modifiers = Notifier.class.getModifiers();
        assertThat(Modifier.isPublic(modifiers), is(equalTo(false)));
        // Implementation safe for inheritance?
        assertThat(Modifier.isFinal(modifiers), is(equalTo(true)));
    }

Vorher sah der Test so aus:


    @Test
    public void creation() {
        new Notifier();
    }

  • Cost cutter - süchtig machender Tetris Clone.
    via Petronella
  • Weiss gar nicht wieso sich die Sozialverbände und -anbieter so über die geplante Reduzierung der Wehrdienstzeit aufregen. Zivis sollen keine Arbeitsplätze wegnehmen dürfen, also nur Jobs machen, auf die verzichtet werden kann. Wie schlimm steht es eigentlich ums Pflegesystem?
  • Android Icons für die Entwicklung unter Creative Commons Attribution Share Alike Lizenz.
  • Some Java Concurrency Tips

Auf http://code.google.com/p/sportics-j2me habe ich die Applikation, die beim Frankfurter Helbmarathon gelaufen ist, hochgeladen. Der Code ist unter der GPL 3 freigegeben. Die Version 1.0 ist mit dem Nokia N79 und N85 getestet worden und lief 5 Stunden stabil. Dann war der Akku leer :-)

Passwort-Safes sind so eine Sache. Grundsätzlich darf man ihnen nicht vetrauen. Vielleicht wenn sie Open Source sind und auf Standard Crypto aufsetzen. Darauf verlassen sollte man sich trotzdem niemals. Trotzdem verwende ich einen – selbstgeschriebenen.

Was aber soll von einer derartigen Android Applikation gehalten werden, die uneingeschränkten Netzwerkzugriff verlangt?

Seit heute wegen HTC Hero wieder Eclipse.

Finden sich hier und sind sicherlich ein spannende Lektüre für zwischendurch – auch wenn solche Dinge wie Speed kills allgemeine Weisheiten sind. Nur vergessen wir sie halt häufig, wenn Projektmanager mal wieder fragen, warum etwas so lange dauert. Fragen sind überhaupt die Waffe der Projektmanager. Wer fragt muss sich nicht rechtfertigen. Der Gefragte muss sich rechtfertigen. Deswegen ist es auch immer eine gute Idee als Entwickler den Spiess umzudrehen. Beispielsweise: Wieso habe ich nicht genug Zeit es ordentlich zu machen? Leider steht sowas nicht in der Liste.

Dense code is dense code.

Nein, nix über Snow Leopard. Nur die Bestätigung das Max Recht hat. Mac OS X wird immer mehr zu Windows: jedes Popelupdate erfordert einen Neustart. Heute ein lächerliches 161 MB Java-Update. Wieso erfordert ein Java-Update einen Neustart? Das versteht vermutlich nur Apple.

Im just on the trip to simplify some aspects of software development thru bytecode extendsion. In «Loggen vereinfachen» (german) I've written down some thought about simplify logging.

Today I read a blog entry from Kirk Pepperdine on the subject. The tipp is trivial. Kirk suggests that before a logcall a condition checks whether the call is at all meaningful. The approach makes sense, but has a nasty side effect: it bloats the code in such a way that the actual business logic between the log blocks will eventually go away.

One solution may be to examine the generated bytecode. If there is a log call in the code, it can be automatically surrounded with such a if statement.

Advantage: The developer can continue to write simple log calls without bloat the code.
Disadvantage: It does not look right, a tool that manipulates its code. An he needs the tool.

What prevails? Advantage or disadvantage? In my opinion, the advantage of cleaner code.

As well as some Java developers read along I would be interested what you think.