Gastbeitrag: SQL als "interne DSL" in Java mit jOOQ

Vor einiger Zeit hat Christian auf seinem Blog das fluent API seiner jRTF-Library vorgestellt, welche dem Benutzer ermöglicht, RTF-Dokumente mit einfachen Sprach-Konstrukten direkt mit Java zu erstellen:

DSL (Domain Specific Languages) sind ein spannendes Thema in vielen Bereichen. Für die meisten Zwecke werden sogenannte "externe" DSL’s definiert, also für einen technischen oder fachlichen Bereich spezialisierte Sprachen, welche unabhängig von anderen Sprachen interpretiert oder kompiliert werden. Manchmal gelingt es aber auch, solche spezialisierten Sprachen in einer anderen Sprache zu "internalisieren", wie dies eben mit jRTF gelungen ist. Heute möchte ich eine ähnliche DSL präsentieren, welche ich in jOOQ (Java Object Oriented Querying) eingebaut habe. jOOQ bildet SQL als "interne DSL" in Java ab, so dass Datenbank-Abfragen direkt in Java formuliert werden können. Ein Beispiel:

// Suche alle Bücher, welche in 2011 publiziert wurden
create.select()
      .from(BOOK)
      .where(PUBLISHED_IN.equal(2011))
      .orderBy(TITLE)
      .fetch();

Dabei steht BOOK für eine Tabelle mit den Feldern PUBLISHED_IN und TITLE. Alle diese Objekte werden von jOOQ generiert.

Weiterlesen

Gastbeiträge sind willkommen

Wer Lust hat, etwas spannendes auf dem Java-Insel-Blog zu veröffentlichen (einmalig oder mehrmalig), kann sich gerne bei mir melden. Die Themen sollten sich natürlich um Java im weitesten Sinne drehen, also nicht, wie man den besten Mochito mixt, oder den Opa vom Schnarchen abhält. Für Leser sind Gastbeiträge etwas feines, denn so bekommt der Blog etwas andere Themen und neue Blickwinkel. Schreiber wiederum können ein relativ großes Publikum erreichen und so spannenden Projekte oder Lösungen vorstellen.

enum für Singleton nutzen

Ein Singleton ist ein Objekt, was es in der Applikation nur einmal gibt.[1] Javas enum ist dafür perfekt geeignet, denn die Aufzählungsobjekte gibt es in der Tat nur einmal und die Bibliothek implementiert einige Tricks, um das Objekt auch möglichst nur einmal zu erzeugen, etwa dann wenn die Aufzählung serialisiert über die Leitung geht.

Ein Beispiel dazu. Ein enum MainFrame soll genau eine Konstante INSTANCE deklarieren. Da enum-Typen Attribute deklarieren können, soll unser MainFrame eine Objektvariable JFrame bekommen. Das bedeutet dann, dass mit dem Exemplar INSTANCE ein Swing-Fenster assoziiert ist. Das es nur ein Aufzählungselement in der enum gibt, kann auch nur ein JFrame-Exemplar gebildet werden:

public enum MainFrame

{

INSTANCE;

private JFrame f = new JFrame();

public JFrame getFrame()

{

  return f;

}

}

Damit ist INSTANCE ein Exemplar vom Typ MainFrame und hat ein privates Attribut und eine öffentliche Zugriffsmethode. Da es nur eine Konstante gibt, gibt es auch nur ein Fenster. Eine Anwendung sieht etwa so aus:

com/tutego/insel/enumeration/MainFrameDemo.java, main()

MainFrame.INSTANCE.getFrame().setTitle( "Singleton" );

MainFrame.INSTANCE.getFrame().setBounds( 100, 100, 300, 400 );

MainFrame.INSTANCE.getFrame().setVisible( true );

Aus jedem Teil der Anwendung ist MainFrame.INSTANCE zugänglich und repräsentiert dieses eine Exemplar. Auch kann dieses Exemplar übergeben werden, weil es ein Objekt ist, wie jedes andere auch.


[1] Pro Klassenlader, um das etwas genauer auszudrücken.

Diverse Google-APIs werden dichtgemacht, Translate gehört dazu

In den kommen drei Jahren sollen laut http://googlecode.blogspot.com/2011/05/spring-cleaning-for-some-of-our-apis.html eine Reihe von APIs dichtgemacht werden:

Das alles fand ich nicht so tragisch, aber Translate ist heftig in der Diskussion, und Google wird das wohl noch einmal überdenken müssen. Die Google-Antwort (bisher) darauf:

This was a tough decision for us to make; we’re sorry to hear that it’s been a tough one for you to read. Thank you all for your comments, and for reminding us of the passion and energy that you bring to building great products that use our APIs. We launch a lot of APIs, many of them experimental or in Labs. This round of spring cleaning is designed to let us do a better job by focusing more effort on fewer APIs, so that you can continue to count on them. Deprecating the Translate API was the hardest choice for us to make — we’re excited about the global web, and about helping developers and webmasters anywhere reach audiences everywhere. We continue to invest in our Translate offerings, including the Google Translate web element. But the Translate API was subject to extensive abuse — the vast majority of usage was in clear violation of our terms. The painful part of turning off this API is that we recognize it affects some legitimate usage as well, and we’re sorry about that; we hope that our other offerings will cover many of those legitimate use cases.
We are listening, and we really appreciate your thoughtful responses to this post.

Nicht weiter gepflegt werden weiterhin:

Dafür kommen neue APIs dazu:

In 4 Tagen nach der Ankündigung beschäftigen sich über 150 Kommentare mit den Endscheidungen. Ein Kommentar dazu bringt es vielleicht auf den Punkt: “Your new APIs are either pure bullshit or specially aimed to promote your own affiliates.”

Eine Übersicht aller Google-APIs gibt http://code.google.com/intl/de-DE/more/.

Twitter steigt auf Java um

Das führt zu einer deutlichen Performance-Verbesserung und Hardware kann wieder abgebaut werden. Weiterhin werden Entwickler langsame Programme schreiben können (was ebenfalls in allen anderen Programmiersprachen gelingt), aber zumindest zeigt Twitter (neben so hoch skalierten Systemen wie eBay oder Facebook), dass Java grundsätzlich eine exzellente Performance bietet. Ein paar Details unter http://engineering.twitter.com/2011/04/twitter-search-is-now-3x-faster_1656.html. Die Kernbausteine der Lösung (Blender genannt) sind Apache Thrift, Apache Lucene und JBoss Netty.

Die JavaMail API (Teil 2)

Steht die Verbindung zum Server, kann der Client eine Mailbox öffnen. Wir deklarieren dazu eine openPop3InboxReadOnly() und closeInbox() Methode.

com/tutego/insel/mail/MailUtils.java, Teil 2

public static Folder openPop3InboxReadOnly( Session session )

throws MessagingException

{

Store store = session.getStore( "pop3" );

store.connect();

Folder folder = store.getFolder( "INBOX" );

folder.open( Folder.READ_ONLY );

return folder;

}

public static void closeInbox( Folder folder ) throws MessagingException

{

folder.close( false );

folder.getStore().close();

}

Die Rückgabe von openPop3InboxRealOnly() ist ein Folder-Objekt und mit diesem lassen sich letztendlich die E-Mails abrufen:

com/tutego/insel/mail/MailUtils.java, Teil 3

public static void printAllTextPlainMessages( Folder folder )

throws MessagingException, IOException

{

for ( Message m : folder.getMessages() )

{

System.out.println( "\nNachricht:" );

System.out.println( "Von: " + Arrays.toString(m.getFrom()) );

System.out.println( "Betreff: " + m.getSubject() );

System.out.println( "Gesendet am: " + m.getSentDate() );

System.out.println( "Content-Type: " +

new ContentType( m.getContentType() ) );

if ( m.isMimeType( "text/plain" ) )

System.out.println( m.getContent() );

}

}

Die Implementierung holt sich mit getContent() den kompletten Inhalt, aber natürlich lässt sich der auch über einen Eingabestrom holen.

Ein kleines Demo dazu, was erst Verbindung mit dem Google Mail Server herstellt, dann sich den INPUT-Ordner öffnet und alle E-Mails abläuft. Die Nachrichten werden nicht vom Server gelöscht.

com/tutego/insel/mail/PrintAllMailsWithMailUtils.java, main()

Session session = MailUtils.getGMailSession(

JOptionPane.showInputDialog( "user" ),

JOptionPane.showInputDialog( "pass" ) );

Folder inbox = MailUtils.openPop3InboxReadOnly( session );

MailUtils.printAllTextPlainMessages( inbox );

MailUtils.closeInbox( inbox );

Das Programm öffnet zwei Dialoge, einen für den Benutzernamen und einen für das Passwort, es ist jedem selbst überlassen, hier feste Strings einzukodieren.

Hinweis

Um herauszufinden, ob überhaupt Nachrichten auf dem Server vorliegen, können wir auf dem aktuellen folder-Objekt die Methode getMessageCount() nutzen.

Nachricht löschen

Um eine Nachricht vom Server zu löschen, darf der Ordner nicht mit READ_ONLY geöffnet werden, sondern mit Folder.READ_WRITE. Anschließend lässt sich einer Nachricht, repräsentiert durch ein Message-Objekt, mit setFlag() ein Lösch-Hinweis geben:

message.setFlag( Flags.Flag.DELETED, true );

Die Daten werden jedoch nur dann vom Server gelöscht, wenn zum Schluss folder.close(true) aufgerufen wird. Ohne den Aufruf von close() mit dem Argument true bleiben die Nachrichten erhalten.

Inselupdate: Primitive Elemente in Datenstrukturen verwalten

Jede Datenstruktur der Collection-API akzeptiert, auch wenn sie generisch verwendet wird, nur Objekte. Primitive Datentypen nehmen die Sammlungen nicht auf, was zur Konsequenz hat, dass Wrapper-Objekte nötig sind (über das Boxing fügt Java 5 scheinbar primitive Elemente ein, doch in Wahrheit sind es Wrapper-Objekte). Auch wenn es also heißt:

List<Double> list = new ArrayList<Double>();

list.add( 1.1 );

list.add( 2.2 );

sind es zwei neue Double-Objekte, die aufgebaut werden, und in die Liste wandern. Anders und klarer geschrieben, was wirklich passiert:

List<Double> list = new ArrayList<Double>();

list.add( Double.valueOf(1.1) );

list.add( new Double(2.2) );

Dem Double.valueOf() ist der new-Operator nicht abzulesen, doch die Methode ist implementiert als: Double valueOf(double d){ return new Double(d); }.

Spezialbibliotheken

Für performante Anwendungen und großer Menge von primtiven Elemente ist es sinnvoll, eine Klasse für den speziellen Datentyp einzusetzen. Anstatt so etwas selbst zu programmieren, kann der Entwickler auf drei Implementierungen zurückgreifen:

  • fastutil (http://fastutil.dsi.unimi.it/). Erweiterung um Datenstrukturen für (sehr viele) primitive Elemente und hochperformante Ein-/Ausgabe-Klassen.
  • GNU Trove (http://trove.starlight-systems.com/). Stabil und Entwicklung ist aktiv. Neue Datenstrukturen aus Java 5 oder 6 wie Queues zählen jedoch nicht dazu.
  • Apache Commons Primitives (http://jakarta.apache.org/commons/primitives/). Stabil in der Version 1.0, aber seit Ende 2003 nicht mehr aktualisiert.
  • Inselupdate: Blockierende Warteschlangen

    Die Schnittstelle BlockingQueue steht für besondere Queues, die blockieren können. Das kann aus zwei Gründen geschehen: entweder sind keine Daten zu entnehmen da die Queue leer ist, oder eine maximale Anzahl von zu haltenden Elementen ist erreicht. Besonders in Produzenten/Konsumenten-Szenarien sind blockierende Warteschlangen sehr nützlich.

    Eine performante thread-sichere Implementierung ist in der Praxis sehr wichtig und die Java SE Bibliothek hat zwei besondere Realisierungen auf Lager:

    • ArrayBlockingQueue: Queue immer mit einer maximalen Kapazität, realisiert intern mit einem Feld
    • LinkedBlockingQueue: Queue unbeschränkt oder mit maximaler Kapazität, intern realisiert durch eine verkettete Liste
    • PriorityBlockingQueue: Eine blockierende PriorityQueue

    Die anderen Realisierungen wie DelayQueue sind für uns jetzt nicht relevant.

    Das schöne an blockierenden Warteschlangen ist ihr Verhalten in Produzenten/Konsumenten-Verhältnissen; ein Thread (oder beliebig viele Threads) setzt (viele setzen) Daten in die Queue, ein Thread (oder beliebig viele Threads) holt (viele Threads holen) die Daten wieder raus. Bei einer Queue ist es ja so, dass sie nach dem FIFO-Verfahren arbeitet, das heißt, die Daten, die zuerst reingelegt wurden, werden auch zuerst verarbeitet. Bei einer Prioritätswarteschlage ist das etwas anders, aber dazu gleich mehr.

    Java taucht nix für Enterprise? Meine Gedanken

    Nach dem Eintrag im Blog (http://www.tutego.de/blog/javainsel/2011/02/forrester-untersuchung-sagt-java-taugt-nix-fr-enterprise/) über die Forrster Studie fragte ein Kommentator nach meiner Einschätzung. Also, taucht Java ab oder taugt es?

    Es ist schwer einen Anfang zu finden, denn verschiedene Sachen laufen immer durcheinander. Zunächst ist Java eine Vereinigung:

    Java = JVM + Java als Programmiersprache + Java SE Lib + Java EE Lib (wenn man Enterprise hinzunehmen möchte)

    Man könnte noch “Great Communitiy” oder große Anzahl Open-Source Libs dazu nehmen, aber darauf kommt es jetzt nicht an.

    An den Gliedern kann man anfangen unter verschiedenen Bewertungskriterien rumzunörgeln. Es steht außer Frage das die JVM unglaublich leistungsfähig ist. Bei der Programmiersprache Java fängt aber die Kritik schon an – bei der Java SE geht es weiter. Java EE kann man auch kritisieren, jedoch für einen anderen Grund.

    • Die Sprache Java hat sich die letzten Jahre nicht gewandelt, aber Skriptsprachen zeigen zum Beispiel deutlich den Trend auf, Collection-Unterstützung in den Sprachkern aufzunehmen und Closures sowie funktionale Aspekte zu unterstützen desweiteren Nebenläufig besser anzugehen.
    • Die Bibliotheken haben deutliches Potenzial. Einmal horizontal (unterschiedlichen Technologien) wie vertikal (in der Tiefe). Wenn Java SE schon fertig wäre, wäre Apache Commons * oder Google Collections/Guava gar nicht nötig. Wenn Java EE auch den Web-Technologie-Teil abdecken soll, OOOHA, da ist noch viel zu tun.

    Der Autor der Studie ist nicht gegen Java: die Folien zeigen, das Java in vielen Bereichen perfekt passt. Er macht aber klar, dass Java eben nicht für jedes Problem die Antwort ist. Da hat der Mann natürlich Recht! Mit der Banane einen Nagel in die Wand zu schlagen wird auch kompliziert. Java ist explizit als General Purpose Sprache entworfen worden. Das heißt: Für alles und nichts! Während man außer Frage stellt, Java im Bereich Treiberprogrammierung einzusetzen, versuchen viele Java (also die Sprache + Java SE + Java EE) dort einzubringen, wo es bessere Lösungen gibt. Java ist im Gui-Bereich einfach schwach. Punkt. Gui ohne Databinding? Nicht gut. (Es geht immer noch darum, dass es kein Teil der Standard-Bibliotheken ist. Natürlich gibt es Databinding am Open-Source-Himmel … sogar gaaaanz viele Lösungen.) Es steht außer Frage, dass man mit Swing und JSF absolut geile Lösungen bauen kann. Doch Softwareentwicklung besteht nicht daraus, mit ein paar Experten ein System zu bauen; gibt Experten FORTRAN oder COBOL und auch dann wird das Design super sein.

    Die zentralen Schwachpunkte im Gui-Bereich sind:

    • Zu kompliziert mit den STANDARD-Frameworks für den Durchschnitts-Joe. In einer Tabelle eine Fließkommazahl mit zwei Nachkommastellen zu formatieren muss einfacher gehen als extra einen Cell-Renderer zu programmieren.
    • Für echte Oberflächen muss man zukaufen, OS-Libs nehmen, oder stark in Eigenentwicklung investieren. Databinding gibt es, klar, aber eben nicht im Java SE. Man schaue nur auf Eclipse RCP und dann sieht man, was in Swing alles fehlt.
    • Agil mal eben schnell eine Änderungen umzusetzen geht nicht.

    WENN man also Gui-Entwicklung zur Enterprise-Entwicklung zählt – und das tut der Autor der Studie, das ist aber auch Diskussionssache – hat er mit seiner Kritik recht. Mich wundert, was es an dem Punkt zu diskutieren gibt. Die Diskussion gleitet schnell in die Richtung das man sagt: Ja, aber in Ruby, mit Eclipse RCP, mit Vaadin, mit bla, … geht das alles! Stimmt, es geht aber hier um pures Java und um das, was in Java SE/Java EE von Oracle kommt. Hier hat eben Java nichts zu bieten. Ich finde Swing toll und mag es, aber für heutige Richclient-Anwendungen ist das nichts. Auch JSF ist nichts für moderne RIA-Anwendungen. Viel zu HTML-lasting.

    Java EE ist im Kern ausgereift und für Geschäftslogik und Persistierung nahezu perfekt. Container wie GlassFish machen es rund. Hier liegt nicht das Problem. Entwickler großer Anwendungen müssen lernen das richtige Tool für den Job zu finden. Im Enterprise Bereich ist Java EE 6 ein guter Anfang für das Backend. Den Gui-Bereich können wir aufgeben. Klar, das es mit Swing und JSF “irgendwie geht”, aber wie gesagt: es darf keine Technologie für Experten sein. Es wird natürlich immer Softwareentwickler geben die sich wünschen, das eine Technologie für Experten ist, aber es geht um Wirtschaftlichkeit, ob wir das wollen oder nicht. Und wenn eben ein Swing-Entwickler für einen neuen Button 20 Minuten im Quellcode braucht, der Silverlight-Entwickler aber nur 5 Minuten, ist klar, wie die Rechnung aussieht. Und selbst das ist noch viel zu low-level gedacht.

    Selbst wenn man Java aufbohrt und pimpt bis zum Abwinken mit Business-Rules-Engine, alles in dynamischen Programmiersprachen auf der JVM entwickelt, usw. usw., es wird immer noch zu viel selbst gebaut. Entwickler müssen lernen, sich in komplexe existierende Systeme einzuarbeiten, und auf deren Basis eigene Lösungen entwickeln. Im Web-Bereich sei einmal der JBoss-Stack oder Alfresco in den Raum geworfen, aber auch richtig fette Sachen wie SAP, auch wenn vielen das nicht gefallen dürfte. Oder Talend zur Konvertierung. Der Autor der Studie lässt Alternativen vielleicht bewusst offen (RoR wird genannt im Web-Bereich) und ich vermute einfach deswegen weil es keine Alternativen gibt! Oracle bietet eine wunderbare Basis aber es liegt an uns, mächtigere Framworks, und dann auch DSL für spezifische Probleme zu nutzen. Java hat seinen Platz und ist eben nicht für alles zu gebrauchen. Ich erinnere mich gut an dBASE, das zeigt schon vor über 10 Jahren die Richtung auf: Eine Entwicklungsumgebung mit Programmiersprache. Das ist Rapid Application Development von datatenbankgetriebenen Anwendungen. Eigenentwicklung wird es immer geben, aber für gewisse Probleme funktionieren wunderbar 4GL-Lösungen.

    Hat Apache bei Sun/Oracle doch geklaut?

    Es geht die Frage um, ob Harmony bei Suns Implementierung geklaut hat. http://fosspatents.blogspot.com/2011/01/new-evidence-supports-oracles-case.html gibt ein Diff der compilierten Dateien und zeigt große Ähnlichkeiten auf. Ich stimme dem zu, dass das geklaut ist, denn so gleiche Implementierungen zu wählen halte ich für absolut unwahrscheinlich aus folgenden Gründen:

    • Einen Vector mit der Größe 10 (an anderer Stelle 20) vorzuinitialisieren und dann 10 (an anderer Stelle 20) als capacity-increment zu wählen ist sehr speziell; das exakt so zu machen ist eigentlich ausgeschlossen. Mein stärkster Indiz, das das geklaut ist.
    • Objektvariablen explizit auf null/false/0 zu setzen ist Unsinn; warum sollte Apache den Quatsch wiederholen?
    • Private Methode heißen alle gleich, was aber natürlich ein Implementierungsdetail ist. findTable() etwa ist nicht gerade naheliegend.
    • Warum nennen beide die (privaten) Variablen gleich, insbesondere permissionSet und nicht etwas permissions?

    Code: http://www.docstoc.com/docs/69702407/1-AclEntryImpl-synopsis, http://www.docstoc.com/docs/69702409/2-AclImpl-synopsis.

    Spiel Poisonville eingestellt. Ist Java daran Schuld?

    Mit viel Tam-Tam hat das Hamburger Unternehmen Bigpoint vor anderthalb Jahren auf der Spielemesse GCO 2009 in Leipzig einen Brower-basierteren GTA-Klon vorgestellt:

    Jetzt stelle Bigpoint das Spiel ein und erklärt das mit den “vielen Fehlern der Java-Plattform”. Siehe

    Details sind leider nirgendwo aufgeführt. Wer weiß mehr über diese Probleme? Kann es sein, dass das Spiel einfach nicht am Markt ankam und Java jetzt Sündenbock ist?