Ruby on Rails Ruby on Rails und IBM DB2

Rails und DB2 haben mich ein wenig beschäftigt. Das Ganze hat irgendwie hingehauen, hat mir aber einige Hürden bereitet.

Grundsätzlich habe ich gedacht durch den abstrahierten Datenbank-Handler wäre es kein Problem mein Projekt (Rails 3.0.6) von MySQL auf DB2 umzustellen. Im Endeffekt war es auch kein großes Problem, dennoch gab es einige „Hürden“ die es zu bewältigen gab.

Als DB2-Version kam zu Entwicklungszwecken ein DB2 9.7.4 Express-C zum Einsatz. Ich lokal auf meinem Entwicklungsplatz dafür das Paket mit dem kompletten Datenbank-Server installiert. Per “db2cc” war es auch einfach möglich eine Datenbank zu erstellen.

In Rails hat sich der DB2-Handler „ibm_db“ dann auch gleich mit der Datenbank korrekt verbunden. Dennoch funktionierte mein Projekt nicht mehr. Es gab hier Fehler, die ich nicht erklären konnte. Nach genauem sichten des Codes, habe ich bemerkt, dass DB2 viel genauer arbeitet als MySQL. So habe ich Abfragen getätigt, bei denen ich keine Typ-Konvertierung durchgeführt habe. MySQL hat dieses auf Anhieb verstanden, DB2 gibt mir einen Fehler aus. Ich habe beispielsweise bei ein ID (natürlich eine Zahl) in einer Abfrage verwendet. Die abzufragende Tabelle hat diese ID allerdings als String gespeichert. Da ich hier den Typ nicht konvertiert habe, kam es zu einem Fehler. Mit einem ergänzendem „.to_s“ war der Fehler beseitigt.

Sehr schön. Aber es gab noch ein Problem. Das Produktivszenario sieht so aus, dass ein DB2-Server vom Applikationsserver getrennt arbeitet. Die Rails-Anwendung sollte also nicht mit meinem lokalen Datenbank-Server kommunizieren, sondern über das Netzwerk eine Verbindung aufbauen. Ohne DB2-Libs und Includes ist es aber nicht möglich das ibm_db Gem per „gem install ibm_db“ zu installieren. Und den großen Datenbank-Server zu installieren erschien mir übertrieben und ist ach nicht gewollt.

Auf der IBM-Seite des DB2 Expess-C läßt sich auch nicht sofort ein passendes Runtime-Paket o.ä. finden. Nach etwas Zeit und Suchen folgte ich dem Link zu “Data server drivers for Java, .NET, and other platforms”, der direkt von der Express-C Seite abgeht. Hier gab es also noch weitere Downloads für DB2-Express-C. Unter anderem das Paket „IBM Data Server Client“. Dieses beinhaltet alle notwendigen Ressourcen zur Installation des DB2-Handlers. Wichtig dabei war allerdings, dass ich die Pfade zum Lib und Include-Verzeichnis angeben. Mit

export IBM_DB_INCLUDE=/home/user01/Downloads/dsdriver/include/
export IBM_DB_LIB=/home/user01/Downloads/dsdriver/lib/

war das schnell erledigt. Anschließen wurde das Gem fehlerfrei installiert.

Und trotzdem fand meine Rails Anwendung nicht die Datenbank auf dem entfernten Server. Meine database.yml sah ungefähr so aus (Auszug!):

production:
      database: mydbprd
      username: user01
      password: Start123
      schema: mydb
      host: db2host
      port: 50002

Wenn man DB2 auf einem Client benutzt und dieser sich per Netzwerk mit einem DB2-Server verbinden soll, ist es notwendig, dass der DB2-Handler weiß, wo die Datenbank liegt. Dafür muss die Datenbank katalogisiert werden. Katalogisieren kann man mit dem Befehl „db2“, welches sich im Paket des Datenbank-Server befindet, allerdings nicht im Handler-Paket mit den passenden Ressourcen.

Ich benötigte daher noch ein weiteres Paket. Auch dieses gab es auf der von mir entdeckten Seite.

>> IBM Runtime Client

Wenn dieses installiert ist, kann auch die lokale DB2-Konsole (Command Line Processor = CLP) geöffnet werden. Per Befehl „db2“ gelangt man dorthin und kann nun katalogisieren. Als erstes den passenden Node über den die Kommunikation des DB2-Servers durchgeführt wird. Dieser wird über den Befehl

CATALOG TCPIP NODE mydb2node REMOTE db2host SERVER 50002

katalogisiert. Anschließend ist es noch notwendig die Datenbank zu katalogisieren:

CATALOG DATABASE mydbprd as prod_db AT mydb2node

Über den DB2-CLP habe ich noch überprüft, ob die Verbindung zur Datenbank hergestellt werden kann. Dies erfolgt mit dem Befehl “Connect”:

CONNECT TO mydbprd USER user01 USING Start123

Als diese Schritte durchgeführt wurden, konnte meine Rails-Anwendung mit der entfernten DB2-Datenbank kommunizieren.


default Subversion-Erfahrungen und SVN-Repository Backup

Es war nun endlich an der Zeit von CVS auf Subversion umzusteigen. Besonders in Hinblick auf die kommende Lotus Notes Designer Erweiterung, die es endlich ermöglicht, Designelemente in ein Versionierungssystem ein- und auszuchecken. Dazu aber in einem gesonderten Artikel mehr. Als erstes habe ich alle bestehenden CVS-Repositories genommen und mittels CVS2SVNkonvertiert. Das hat auch hervorragend geklappt. Das CVS2SVN läßt sich recht einfach wie folgt aufrufen:

cvs2svn --svnrepos <<Ziel-Pfad zum SVN-Repos.>> <<Quell-Pfad des CVS-Repos.>>

Dieser Aufruf klappte auch schon wunderbar. Allerdings gab es einige Probleme mit deutschen Umlauten in den Commit-Logs des CVS. Warnungen waren daher in den Repositories an der Tagesordnung. Dafür schafft ein weiterer Parameter Abhilfe mit dem ich das Encoding des Repositories explizit angegeben habe. Zur Sicherheit habe ich das fallback-encoding auch noch angegeben.

cvs2svn --svnrepos <<Ziel-Pfad zum SVN-Repos.>> <<Quell-Pfad des CVS-Repos.>>
 --encoding=latin_1  --fallback-encoding=latin_1

Damit ließen sich dann die CVS-Repositories sehr schnell konvertieren. Sobald sie in den Subversion-Repository-Pfad gestellt wurden, waren diese auch wieder von allen anderen erreichbar.   Nachdem ich nun meine Subversion-Repositories hatte, kam noch ein Wunsch auf. Aktuell arbeite ich, neben Projekten auf dem PC, auch an einem Hobby-Projekt. Es geht darum ein PC-Spiel für einen alten ATARI XL/XE (1,79 MHz, 64 KB!) umzusetzen. Auch auf diesem nostalgischem System ging die Entwicklung weiter. Mittlerweile werden die meisten Programme dafür nicht mehr auf dem kleinen Home-Computer geschrieben, sondern in einer richtigen Entwicklungsumgebung unter Windows oder Linux (dazu hat Creature XL einen interessanten Artikel in seinem Blog verfasst). Subversion oder andere Versionierungssysteme werden dabei auch gern genutzt. Wir haben für unser Spiel daher auch ein SVN-Repository. Um zu verhindern, dass wir nicht mehr an den Code kommen, weil der Server nicht erreichbar ist, haben wir uns entschlossen, das Repository zu spiegeln. Creature XL hat einen Server und ich habe einen Server. Das paßte sich ganze gut. Auf dem Server von Creature XL befindet sich das Hauptrepository, welches mein Server spiegeln sollte. Ich habe dafür als erstes einen neuen User angelegt, der nur für das spiegeln zuständig ist. Per gerechneten und ausgetauschten Keys kann sich der User an dem anderen Server ohne Kennwort anmelden. Als erstes muss auf dem Spiegel-Server nun ein neues SVN-Repository angelegt werden:

svnadmin create /srv/svn/repo_name

Hier befindet sich nun ein neues leeres Repository. Damit das Repository vorerst nur vom SVN-Spiegel-User benutzbar ist, müssen noch folgende Zeilen in die Datei  /srv/svn/repo_name/hooks/pre-revprop-change eingetragen werden. Damit sichern wir das Repository vor anderen Server-Usern ab.

#!/bin/sh
USER="$3"
if [ "$USER" = "svnsync" ]; then exit 0; fi
echo "Only the svnsync user can change revprops" >&2
exit 1

Als nächstes muss einmal eine initiale Syncronisation durchgeführt werden, damit sich beide Repositories das erste Mal abgleichen können.

svnsync init file:////srv/svn/repo_name svn+ssh://user@quellserver/srv/var/repo_name

Als nächstes muss die eigentliche Syncronisation der Repositories aufgerufen werden. Auch dies funktioniert mit einem Befehl:

svnsync sync file:///srv/svn/repo_name

Da sich hier die Repositories durch das Initial-Sync schon kennen, muss der Quell-Server nicht mehr angegeben werden. Damit der Abgleich der Subversion-Repositories nicht immer per Hand durchgeführt werden muss, habe ich den svnsync-Befehl in die Crontab per crontab -e mit aufgenommen. Damit findet stündlich ein Abgleich statt:

0 * * * * svnsync sync file:///srv/svn/repo_name

Eine weitere Idee entstand dabei. Es wäre schön, wenn wir das Repository per Browser durchsuchen könnten. Dafür existiert das Projekt “WebSVN“, welches sich unter Debian sehr einfach per apt-get install websvn installieren läßt. Es handelt sich um eine PHP-Anwendung, die sich alternativ aber auch einfach in ein Apache-Webverzeichnis extrahieren läßt. Zwei Anpassungen habe ich dabei noch durchgeführt. Zum einen wollte ich nicht, dass jeder den Code der Repositories sehen kann. Eine Anmeldung sollte her. Dafür nutze ich die Standard-Authentifizierung des Apache. Ich habe als erstes ein neues Passwort-File erzeugt:

htpasswd -cm /etc/apache2/dav_svn.passwd user1

Der Befehl fragt anschließend das Passwort ab und erzeugt eine Hash-Datei unter /etc/apache2/dav_svn.passwd. Weitere User können zu der Datei hinzugefügt werden. Dies funktioniert mit dem gleichen Befehl, allerdings ohne die -c Option, da diese immer eine neue Datei erstellt.

htpasswd -m /etc/apache2/dav_svn.passwd user2

Nun wird die Passwort-Datei dem DAV-Zugriff bekannt gemacht: In die Datei /etc/apache2/mods-enabled/dav_svn.conf oder einer .htaccess Datei werden folgende Zeilen benötigt:

AuthType Basic
AuthName "Subversion Repository"
AuthUserFile /etc/apache2/dav_svn.passwd
AuthzSVNAccessFile /etc/apache2/dav_svn.authz

Als zweite Anforderung werden nun alle Repositories des Servers angezeigt. Hier soll aber nur momentan unser aktuelles Projekt angezeigt werden. Dafür können einige Anpassungen in der Datei /etc/websvn/svn_deb.conf durchgeführt werden. Wenn mindestens ein Repository bereits auf dem Server existiert, kann die folgende Zeile auskommentiert werden. Diese zeigt nur ein Beispiel-Repository im Browser an.

// $config->addRepository("repos1", "file:///var/svn/");

Damit wird dieser Eintrag nicht mehr im WebSVN angezeigt, sondern nur noch alle Repositories, die sich auf dem Server befinden. Möchte man nun nur bestimmte Repositories ausgeben, ist folgende Zeile notwendig.

$config->addRepository("atari8", "file:///srv/svn/repo_name");

Damit können bestimmte Repositories, die angezeigt werden sollen, hinzugefügt werden. Für jedes weitere Repository ist diese Zeile einfach zu kopieren. Dennoch werden alle Repositories angezeigt. Grund dafür ist der Config-Parameter parentPath. Dieser sorgt dafür, dass alle Repositories durchsucht werden. Nach dem auskommentieren der folgenden Zeile werden nur noch die Repositories angezeigt, die per ->addRepository hinzugefügt wurden.

//$config->parentPath("/var/svn");

 


flashlight XPages und die Suche im Web

Ich habe an eienem größeren Projekt gearbeitet, welches eine native Lotus Notes Anwendung 1:1 um eine Web-Oberfläche erweitern sollte. Dies wurde mit Hilfe der XPages durchgeführt. An sich erst einmal eine schöne Sache, allerdings sind die XPages noch sehr buggy. Diese Fehler mussten umschifft werden.

Es wurde nun aktuell ein Defect des Kunden gemeldet. Die Suche in den XPages funktioniere nicht immer korrekt. Jede “Ansicht” besitzt ein Suchfeld, über das die Dokumente durchsucht werden können. Dies ist zunächst als reine Volltextsuche umgesetzt. Ich habe es mit den Tipps aus dem “XPages-Wiki” realisiert. Damit sollte eigentlich alles gefunden werden, nachdem gesucht wird.

Dem ist aber nicht so. Ich habe als erstes wieder daran gedacht, dass es sich um einen weiteren Bug in der XPages-Implementierung handelt, aber weit gefehlt. Nach längerem probieren und testen konnte ich erkennen, dass es sich immer um Zahlenfelder handelt, die nicht durchsucht werden. Ich habe dies auch im Notes-Client probiert und auch hier wurden keine Zahlen gefunden. In der Anwendung ist es aber gerade in der Web-Oberfläche wichtig, dass Kundennummern gefunden werden. Diese waren in Zahlenfelder abgelegt.

Nach einiger Recherche im Internet stieß ich dann auch darauf, dass das in Lotus Notes genauso umgesetzt ist. Datenbanken – auch wenn sie Volltext-Indiziert sind – werden nicht nach Zahlenfeldern durchsucht. Der Grund dafür ist mir noch nicht klar… Auf jeden Fall zieht sich dieses Problem bis in die XPages. Damit funktioniert meine Suche nicht.

Es gibt allerdings eine recht simpele Lösung für das Problem. In der Volltextsuche im Notes-Client können die Dokumente direkt auf die Inhalte bestimmter Felder durchsucht werden. Es handelt sich dann nicht mehr um eine Volltextsuche, sondern um eine Suche auf Basis z.B. eines Feldes. Dafür muss allerdings der suchende den Feldnahmen kennen und kann diesen dann mit in das Suchfeld eintragen. In etwa so:

[FN_Kundennummer]=123456

Damit werden dann alle Dokumente der Ansicht durchsucht und es werden alle Dokumente mit dem Zahlenfeld-Inhalt “123456″ angezeigt. Genau dieses funktioniert auch in den XPages. Allerdings nur, wenn es vom Programmierer so umgesetzt wird. Grundsätzlich kann in das Suchfeld nicht diese “Formel” eingetragen werden. Damit kommt der Domino-Server nicht zurecht. Wenn das Search-Property eines View-Panels allerdings so angepaßt wird, dass der Feldname vor den Suchstring gesetzt wird, funktioniert es, und die korrekten Dokumente werden angezeigt.

Da es sich bei mir um eine Ansicht sortiert nach Kundennummern handelt und der User im Grunde nur nach Kundennummer suchen möchte, habe ich das Ganze wie folgt umgesetzt. Ich habe eine weitere Such-Optimizer-Function geschrieben. Diese ruft die eigentliche Optimizer-Function auf und erweitert diese mit einem übergebenen Feld:

function searchOptimizeQuery_field(q:string, fieldname:string) {
    if (!q) return "";
    return "[" + fieldname + "]=" + searchOptimizeQuery(q);
}

Damit werden die Dokumente des ViewPanels dann nach Kundennummern durchsucht.

 

UPDATE:Leider habe ich noch etwas vergessen. Mit der oben genannten Umsetzung kann nur nach Zahlen gesucht werden. Wird ein Text eingegeben, erscheint ein Fehler. Um dieses zu lösen, prüfe ich als erstes, ob Suchstring tatsächlich eine Zahl ist. Dann wird das Suchquery wie oben beschrieben erweitert. Anderfalls wird eine normale Volltextsuche durchgeführt. Ich habe dies wie folgt gelöst:

function searchOptimizeQuery_field(q:string, fieldname:string) {
    if (!q) return "";

    if (IsNumeric(q) ) {
        return "[" + fieldname + "]=" + searchOptimizeQuery(q);
    } else {
        return searchOptimizeQuery(q);
    }
 }

function IsNumeric(input) {
    return (input - 0) == input && input.length > 0;
}

1092493__track Ein neuer Blog, ein neues Glück

Wer mich kennt, der weiß, dass ich schon diverse Blogs gestartet habe. Alle Blogs existieren aus verschiedenen Gründen nicht mehr. Der Hauptgrund war meist, dass die Blogs niemanden interessiert haben. Also verschwanden sie irgendwann endgültig aus dem Netz.

Ich starte nun einen neuen Versuch. Ich bin Software-Developer und springe – manchmal sogar täglich – zwischen diversen Programmiersprachen hin und her. Aus dem Grund kam die Idee auf über mein Programmiererleben zu schreiben und somit evtl. das eine oder andere Problem auch für “Mitleidende” Programmierer hoffentlich mit Lösung zur Verfügung stellen. Ich hoffe hierbei auch auf rege Beteiligung durch die Kommentarfunktion. Über mangelnde Kommentare in Blogs darf man sich ja nicht beschweren. Die Spammisten sorgen ja immer schön dafür, dass mittlerweile auch die Blogs zugemüllt werden. Ich habe alles dafür getan, dass die Spam-Kommentare sofort abgeblockt werden.

Also, ich freu mich auf spannende Beiträge. :)


Copyright © 1996-2010 A Programmer's Blog.... All rights reserved.
iDream theme by Templates Next | Powered by WordPress