TwitterGoogle

Vorstellung der Diff, Match and Patch Bibliothek

Bisher habe ich auf wikihost.org das diff-Tool der Linux-Shell verwendet, um den Anwendern eines Wikis die Möglichkeit zu geben, zwei unterschiedliche Versionen einer Wiki-Seite hinsichtlich ihrer Unterschiede zu vergleichen. Dabei wurden einfach die beiden Wiki-Sources temporär als Datei weggeschrieben, das externe diff aufgerufen und der Output wieder eingelesen und interpretiert.
Dieser Ansatz hatte einige Nachteile, wie z.B. das Unvermögen mit Unicode-Zeichen umzugehen, die Verarbeitungsgeschwindigkeit und eine unschöne Darstellung.

Aus genannten Gründen war ich daher auf der Suche nach einer vernünftigen, integrierten Lösung. Gefunden habe ich eine sehr schöne für mehrere Sprachen entwickelte Bibliothek.

Google Diff, Match and Patch

Die diff, match and patch-Bibliothek von Neil Fraser stellt  identische Funktionen für Java,  JavaScript, Dart, C++, C#, Objective C, Lua und Python bereit. Sie wird auf code.google.com gehostet und unter der Apache License 2.0 bereitgestellt.

Für wikihost.org ist die Java-Bibliothek relevant, daher beziehe ich mich hier ausschließlich darauf. Wikihost.org ist in Grails/Groovy entwickelt, daher zeige ich auch kurz, wie die Java-Bibliothek dort einzubinden ist.

 

Bibliothek ins Grails-Projekt aufnehmen

Damit die Java-Klassen der diff-Bibliothek in der Grails-Anwendung genutzt werden können, muss das Java-File einfach in das Verzeichnis <PROJECT>/src/java kopiert werden.

Hier die Projekt-Struktur des wikihost.org Grails-Projekts mit eingebundener diff-Bibliothek:

 

  Diff Project-157x300 in

 

Ist das erledigt, kann man auch schon beginnen, die diff-Funktionalität in einem der Controller zu nutzen.

Diff in Grails ermitteln

Hier der Code, wie ich ihn zum Vergleich der Revisionen einer Wiki-Seite nutze:

//Initialisiere diff-Bibliothek
def dmp = new diffy.diff_match_patch()
//Vergleiche alte und neue Version
def diffed = dmp.diff_main(oldRevText,newRevText)
//mache für Menschen lesbar (optimierte Darstellung)
dmp.diff_cleanupSemantic(diffed)
//als HTML ausgeben (färbe gelöschte Teile rot, Hinzugefügte grün)
def TextHtml = dmp.diff_prettyHtml(diffed)

 

Zuerst wird eine Instanz der Klasse diff_match_patch initiiert. Den Package-Namen diffy habe ich in der Klasse definiert, damit ich leichter erkenne, wo diese Klasse herkommt. Der eigentliche Vergleich zwischen oldRevText und newRevText findet dann in der zweiten Zeile durch Aufruf der Methode diff_main() statt. Da die Differenz zwischen den beiden Versionen durch Veränderungsschritte (was muss gelöscht und hinzugefügt werden, um vom alten auf den neuen Zustand zu kommen aka Levenshtein-Distanz) dargestellt werden, wäre in vielen Fällen ein kaum entzifferbares Ergebnis, wie in diesem Beispiel der Fall:

Diff Demo1 in

Durch den Aufruf der Methode diff_cleanupSemantic() wird dies lesbarer gemacht, indem die einzelnen diffs zu größeren Blöcken zusammengefasst werden. Hier der selbe Vergleich mit nachträglicher Optimierung:

Diff Demo2 in

Mit der Methode diff_prettyHtml() kann eine simple HTML-Ausgabe erzeugt werden. Möchte man das Ergebnis nicht für eine HTML-Seite

Das Ergebnis liegt zum Schluss in der Variable TextHtml und wird an die GSP-Seite zur Ausgabe im Browser durchgereicht.

 

Selbst ausprobieren kann man die Funktionen der Bibliothek unter http://neil.fraser.name/software/diff_match_patch/svn/trunk/demos/demo_diff.html direkt im Browser.

Mit Talend Open Studio einen Webservice erstellen

Über Talend Open Studio (TOS) als ETL -Werkzeug habe ich ja schon öfters geschrieben. Es handelt sich in erster Linie um ein ETL-Werkzeug, also ein Programm, mit dem man Daten aus verschiedensten Quellen laden, verarbeiten und in beliebige Ziele übertragem kann. Dass man mit TOS aber auch ganz leicht einfache Webservices erzeugen kann, wissen jedoch die Wenigsten. Und dazu braucht es keinerlei Programmier-, XML- oder SOAP-Kenntnisse.

Deswegen möchte ich hier mal exemplarisch einen sehr einfachen Webservice mit Talend realisieren.

Das Szenario

Ein Webservice soll es ermöglichen, Preise zu beliebigen Artikeln aus der Warenwirtschaft zu ermitteln. Das Warenwirtschaftssystem wird durch eine CSV-Datei repräsentiert und kann somit ganz leicht angepasst und erweitert werden.

Hier die ersten paar Zeilen aus dieser Datei:

id;artikel;preis
1;DIN A4 Ringbuch;1,99
2;Klebefilm Rolle 25m;0,89
3;Briefumschlag m. Sichtfenster DIN A5 (100 Stk);9,89
4;Papierlocher blau;4,99

Der Webservice wird einen einzelnen Aufrufparameter articleid entgegennehmen. Dieser entspricht der Artikelnummer, über welche dann der Datensatz gesucht wird. Kann der Artikel nicht gefunden werden, wird ein entsprechender Fehler zurückgemeldet, ansonsten liefert der Webservice den vollständigen Artikeldatensatz zurück.

Lesen Sie weiter

Grails 1.3.7 released

CXmUZIAv28XIiNgkRiz4RRl21TsGZ5HoGpZw1UITNyV in Graeme Rocher hat die Version 1.3.7 des Web-Frameworks Grails veröffentlicht. Bei Grails handelt es sich um eine Zusammenstellung von Frameworks, wie Spring, Hibernate und SiteMesh.
Programmiert wird Grails mit Groovy nach dem Prinzip “Convention over configuration” und ermöglicht so schnelle Ergebnisse bei der Programmierung.
Um noch ein wenig mehr zu Grails zu erfahren, empfehle ich 5 Gründe warum Grails einfach groovy ist zu lesen.

Die wesentlichen Neuerungen von Version 1.3.7 sind

  • Grails verwendet Groovy 1.7.8
  • Request-Parameter können von Stacktrace-Logs ausgeschlossen werden (gezielt einzelne Parameter, oder komplett alle)
  • rund 30 Bugfixes, sowie
  • einige kleinere Verbesserungen (Details im Changelog)

Bisher habe ich noch keine Probleme mit Version 1.3.7 festgestellt; die Migration des Projekts zu wikihost.org ging reibungslos über die Bühne und läuft nun seit knapp 24 Stunden unter normaler Last produktiv.

Grails 1.3.7 Download
Grails 1.3.7 Dokumentation

5 Gründe warum Grails einfach groovy ist

Seit nun fast einem Jahr schreibe ich meine Wiki-Hosting-Plattform wikihost.org in Grails neu. Die bisher zugrundeliegende Technologie, die tdbengine, erschien mir für ein solches Portal einfach nicht mehr zeitgemäß.
Am Anfang stand die Entscheidung, in welcher Programmiersprache bzw. mit welchem Framework ich das (Mammut)-Projekt angehe. PHP und Perl mag ich nicht, Java-Servlets erschienen mir sehr umständlich und aufwändig und an mir völlig fremde Sprachen, wie Ruby oder Python traute ich mich nicht. Mit Grails und Groovy fand ich einen Mittelweg aus Java- und JavaScript-ähnlicher Programmierung, welche ich mir, mit ein wenig Lektüre, schnell aneignen konnte.

Und ich muss heute sagen, dass dies eine gute Entscheidung war und ich bis heute nicht von Grails enttäuscht wurde.

Hier nun meine 5 Gründe, warum ich finde, dass Grails einfach groovy ist:

1. Die zugrundeliegende Sprache Groovy

Mit Groovy zu arbeiten ist einfach … groovy. Während Java starr und restriktiv jede noch so kleine Abweichung vom Schema F abstraft, ist Groovy, welches Grails zu Grunde liegt, wesentlich gelassener. Ob man nun eine Funktion bzw. Methode mit oder ohne Klammern aufruft, um Parameter zu übergeben ist egal. Datentypen? Kann bzw. sollte man dort benutzen, wo es notwendig und sinnvoll ist. Darf man aber getrost ignorieren, wo es zulässig erscheint.

Groovy ist ausserdem eine funktionale Sprache und löst sich vom Paradigma Javas, welches extrem Objekt-bezogen ist. Mit sogenannten Closures bieten sich ganz neue Ansätze beim Code-Schreiben: Einer Funktion als Parameter eine Funktion zu übergeben, das gibt es in Java so nicht.

Kleines Beispiel in Java und Groovy:

//Java
char[] arr = {'a','b','c'};
for(int i = 0; i < arr.length; i++) {
  System.out.println( arr[i] );
}
//Groovy
['a','b','c'].each { println it }

2. Man muss sich an vielen Stellen einfach keine Gedanken über die zugrundeliegende Datenbank machen

Der O/R-Mapper Hibernate ist fast völlig transparent in Grails integriert. Hat man seine Datenbank in der Konfiguration korrekt hinterlegt und sogenannte Domain Classes definiert, sorgt dieser dafür, zu jeder Klasse eine entsprechende Datenbank-Tabelle zu erzeugen bzw. diese entsprechend anzupassen. Um korrekte SQL-Syntax, Normalisierung oder Indexierung der Daten muss (kann aber trotzdem) man sich keine Gedanken machen.

// Beispiel Domain-Klasse
package org.example
class Poem {
    String title
    String author

    static constraints = {
        title(blank: false)
        author(blank: false)
    }
}

3. Convention over Configuration bringt schnelle Ergebnisse

Wer sich die Website zu Hibernate oder dem Spring-Framework mal etwas genauer durchliest, wird immer wieder auf XML-Strukturen stoßen, mit denen diese Frameworks konfiguriert werden. Das ist aufwendig, fehleranfällig und mit Grails auch gar nicht notwendig. Grails setzt gewisse Conventions voraus, wie z.B. Class-Names wie FlugzeugController, um dahinter eine Controller-Klasse (im Sinne des MVC-Patterns) zu definieren, die bestimmte Methoden bereitstellt. Darum, dass es sich letztlich um Servlets handelt, die im Container gemappt werden müssen, braucht der Entwickler sich keine Gedanken zu machen.

4. Plugins für viele unterschiedliche Aufgaben existieren bereits

Egal ob eine Anbindung an PayPal erfolgen soll, ob die eigenen Inhalte per Volltextsuche via Lucene durchstöbert werden sollen oder ob einfach hübsche Formular-Widgets im Browser der Besucher erscheinen sollen, es gibt für vieles ein passendes Plugin. Diese Plugins können dank der verwendeten IDEs (Netbeans oder Eclipse) mit wenigen Klicks eingebunden werden und stehen danach transparent zur Verfügung.

Dadurch kann man sich für viele Aufgabenstellungen die grundlegende Arbeit sparen und nutzt (meist) ausgereifte Bibliotheken.

5. Im schlimmsten Fall steht einen die ganze Welt von Java zur Verfügung

Weil Groovy letztlich wie ein Aufsatz auf Java funktioniert und letztendlich ganz normale .class-Dateien als Kompilat herauskommen steht einem die ganze Welt von Java zur Verfügung. D.h. alle Taglibs oder Bibliotheken, die man in einem normalen Java-Programm nutzen kann, lassen sich auch in einer Grails-Applikation verwenden. Daher mache ich mir so schnell auch keine Sorgen, dass ich mich mit wikihost.org bzw. der darunterliegenden Umgebung wieder in eine Sackgasse manövriere.

Es gibt sicherlich noch viele weitere Gründe, warum das Arbeiten mit Grails mir groovy erscheint. Vielleicht liefere ich ja demnächst noch weitere nach.

tFileFetch: HTTP-Zugriff in Talend Jobs

Mit tFileFetch kann man in seinen ETL-Prozessen auf beliebige HTTP-Server zugreifen, entweder um Dateien herunterzuladen, oder Daten zu übermitteln. Auch der Upload von Dateien ist dabei möglich. Ausserdem bietet tFileFetch auch den lesenden Zugriff auf Dateien auf einem FTP- sowie auf einem Samba (SMB)-Server. FTP und SMB-Zugriff werde ich jedoch in diesem Beitrag außenvorlassen.

TFileFetch Icon32 in

Die Komponente tFileFetch, deren Name zugegebenermaßen nicht unbedingt auf die ganze dahinterliegende Funktionalität schließen lässt, befindet sich im Bereich Internet der Komponenten-Palette.

Wenn das Protokoll http ausgewählt ist, kann man zum einen Dateien und Seiten aus Talend herunterladen und zum anderen auch HTML-Formulare ausfüllen, ja sogar Dateien hochladen.

Im Feld URI muss man dazu die vollständige Adresse samt Protokoll (also http://) angeben. Das Destination Directory sollte auf das Verzeichnis zeigen, in dem das Ergebnis des Aufrufs abgelegt werden soll. Je nachdem, ob man nun eine Datei herunterlädt, eine Seite aufruft oder ein Formular abschickt, wird das Ergebnis des Aufrufs dort unter dem entsprechenden Namen abgelegt (also bei http://www.meinserver.de/xyz/index.html als index.html).
Möchte man dies nicht, so kann man im Feld Destination Filename auch einen eigenen Namen explizit vergeben.

 in

Beim Zugriff auf HTTP-Server werden für das Öffnen eines Dokuments normalerweise die Methode GET und beim Versenden von Formulardaten die Methode POST verwenden. Auch wenn es noch weitere Zugriffsmethoden (wie z.B. PUT oder DELETE) gibt, werden diese von tFileFetch nicht unterstützt. Der Zugriff über GET bedingt, dass evtl. zu übertragende Formulardaten in der URL übergeben werden. Daher ist der Upload von Dateien nur mit POST möglich. Auch ist die Anzahl der Zeichen, die in einer URL enthalten sein dürfen auf unter 4000 beschränkt. Aus diesem Grund ist standardmäßig die Checkbox POST method aktiviert. Möchte man keine Formulardaten an den Server übermitteln, empfiehlt es sich daher, diese Checkbox abzuwählen.

In der Tabelle Parameters können die einzelnen Formularfelder in Form von Key-Value-Paaren ausgefüllt werden. Für jedes Feld fügt man einfach mit dem grünen Plus eine neue Zeile in der Tabelle hinzu. Die Spalte Name muss den Feldbezeichner enthalten während in Value der zu übertragende Wert eingetragen wird.

Möchte man Dateien mit dem Formular hochladen, so muss dies im Reiter Advanced settings eingerichtet werden. Hat man die Checkbox Upload ausgewählt, so erscheint darunter eine Tabelle. In dieser Tabelle trägt man nun wieder die Namen der File-Upload-Felder ein und unter File den absoluten Pfad zur Datei.

 in

Beim Upload von Dateien ist es erforderlich, dass die Übertragungsmethode POST unter Basic settings aktiviert ist.

Ist beim Zugriff auf die angegebene URI eine HTTP-Authentifizierung erforderlich, so kann man die entsprechende Checkbox anwählen und dann den Benutzernamen und das Passwort angeben.

 in

Seit der Version 3.2 von Talend Open Studio und Talend Integration Suite lassen sich Proxy-Einstellungen job-weit mit der Komponente tSetProxy einrichten, daher verzichte ich auf die Beschreibung der Proxy-Settings in tFileFetch.

Beim Zugriff auf einen Server kann natürlich auch einmal ein unerwünschter Zustand eintreten, wie z.B. eine Überlastung oder Downtime des Servers. Damit der Talend-Prozess dann nicht endlos wartet, bis seine Anfrage beantwortet wird, gibt es das Feld Timeout. Hier kann man die maximale Zeit, die die Komponente geduldig auf Response wartet, in Millisekunden angeben.

 in

In diesem Beispielszenario wird ein Formular per POST an eine URL geschickt und, mit den per File-Upload übermittelten Transaktionen, aus der Datei transaktionen_2009_11.csv, eine CSV-Datei erzeugt. Diese wird als Ergebnis des Aufrufs im Verzeichnis /var/temp/result/ als umsaetze.csv abgelegt.

Da es sich bei dieser URL um einen geschützten Bereich auf dem Web-Server handelt, werden der Benutzername und das Passwort für die Authentifizierung mit übertragen. War der Aufruf erfolgreich, so werden die heruntergeladenen Daten mit der Komponente tFileInputDelimited eingelesen und mit tMysqlOutput in die Zieltabelle einer MySQL-Datenbank übertragen.

Aber auch eine Spam-Maschine lässt sich mit dieser Komponente relativ schnell und unkompliziert erstellen. Nur wie das geht werde ich hier sicherlich nicht vormachen.

Possibly related posts: (automatically generated)