system update :-/

Wer meine vergangenen Kurzbeiträge verfolgt hat, hat mitbekommen, dass ich mein System auf MacOS 10.6 aktualisiert habe.
Neben vielen Dingen die erstaunlich problemlos liefen, gibt es leider auch einige Probleme.
Manche davon ließen sich sehr einfach lösen:

  • Die fehlenden Java Versionen 1.4 bis 1.5 lassen sich einfach durch das manuelle Kopieren aus einem Backup wieder herstellen
  • Weiterhin gibt es einige Programme, die fehlerhaft, oder gar nicht liefen:
    • Cyberduck lief gar nicht – da gibt es mittlerweile eine lauffähige, neue Version auf der Homepage
    • BetterZip lief zwar, konnte aber keine tar.gz Files mehr lesen. Auch hier gibt es eine neue Version, siehe eine der letzten Posts
  • Was für mich viel störender ist, ist das Nicht-Funktionieren des gpgMails Plugins von Stéphane Corthésy, da ich hin und wieder doch gerne verschlüsselte Emails verschicke. Das das Plugin von der aktuellen Version von Mail.app deaktiviert wird, hat wohl 2 Gründe:
    1. Wird das aktuelle Mail.app standardmäßig als 64bit-Anwendung ausgeführt. Das gpgMail Plugin ist allerdings nur als 32bit Version kompiliert.
    2. Hat sich mit der neuen Version wohl auch die (undokemntierte) API von Mail.app geändert.

Jeder der einmal versucht hat, eine API anhand von Message Calls und vorhandenen Headern zu reverse-engeneeren kann wohl nachvollziehen, wieso Stéphane für eine weitere Runde dieser Arbeit keine Zeit hat. Aber da das Plugin als Source vorliegt, liegt es ja nahe, sich der Sache selbst anzunehmen. Zwar sind meine Objective-C Kenntnisse bei weitem noch nicht so gut, wie ich es gerne hätte, allerdings ist das Plugin zwar sehr gut in Mail.app eingefügt, allerdings dient es ja nur als Client für libgpg. Zudem sind die Sourcen wirklich gut kommentiert worden, sodass die Stellen, an denen man Snow-Leopard spezifischen Code einfügen müsste, sehr schnell deutlich werden :-).

Stéphane hat hierzu in dem Projektforum von sourceforge ein paar Hinweise gegeben. So werden für eine erfolgreiche Kompilierung von gpgMail zuerst einmal universal-binary(UB) (oder nur 64bit) Versionen von gpg, libgpg-error, libgpgme und dem MacGPGME framework benötigt.

Mein erster Versuch mit gpg,libgpg und libgpg-error über macports zu Installieren und danach per hardlinks von /opt auf /usr zu linken, brachte mir zumindest eine kompilierte 64bit Version vom MacGPGME framework. Ein UB lässt sich nicht kompilieren, da ich scheinbar von den libs nur eine expliziete 64bit Version besitze (womöglich müsste ich die hardlinks auch im lib64 Verzeichnis erstellen).

Momentan bin ich dabei das MacGPGME framework in einer UB Version zu erstellen. Was mich ein wenig gewundert hat ist, dass gpgMail scheinbar Header Dateien verlangt, welche das MacGPGME framework gar nicht hergibt.

Es ist zumindest vermeldet worden, dass ein weiterer Entwickler sich der Sache angenommen hat, der zumindest mehr Ahnung zu haben scheint als ich :-). Vielleicht werde ich mich dann mal bei ihm melden, so ich denn nennenswerte Fortschritte erreichen kann. Ist zu hoffen, dass die API Änderungen von Mail.app nicht zu gravierend sind….

Updating to Snow Leopard

Also machen wir es erstmal kurz.

Ich bin erstaunt wie problemlos das Update von 10.5 auf 10.6 von Statten ging.
Mein Ansatz war, das System neu aufzusetzen und dann per Migrations-Assistent meine Daten zu übertragen.
Was soll ich sagen? Nach jetzt gut 3 Stunden ist alles fertig.

Und bisher fand sich nur Cyberduck, welches die benötigte Java Version (1.5) nicht mehr findet.
Ja. Leider ist Java 1.5 nicht mehr vorhanden.
Dies ist in sofern schwerwiegend, weil es Sicherlich aus Entwicklersicht einige Gründe gibt, ein 1.5er JDK vor zu halten.
Ich bin gerade dabei zu versuchen das alte 1.5 JDK zu aktivieren.

Die gute Nachricht ist, dass nun endlich ja JDK 1.6 in 64bit UND 32bit vor zu finden ist :-).

Achja…noch erwähnenswert: Wer bei der Installtion das optionale Rosetta wieder installiert hat, kann nun immer noch PowerPC Code (jaja ganz old-school) ausführen. War für mich wichtig, weil es für meinen alten HP Scanner sonst keinen Treiber mehr gibt :-/.

GnuPG Java Wrapper API

Yaniv Yemini wrote a small GnuPG Java Wrapper API.
Just had a small look over it.
So to get it your version from here
Here is just a small demo:

import javax.swing.JOptionPane;
import org.gpg.java.GnuPG;
public class Loader {
    public static void main (String args[]){
        GnuPG pgp = new GnuPG ();
        String toolChain[] = {"sign", "clearsign", "signAndEncrypt", "encrypt", "decrypt"};
        String message = JOptionPane.showInputDialog(null, 
                                "Message you want to encrypt?", 
                                "Enter your message", 
                                JOptionPane.QUESTION_MESSAGE);
        String keyID = "0x56B69D6B";
        System.out.println("using message: "+message);
        System.out.println("using key ID: "+keyID);
        for(String tool : toolChain){
            System.out.println("running: "+tool);
            if(tool.equals("sign")){
                String passPhrase = enterPassPhrase(tool);
                pgp.sign (message, passPhrase);
            }
            if(tool.equals("clearsign")){
                String passPhrase = enterPassPhrase(tool);
                pgp.clearSign (message, passPhrase);
            }
            if(tool.equals("signAndEncrypt")){
                String passPhrase = enterPassPhrase(tool);
                pgp.signAndEncrypt (message, keyID, passPhrase);
            }
            if(tool.equals("encrypt")){
                pgp.encrypt (message, keyID);
            }
            if(tool.equals("decrypt")){
                String passPhrase = enterPassPhrase(tool);
                pgp.decrypt (message, passPhrase);
            }
            System.out.println("result: " + pgp.getGpg_result() + "nn");
            System.out.println("error: " + pgp.getGpg_err() + "nn");
            System.out.println("exit: " + pgp.getGpg_exitCode() + "nn");
        }
    }
    public static String enterPassPhrase(String usage){
        return JOptionPane.showInputDialog(null, 
                                "Please enter the Passphrase of your private Key for "+usage, 
                                "Passphrase", 
                                JOptionPane.QUESTION_MESSAGE);
    }
}

Unforntunetally there is a Problem with decrypting a message. It is possible to decrypt the String with the gpg CI Version, but within Java it does not work. So maybe the error is on my site :-).

advanced XML-Parser

Innerhalb unseres Projektes ist die Notwendigkeit entstanden, XML-Dokumente, die etwas umfangreicher als die Standard-Java-Deskriptoren sind, auf Gleichheit hin zu untersuchen.
Folgende XML-Strings sind gegeben:

A)

<items>
    <item name="a">
        <value>1</value>
    </item>
    <item name="b">
        <value>2</value>
    </item>
    <item name="c">
        <value>3</value>
    </item>
</items>

 

B)

<items>
    <item name="a">
        <value>1</value>
    </item>
    <item name="c">
        <value>3</value>
    </item>
    <item name="b">
        <value>2</value>
    </item>
</items>

 


Diese Untersuchung soll eine Aussagen über:

  • Gleichheit: (2 Dateien enthalten das gleiche XML-Modell
    • sowohl in der gleichen Reihenfolgen A)
    • als auch in einer anderen Reihenfolge B) ).
  • Veränderungen: welche Stellen sind verändert worden.

Während Forderung zwei sich noch mit einem einfachen String-Vergleich lösen lässt, ist Forderung eins nur durch das erkennen eines Modells lösbar.
Hierbei ist es notwendig, die einzelnen Knoten zu erkennen.
Zudem sind die zu-untersuchenden XML-Dateien > 5 MBb sodass viele – professionelle XML-Tools hier streiken müssen und mit Speicherfehlern aufgeben.
Der Ansatz der hier vorgestellt wird, setzt sich aus drei Stufen zusammen:

  1. SAX-basiertes Parsen der Datei und einlesen in eine Datenbank (aus Performance-Gründen wird hier H2 als inMemory Datenbank genutzt).
  2. Um schnelle Vergleiche zu ermöglichen wird ein Modell benutzt, welches u.a. auch in ZFS angewendet wird: Erkennen von Veränderungen anhand von Prüfsummen.
    Was bei ZFS dazu benutzt wird, um Änderungen innerhalb des Dateisystems zu erkennen, soll hier dazu dienen, Unterschieder zwischen zwei XML-Modellen schnell und zuverlässig zu erkennen.
    Hierzu wird für jeden Knoten eine Prüfsumme berechnet. Diese leitet sich jeweils aus den Prüfsummen seiner Kindsknoten, dem Inhalt seiner Attribute und dem Wert des Knotens ab.
    Momentan wird über diesen Gesamt-String ein SHA1-Hash gebildet. Eine weitere Prüfsumme wird benötigt, um den Knoten innerhalb des Modells zu lokalisieren (wir verwenden hier den XML-Path+Knotennummer):
  3. <--                   Hash des Pfades                   -->
            3a52ce780950d4d969792a2559cd519d7ee8c727
            ./items/value
  4. <--             Hash des Knotens item              -->
            481e6ff69a8402231a3b9c6e46a7fef4f09adbb3
            hash von: "item", attribute "name=b", hash von "value"
  5. Da sowohl eine Aussage über Unterschied im sortierten Zustand – die Reihenfolge der (Kinder-)Knoten ist wichtig – als auch im unsortierten Zustand (Die Reihenfolge der Kinder-)Knoten ist egal,
    wird vor dem Berechnen des Hashes des Kindes eines Knotens, die Kinder einmal unsortiert und einmal sortiert als Basis für den SHA1-Hash genommen.

Momentan ist das Datenmodell soweit vollständig, die Knotenwerden beim Parsen in die Datenbank eingelesen. Dieser Vorgang wird momentan noch hinsichtlicher Dauer und Speicherverbrauch optimiert. Auch eine aussagekräftige Fortschrittanzeige sollte eingebaut werden. Danach muss der Algorithmus zum Erkennen der unterschiedlichen Stellen implementiert werden.
Als letztes sollen diese Unterschiede in einer übersichtlichen und – für große Dokumente – gut navigierbaren GUI angezeigt werden.

sophisticated Backups mit Rsync Part II

Version 3.1
Features:

  • Logs werden nun gzip komprimiert
  • wöchentliche Backups aus der vorherigen Woche werden tar.gz komprimiert

 

#!/bin/sh

# Philipp's backup-scripte version 3.1

ROOT=`pwd`
BACKDIR=$ROOT/backup

D=`eval date +%Y-%m-%d`
W=`eval date +%Y-%W`
w=`eval date +%w`
LATEST="latest"
EXCLUDE=$ROOT/exclude.txt
SOURCES=$ROOT/sources.txt

LOG=$ROOT/log/$D.log

# Array mit allen ben‚‚tigten Verzeichnissen und Ordnern
folders=( $ROOT/log )
files=( $EXCLUDE $SOURCES $LOG)

for folder in ${folders[@]}; do
    if [ ! -d $folder  ] ; then mkdir -p $folder; fi
done

for file in ${files[@]}; do
    if [ ! -f $file  ] ; then touch $file; fi
done

log () {
    if [  -z "$1" ] ; then echo "" > $LOG ; fi
    echo $1
    echo $1 >> $LOG    
}

# needs Hostname
gzipLastWeekly (){
    log "=================================================================="
    log "compress...";
    echo $1
    ROOT=`pwd`
    L_BACKDIR="$ROOT/backup/$1/weekly"; 
    if [ -d $L_BACKDIR ] ; then    
        NUM=${#L_BACKDIR}+1;
        L_LATEST=`ls -al $L_BACKDIR/latest`
        L_FOLDER="${L_LATEST#*-> }";
        L_FILE="${L_LATEST#*-> }";
        L_FILENAME="${L_FILE:$NUM:7}";
        log "L_BACKDIR $L_BACKDIR";
        #log "L_LATEST $L_LATEST";
        log "L_FOLDER $L_FOLDER";
        log "L_FILE $L_FILE";
        log "L_FILENAME $L_FILENAME";
        log "=================================================================="          
        if [ -d $L_FOLDER ] ; then
            if [ $L_FILENAME != "$W" ]; then
                log "compress  $L_FOLDER";
                cd $L_BACKDIR
                tar -cvf - $L_FILENAME/ | gzip > $L_FILENAME.tar.gz  | tee -a $LOG
                cd $ROOT
                rm -R $L_FOLDER
                log "MD5: "
                log "=================================================================="
                md5 $L_BACKDIR/$L_FILENAME.gz -out $LOG;
                log "=================================================================="
            fi
        fi    
    fi
    log "...done";
    log "==================================================================" 
}

# Ab hier gehts dann richtig los :-)

log

log "STARTING BACKUP..."
log "date: $D"

#stopping start time
#TIME0= expr `date +%s`;

# backup following sources
for SOURCE in `cat $SOURCES`; do
    log ""
    log "=================================================================="
    log "====== backup: $SOURCE "
    if [ ! -d $BACKDIR/$SOURCE/daily/$D  ] ; then mkdir -p $BACKDIR/$SOURCE/daily/$D; fi    
    if [ ! -f $BACKDIR/$SOURCE/src-root.txt  ] ; then touch $BACKDIR/$SOURCE/src-root.txt; fi    
    if [ ! -f $BACKDIR/$SOURCE/src-folders.txt  ] ; then touch $BACKDIR/$SOURCE/src-folders.txt; fi      
    #Logindaten lesen
    LOGINDATA=`cat $BACKDIR/$SOURCE/src-root.txt`
    if [ ! "$LOGINDATA" = "" ]; then
        log "====== benutze $LOGINDATA" 
        log "=================================================================="
        log ""
        for FOLDER in `cat $BACKDIR/$SOURCE/src-folders.txt`; do
            log "backup up... $FOLDER"
            mkdir -p $BACKDIR/$SOURCE/daily/$D/$FOLDER
            ### wenn schon latest-day vorhanden, dann sichere nur ‚nderungen
            if [ -d $BACKDIR/$SOURCE/daily/$LATEST  ] ; then 
		        log "using latest: $BACKDIR/$SOURCE/daily/$LATEST"
                rsync -zrva $OLD --exclude-from=$EXCLUDE --link-dest=$BACKDIR/$SOURCE/daily/$LATEST/$FOLDER  $LOGINDATA/$FOLDER/ $BACKDIR/$SOURCE/daily/$D/$FOLDER | tee -a $LOG
            else
                rsync -zrva $OLD --exclude-from=$EXCLUDE $LOGINDATA/$FOLDER/ $BACKDIR/$SOURCE/daily/$D/$FOLDER | tee -a $LOG
            fi   	
        done

        ### setze latest von altem Stand auf aktuelles Backup
        if [ -d $BACKDIR/$SOURCE/daily/$D ] ; then
            log "Daily: deleting ln last daily latest: $BACKDIR/$SOURCE/daily/$LATEST"
            if [ -d $BACKDIR/$SOURCE/daily/$LATEST ] ; then rm $BACKDIR/$SOURCE/daily/$LATEST; fi
            log "Daily: updating ln daily latest: $BACKDIR/$SOURCE/daily/$LATEST"
            ln -s $BACKDIR/$SOURCE/daily/$D $BACKDIR/$SOURCE/daily/$LATEST | tee -a $LOG     
            log "Daily: deleting ln last daily latest: $BACKDIR/$SOURCE/$LATEST"
            if [ -d $BACKDIR/$SOURCE/$LATEST ] ; then rm $BACKDIR/$SOURCE/$LATEST; fi
            log "Daily: updating ln daily latest: $BACKDIR/$SOURCE//$LATEST"
            ln -s $BACKDIR/$SOURCE/daily/$D $BACKDIR/$SOURCE/$LATEST | tee -a $LOG     
        fi

        ### setze latest-global von altem Stand auf aktuelles Backup
        log "Daily: deleting ln last global latest: $BACKDIR/$SOURCE/$LATEST"
        if [ -d $BACKDIR/$SOURCE/$LATEST ] ; then 
            rm $BACKDIR/$SOURCE/$LATEST;
        fi            
        log "Daily: updating ln global latest"
        ln -s $BACKDIR/$SOURCE/daily/$D $BACKDIR/$SOURCE/$LATEST | tee -a $LOG 

        ## wenn ende der Woche, dann erstelle Snapshot der Woche
        if [ "$w" = "0" ]; then
            log "Weekly: create week-backup for $W"
            for FOLDER in `cat $BACKDIR/$SOURCE/src-folders.txt`; do
                mkdir -p $BACKDIR/$SOURCE/weekly/$W/$FOLDER
                rsync -zrva $OLD --exclude-from=$EXCLUDE $BACKDIR/$SOURCE/daily/$D/$FOLDER/ $BACKDIR/$SOURCE/weekly/$W/$FOLDER | tee -a $LOG
            done

            ### komprimiere letztes week Backup
            log "==================================================================" 
            log "Weekly: compressing last weekly latest"
            gzipLastWeekly $SOURCE

            ### setze latest-day von altem Stand auf aktuelles Backup
            log "Weekly: deleting ln last daily latest: $BACKDIR/$SOURCE/daily/$LATEST"
            if [ -d $BACKDIR/$SOURCE/daily/$LATEST ] ; then 
                rm $BACKDIR/$SOURCE/daily/$LATEST;
            fi

            ### loesche alte Backups
            log "Weekly: delete all daily folders"
            rm -R $BACKDIR/$SOURCE/daily/*

            log "Weekly: updating ln daily latest: $BACKDIR/$SOURCE/daily/$LATEST"
            ln -s $BACKDIR/$SOURCE/weekly/$W $BACKDIR/$SOURCE/daily/$LATEST | tee -a $LOG            

            ### setze latest-week von altem Stand auf aktuelles Backup
            log "Weekly: deleting ln last weekly latest: $BACKDIR/$SOURCE/weekly/$LATEST"
            if [ -d $BACKDIR/$SOURCE/weekly/$LATEST ] ; then 
                rm $BACKDIR/$SOURCE/weekly/$LATEST;
            fi

            log "Weekly: updating ln weekly latest"
            ln -s $BACKDIR/$SOURCE/weekly/$W $BACKDIR/$SOURCE/weekly/$LATEST | tee -a $LOG 

            ### setze latest-global von altem Stand auf aktuelles Backup
            log "Weekly: deleting ln last global latest: $BACKDIR/$SOURCE/$LATEST"
            if [ -d $BACKDIR/$SOURCE/$LATEST ] ; then 
                rm $BACKDIR/$SOURCE/$LATEST;
            fi            
            log "Weekly: updating ln global latest"
            ln -s $BACKDIR/$SOURCE/weekly/$W $BACKDIR/$SOURCE/$LATEST | tee -a $LOG 
        fi
    fi
done

#stopping end time
#TIME1= expr `date +%s`;
#ERG = expr `$TIME1 - $TIME0`;

log "=================================================================="
log "DONE"
#log "using $ERG seconds"
log "=================================================================="

gzip $LOG -f

 

instant jruby & derby environment für eine RoR Anwendung

Als angestammter Java-Entwickler geht es mir oftmals schwer von der Hand, einer Ruby on Rails (RoR) Anwendung mit relativ wenig Aufwand eine brauchbare Laufzeitumgebung zu bieten.
Normalerweise sollte das OS (MacOS 10.5.6) alles Brauchbare bieten. So ist oftmals eine Rails-Version installiert und auch das (standardmäßig genutzte) SQlite 3 ist vorhanden.
Dennoch sind es oftmals Plugins (spezielle Rails Version / spezielle gems), welche einen zusätzlichen Aufwand benötigen.
Nicht zu vergessen, dass RoR nicht auf allen Systemen vorinstalliert ist und dementsprechend ein interessierter Entwicklung von einem Out-of-the-Box Erlebnis weit entfernt ist.
Sehen wir den Tatsachen ins Auge… die Wahrscheinlichkeit eine installierte JVM vorzufinden ist (noch?) deutlich höher, als eine Lauffähige Ruby-Installation.
Was liegt also näher, als die benötigte Umgebung auf Java fußen zu lassen.
Hierzu werden verwendet:

  • jRuby in Version 1.1.5 (http://jruby.codehaus.org)
  • Derby-DB in Version 10.4.2.0 (http://db.apache.org/derby)
  • weiterhin wird eine installierte JVM (>1.5) vorrausgesetzt

 

Alles weitere wird mit Hilfe von shell-Scripten bewerkstelligt. Wobei momentan nur Unix-Scripte benutzt werden. Eine Portierung auf Windows sollte aber nur eine Sache von Minuten sein.
Es liegt eine RoR-Anwendung in einem Entwicklungs-Status vor. Diese wurde bisher in einem Netbeans-Enviroment mit einer SQlite-DB betrieben.
Das Verzeichnis ist folgendermaßen aufgebaut:

ROOT
|
|- microblog (dies ist unsere RoR-Anwendung)
|
|- derby (derby-installtion - es werden jeweils das bin und lib Verzeichnis benötigt)
| |-bin
| |-lib
|
|- jruby (jruby-installtion - es werden jeweils das bin und lib Verzeichnis benötigt)
| |-bin
| |-lib

Das Hauptproblem besteht darin, dass alle benötigten gems in das entsprechende Unterverzeichnis installiert werden müssen.
Weiterhin muss die Derby-DB mit dem entsprechenden Rake-Task auf mit der aktuellen Schema-Datei instanziiert werden.
Zuletzt sollen die vorhandenen User-Daten in die Derby-DB eingefügt werden.

  1. Anpassen der database.yml
    Wir nutzen weiterhin eine jdbc-Connection. Allerdings ändert sich der Treiber auf den der Derby-DB:
    database.yml

    development:
    adapter: jdbc
    driver: org.apache.derby.jdbc.ClientDriver
    url: jdbc:derby://localhost/microblog_development;create=true
    encoding: utf8
    pool: 5
    username: microblog
    password: microblog
    host: localhost
  2. Export der alten DB-Daten:
    Wir benutzen hierzu das Tool sqlitebrowser (http://sqlitebrowser.sourceforge.net) und erzeugen uns so einen SQL-Dump der alten SQLite-DB. Wir benutzen hierbei nur die SQL-Inserts für den User-Import. Diese speichern wir in die Datei:
    microblog/db/microblog.sql
  3. Für den Import erstellen wir einen Rake-Task:
    microblog/lib/tasks/sql-import.rake

    namespace :microblog do
    desc 'Import old SQL Data'
    task :sqlimport => :environment do
    dbConn = ActiveRecord::Base.establish_connection :development
    sql = File.open("db/microblog.sql").read
    sql.split(';').each do |sql_statement|
    dbConn.connection.execute(sql_statement)
    end
    puts "imported user data '#{Time.now}' "
    end
    end
  4. Erstellen des Setup-Scriptes:
    Folgende Schritte sind notwendig:

    1. Setzen aller benötiger Verzeichnisse
    2. installieren aller benötigter gems
    3. Starten des Derby-DB-Servers
    4. Rake db:migrate
    5. import der alten Daten
    6. Beenden des Derby-DB-Servers

    Das Script sieht wie folgt aus:
    jruby-setup.sh

    #!/bin/sh
    BASE_DIR=`pwd`
    CP=".:$BASE_DIR/jruby/lib/*:$BASE_DIR/derby/lib/derbyclient.jar"
    JAVA_OPTS="-Djdbc.drivers=org.apache.derby.jdbc.EmbeddedDriver"
    JRUBY="$BASE_DIR/jruby/bin/jruby"
    DERBY_HOME=`cd derby && pwd`
    export DERBY_HOME=$DERBY_HOME
    cd $BASE_DIR
    echo "setting up jgems..."
    $BASE_DIR/jruby/bin/jruby $BASE_DIR/jruby/bin/jgem update --system
    $BASE_DIR/jruby/bin/jruby $BASE_DIR/jruby/bin/jgem install jruby-openssl --no-rdoc --no-ri
    $BASE_DIR/jruby/bin/jruby $BASE_DIR/jruby/bin/jgem install -v=2.2.2 rails --no-rdoc --no-ri
    $BASE_DIR/jruby/bin/jruby $BASE_DIR/jruby/bin/jgem install activerecord-jdbc-adapter activerecord-jdbcderby-adapter --no-rdoc --no-ri
    echo "starting derby..."
    $BASE_DIR/derby/bin/startNetworkServer &
    echo "setting up derby..."
    cd microblog
    $BASE_DIR/jruby/bin/jruby $BASE_DIR/jruby/bin/rake db:migrate
    $BASE_DIR/jruby/bin/jruby $BASE_DIR/jruby/bin/rake microblog:sqlimport
    cd $BASE_DIR
    echo "stopping derby..."
    $BASE_DIR/derby/bin/stopNetworkServer &

    Es ist zu erwähnen, dass es notwendig ist, jeweils auf die entsprechende jRuby-Installation zu verweisen.
    Weiterhin benötigt jRuby den entsprechenden derbyClientDriver, welcher in die (von jRuby später verwendete) JAVA_OPTS-Variabel eingetragen wird.
    Ebenfalls musst der Classpath soweit angepasst werden, dass sowohl jRuby, als auch Derby über die notwendigen Bibliotheken verfügen.
    Als letztes ist noch erwähnenswert, dass die beiden Rake-Tasks jeweils aus dem App-Verzeichnis ausgeführt werden.

  5. Das Start-Script.
    Letzendlich sind auch zum eigentlichen Betrieb des Servers Anpassungen notwendig, da auch hier die jRuby-Instanz mit den verwendeten gems benutzt werden sollen.
    Das Script sieht wie folgt aus:
    run.sh

    #!/bin/sh
    BASE_DIR=`pwd`
    CP=".:$BASE_DIR/jruby/lib/*:$BASE_DIR/derby/lib/derbyclient.jar"
    JAVA_OPTS="-Djdbc.drivers=org.apache.derby.jdbc.EmbeddedDriver"
    JRUBY="$BASE_DIR/jruby/bin/jruby"
    export BASE_DIR=$BASE_DIR
    export JRUBY=$JRUBY
    DERBY_HOME=`cd derby && pwd`
    export DERBY_HOME=$DERBY_HOME
    cd $BASE_DIR
    echo "starting derby..."
    $BASE_DIR/derby/bin/startNetworkServer &
    echo "setting up derby..."
    cd microblog
    $BASE_DIR/jruby/bin/jruby $BASE_DIR/jruby/bin/rake db:migrate
    echo "starting microblog"
    $BASE_DIR/jruby/bin/jruby $BASE_DIR/microblog/script/server
    echo "stopping derby..."
    $BASE_DIR/derby/bin/stopNetworkServer &

    Es entspricht also einer abgespeckten Variante des Setup-Scriptes. Hierbei wird auch immer ein db:migrate aufgerufen, für den Fall, dass sich die DB-Struktur in der Zwischenzeit geändert haben sollte.

  6. Auslieferung ;-).
    Derby und jRuby belegen knapp 80 MB sodass es notwendig ist, die Dateigröße für den Transport zu verringern.
    Zuallererst sollten die benötigten gems am besten immer online bezogen werden, sodass man hier ein paar MB sparen kann.
    Weiterhin benutzen wir Jar um die vorhandenen Dateien auf ein 13 MB-Archiv zu packen.
    Die veränderten Scripte sehen wie folgt aus:
    Zuerst das Script, welches die vorhandenen Dateien packt:
    pack.sh

    #!/bin/sh
    find . -name '*.DS_Store' -type f -delete
    jar -cvf statusQ-runtime.jar derby/ jruby/ run.sh pack.sh microblog/db/microblog.sql microblog/lib/tasks/sql-import.rake
    rm -R jruby
    rm -R derby
    rm run.sh
    rm microblog/db/microblog.sql
    rm microblog/lib/tasks/sql-import.rake
    rm pack.sh

    Und nun das geänderte jruby-setup.sh Script, welches vor dem eigentlichen Setup noch für das Entpacken aller Dateien verantwortlich ist:
    jruby-setup.sh

    #!/bin/sh
    jar -xvf statusQ-runtime.jar
    rm -R META-INF
    chmod +x run.sh
    chmod +x setup.sh
    chmod +x pack.sh
    chmod +x jruby/bin/jruby
    chmod +x derby/bin/startNetworkServer
    chmod +x derby/bin/stopNetworkServer
    BASE_DIR=`pwd`
    CP=".:$BASE_DIR/jruby/lib/*:$BASE_DIR/derby/lib/derbyclient.jar"
    JAVA_OPTS="-Djdbc.drivers=org.apache.derby.jdbc.EmbeddedDriver"
    JRUBY="$BASE_DIR/jruby/bin/jruby"
    DERBY_HOME=`cd derby && pwd`
    export DERBY_HOME=$DERBY_HOME
    cd $BASE_DIR
    echo "setting up jgems..."
    $BASE_DIR/jruby/bin/jruby $BASE_DIR/jruby/bin/jgem update --system
    $BASE_DIR/jruby/bin/jruby $BASE_DIR/jruby/bin/jgem install jruby-openssl --no-rdoc --no-ri
    $BASE_DIR/jruby/bin/jruby $BASE_DIR/jruby/bin/jgem install -v=2.2.2 rails --no-rdoc --no-ri
    $BASE_DIR/jruby/bin/jruby $BASE_DIR/jruby/bin/jgem install activerecord-jdbc-adapter activerecord-jdbcderby-adapter --no-rdoc --no-ri
    echo "starting derby..."
    $BASE_DIR/derby/bin/startNetworkServer &
    echo "setting up derby..."
    cd microblog
    $BASE_DIR/jruby/bin/jruby $BASE_DIR/jruby/bin/rake db:migrate
    $BASE_DIR/jruby/bin/jruby $BASE_DIR/jruby/bin/rake microblog:sqlimport
    cd $BASE_DIR
    echo "stopping derby..."
    $BASE_DIR/derby/bin/stopNetworkServer &

Als nächstes sollte die Scripte auf Windows portiert werden.
Weiterhin wäre es interessant, die Derby/jRuby Binaries jeweils direkt online zu beziehen.