Fixing Error “failed, reason: getaddrinfo EAI_AGAIN” in Gitlab Builds

Flattr this!

Some days ago, I detected some new errors in one of our builds pipelines. The interesting part is, that there were no changes done, that might have caused this error.
One example for this error was an DNS resolution error using npm:

#9 [4/5] RUN npm i npm@latest
#9 71.06 npm ERR! code EAI_AGAIN
#9 71.06 npm ERR! syscall getaddrinfo
#9 71.06 npm ERR! errno EAI_AGAIN
#9 71.06 npm ERR! request to https://registry.npmjs.org/npm failed, reason: getaddrinfo EAI_AGAIN registry.npmjs.org
#9 71.06 
#9 71.06 npm ERR! A complete log of this run can be found in:
#9 71.06 npm ERR!     /root/.npm/_logs/2023-02-10T08_30_43_730Z-debug-0.log
#9 ERROR: executor failed running [/bin/sh -c npm i npm@latest]: runc did not terminate sucessfully

After some digging, I found out, that the only update might have come with an updated docker build behaviour, since the docker image, used in this job is docker:latest.

Some Google queries later, I found an issue realted to this topic. It points to a blog post about a strange behaviour of docker in regards to DNS. But since, I had no issues before, I ruled out, that this might be the case here.

And indeed, a look in the latest release notes pointed out the obvious:

Alias docker build to docker buildx build

docker/cli#3314

The easiest fix was to disable buildx alltogether via these ENV Vars:

build:
  image: docker:latest
  stage: build
  variables:
    DOCKER_BUILDKIT: 0
    COMPOSE_DOCKER_CLI_BUILD: 0
  services:
    - docker:dind
  before_script:
…
  script:
…

After this change, the build job did run without any errors.

Disable GitHub Image Cache for CI Build Badges

Flattr this!

Since some time, GitHub caches Images, that are linked in Wiki-Pages or Readme files.
That’s not optimal, when you want to display current states (e.g. the Build Status of your CI Job).

To disable the Caching for a specific Image, you need to configure a proper Caching Header.
So before the Changes, you have:

$ curl -L -I https://consolving.de/jenkins/buildStatus/icon?job=de.consolving.chatlogconverter
    HTTP/1.1 200 OK
    Date: Sun, 03 Aug 2014 10:08:44 GMT
    Server: Jetty(8.y.z-SNAPSHOT)
    ETag: /static/e5920a00/success.png
    Expires: Sun, 01 Jan 1984 00:00:00 GMT
    Content-Type: image/png
    Content-Length: 2339
    Via: 1.1 consolving.de

That means GitHub will cache the Image (for some time), although the Expires Header is set to the past.
In our case, the Jenkins CI is behind an Apache2 Server. So you need to update your Configuration.

  ...
  # Disable Cache for /jenkins/buildStatus
  <LocationMatch "/jenkins/buildStatus/icon*">
    Header set Cache-Control "no-cache"
    Header set Pragma "no-cache"
  </LocationMatch>
  ...

After that, you have now some more Caching Headers set and GitHub won’t Cache your image anymore.

$ curl -L -I https://consolving.de/jenkins/buildStatus/icon?job=de.consolving.chatlogconverter
HTTP/1.1 200 OK
Date: Sun, 03 Aug 2014 10:13:16 GMT
Server: Jetty(8.y.z-SNAPSHOT)
ETag: /static/e5920a00/success.png
Expires: Sun, 01 Jan 1984 00:00:00 GMT
Content-Type: image/png
Content-Length: 2339
Via: 1.1 consolving.de
Cache-Control: no-cache
Pragma: no-cache

Build and Test Project TOX under MacOS

Flattr this!

Some Steps to do

  1. You need to have XCode with installed CLI Tools (see here)
  2. If you are using MacPorts (you really should), you need to install all necessary Dependencies:
    port install libtool automake autoconf libconfig-hr libsodium cmake
  3. Checkout the Project TOX Core Repository:
    git clone --recursive https://github.com/irungentoo/ProjectTox-Core.git
  4. cd ProjectTox-Core
    cmake .
    make all
  5. You need two tools:
    DHT_bootstrap in /other
    and nTox in /testing
  6. Bootstrap Tox (aka get your Public Key):
    ./DHT_bootstrap
    Keys saved successfully
    Public key: EA7D7BD2566A208F83F81F8876DE6C1BDC1F8CA1788300296E5D4F4CB142CD77
    Port: 33445

    The key is also in PUBLIC_ID.txt in the same Directory.

  7. Run nTox like so:
    ./ntox 198.46.136.167 33445 728925473812C7AAC482BE7250BCCAD0B8CB9F737BF3D42ABD34459C1768F854

    Where:

    Some Tox Node
    198.46.136.167
    Port of that TOX Node
    33445
    Public Key of that TOX Node
    728925473812C7AAC482BE7250BCCAD0B8CB9F737BF3D42ABD34459C1768F854
  8. Et voilà:
    /h for list of commands
    [i] ID: C759C4FC6511CEED3EC846C0921229CA909F37CAA2DCB1D8B31479C5838DF94C
    >>

    You can add a friend:

    /f ##PUBLIC_ID##

    List your friends:

    /l

    Message a friend:

    /m ##friend_list_index##  ##message##

maven is not ant

Flattr this!

Neben vielen berechtigten Kritikpunkten die manch einer dem Build-Tool Maven vorwerfen kann, ist oftmals der falsche Einsatz einer der Hauptgründe für die schlechte Perfomance (d.h. lange Build-Zeiten) die fehlerhafte Nutzung von Maven Features.

Oft sieht man, dass Module untereinander durch relative Pfadangaben verknüpft sind. Dies mag bei Ant-Builds ein gängiges Mittel sein, aber wenn man sich vor Augen hält, dass jeder Modul eines Projektes für sich genommen ausgecheckt und gebaut werden können soll, so ist klar, dass man eine abstractere Art und Weise benötigt, einzelne Module miteinander zu verbinden.

Und auch hierfür eignet sich das Mitte der Dependencies. Zu einem vollständigen (und nützlichem) Maven-Build-System gehört zwangsläufig auch ein (eigenes) funktionierendes Maven-Repository (sei es nun Archiva oder Nexus). So ein Repository dient nicht nur zum Lagern von Artefakten, sondern auch als Dreh- und Angelpunkt der einzelnen Module untereinander.

Nehmen wir an, ein Projekt besitzt folgende Struktur:

Root
  |-Modul A
  |-Modul B
    |-Modul C

Nehmen wir weiterhin an, dass Modul A von C abhängt, weil C zum Beispiel XSD Scripte enthält, die separat von einem Fachler aktualisiert werden, aber für die Generierung von Java-Klassen in A benötigt werden.

Würde es nach Ant-Manier gehen, so wäre folgendes denkbar:

<project>
...
    <build>
        <plugins>
            ...
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>xmlbeans-maven-plugin</artifactId>
                <version>2.3.3</version>
                <executions>
                    <execution>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>xmlbeans</goal>
                        </goals>
                    </execution>
                </executions>
                <inherited>true</inherited>
                <configuration>
                    ...
                    <schemaDirectory>../B/C/xsd</schemaDirectory>
                    <classGenerationDirectory>${project.build.directory}/classes</classGenerationDirectory>
                </configuration>
            </plugin>
            ...
        </plugins>
    </build>
...
</project>

Dies dürfte aber spätestens beim Release Build scheitern, weil hier jedes Modul für das Releas separat innerhalb des eigenen Target-Dirs ausgecheckt wird (spätestens hier kommt es dann mit den relativen Pfaden nicht mehr hin).

Was also tun?
Abhilfe schaft das maven-dependency-plugin, welches dem aktuellen Modul erlaub direkt auf die Daten eines einzelnen Artefacts zugreifen zu können. Damit das Artefact durch das Plugin verarbeitet werden kann, sollte es (logischerweise) auch als Dependency im eingetragen sein. So ist sogar sicher gestellt, dass immer der aktuellste Codestand verwendet wird, denn sollt ein Artefact im Repository neuere sein als das, welches lokal vorgehalten wird, so wird dieses heran gezogen.

Die obige Konfiguration würde sich also wie folgt ändern:

<project>
...
    <dependencies>
        ...
        <dependency>
            <groupId>com.example</groupId>
            <artifactId>C</artifactId>
            <version>${project.version}</version>
        </dependency>
        ...
    </dependencies>
    <build>
        <plugins>
            ...
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>2.3</version>
                <executions>
                    <execution>
                        <id>src-dependencies</id>
                        <phase>generate-sources</phase>
                        <goals>
                            <!-- use copy-dependencies instead if you don't want to explode the
                                sources -->
                            <goal>unpack</goal>
                        </goals>
                        <configuration>
                            <artifactItems>
                                <artifactItem>
                                    <groupId>com.example</groupId>
                                    <artifactId>C</artifactId>
                                    <version>${project.version}</version>
                                    <classifier>resources</classifier>
                                    <type>zip</type>
                                    <includes>**/*.xsd</includes>
                                    <overWrite>true</overWrite>
                                    <outputDirectory>${project.build.directory}/C</outputDirectory>
                                </artifactItem>
                            </artifactItems>
                        </configuration>
                    </execution>
                </executions>
            </plugin>            
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>xmlbeans-maven-plugin</artifactId>
                <version>2.3.3</version>
                <executions>
                    <execution>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>xmlbeans</goal>
                        </goals>
                    </execution>
                </executions>
                <inherited>true</inherited>
                <configuration>
                    ...
                    <schemaDirectory>${project.build.directory}/C/xsd</schemaDirectory>
                    <classGenerationDirectory>${project.build.directory}/classes</classGenerationDirectory>
                </configuration>
            </plugin>
            ...
        </plugins>
    </build>
...
</project>

Zu beachten ist hier, dass die Reihenfolge der beiden Plugins wichtig ist, weil ansonsten die Code-Generierung nicht auf die entpackten Dateien der Dependency zugreifen kann. Ich gebe zu, es handelt sich hier um ein einfaches Beispiel, aber zumindest der Drang, sich durch relative Pfade innerhalb von Maven-Files zu helfen ist meiner Beobachtung nach recht weit verbreitet :-/.

Show Build-Information in your iOS App About Panel

Flattr this!

Sometimes it might be useful to have an exact piece of information about what version of an app you have currently running. Especially if you have a decent Testing-Group, it is important to track the versions in which a bug appears. The goal of this post is to achieve a info panel like this in your application.
You get the Application version (from the Application Bundle), the Repository Revision and the Date of the last Commit.

Picture 1: Example Application About Dialog

 

We are using here the build-in functions of subversion to update given keywords with the repository information. More about this topic here. There is also a way to use this method with git, but i did not test it yet. You may find out more about this here
The first step is to create a File-Template you can import in your code, with which you can access all the necessary details:

#define APP_VERSION   
[[[NSBundle mainBundle] infoDictionary]   
objectForKey:@"CFBundleVersion"]
#define APP_EXECUTABLE   
[[[NSBundle mainBundle] infoDictionary]   
objectForKey:@"CFBundleExecutable"]
#define APP_NAME   
[[[NSBundle mainBundle] infoDictionary]   
objectForKey:@"CFBundleName"]
#define APP_BUILD_REVISION @"$Rev$"
#define APP_BUILD_DATE @"$Date$"
#define APP_LAST_AUTHOR @"$Author$"

Code 1: version.h template
The next step is to tell Subversion to replace the placeholder with the subversion values.
You can do this with setting the subversion keyword for that file.
After that, with every commit of the file “version.h” the values will be updated.

svn propset svn:keywords 'Revision Author Date' version.h

Code 2: version.h template
The very last step is to make sure, that “version.h” will be updated each time you make a change to your application. Assuming you build your app every time you made a change, you can use the functions, build into Xcode to force an update on “version.h”. We use the trick, that every change on the propsets of “version.h” is equal to a file modification itself.
So we create a small bash script, setting the propset “build” to a new value. After that, “version.h” needs to be commited as a new version.

#!/bin/sh
DATE=`date`
HOST=`hostname`
svn propset build "$HOST $DATE" Version.h

Code 3: buildUpdate.sh
Now we need to add the run of “buildUpdate.sh” to our Build-Cycle. (Picture 2 & Picture 3).

Picture 2: Project Target Settings

 


Picture 3: Insert Script Call

After a successful commit, the file “version.h” will look something like this:

#define APP_VERSION   
[[[NSBundle mainBundle] infoDictionary]   
objectForKey:@"CFBundleVersion"]
#define APP_EXECUTABLE   
[[[NSBundle mainBundle] infoDictionary]   
objectForKey:@"CFBundleExecutable"]
#define APP_NAME   
[[[NSBundle mainBundle] infoDictionary]   
objectForKey:@"CFBundleName"]
#define APP_BUILD_REVISION @"$Rev: 1047 $"
#define APP_BUILD_DATE @"$Date: 2011-01-21 18:53:38 +0100 (Fri, 21 Jan 2011) $"
#define APP_LAST_AUTHOR @"$Author: phaus $"

Code 4: updated version.h
You might modify the output (e.g. filter out the $s or reformat the date) to get a more stylish output.

creating JNI with Swig

Flattr this!

I am currently playing around with JNI and Java due the colleagues question to make the connect features of jack-audio (http://jackaudio.org) accessible to java.
There is already a javalib (http://jjack.berlios.de) with some features, there seems still some needes ones missing.
So i started today to have a look into SWIG (http://swig.org).
“SWIG is a software development tool that connects programs written in C and C++ with a variety of high-level programming languages.”
After some hours of research i ended up with some facts:
To created yourself a Java binding to a given c/c++ Program or Library you need one or more Interface files (*.I) and swig file with all the necessary swig module descriptions.
There is an example on the swig homepage ( http://www.swig.org/Doc1.3/SWIGDocumentation.html#Introduction) to explain the workflow of SWIG.
There is a c file exmple.c:

/* File : example.c */
double  My_variable  = 3.0;

/* Compute factorial of n */
int  fact(int n) {
    if (n <= 1) 
        return 1;
    else 
        return n*fact(n-1);
}

/* Compute n mod m */
int my_mod(int n, int m) {
    return(n % m);
}

The mapping example.i files looks as the following:

/* File : example.i */
%module example
%{
/* Put headers and other declarations here */
    extern double My_variable;
    extern int    fact(int);
    extern int    my_mod(int n, int m);
%}
extern double My_variable;
extern int    fact(int);
extern int    my_mod(int n, int m);

As you can see, the Interface file has a similar syntax with some additional meta information.
You can now create your JNI bindings:

swig -java example.i
There are also flags for different other languages:
-allegrocl - Generate ALLEGROCL wrappers
-chicken - Generate CHICKEN wrappers
-clisp - Generate CLISP wrappers
-cffi - Generate CFFI wrappers
-csharp - Generate C# wrappers
-guile - Generate Guile wrappers
-java - Generate Java wrappers
-lua - Generate Lua wrappers
-modula3 - Generate Modula 3 wrappers
-mzscheme - Generate Mzscheme wrappers
-ocaml - Generate Ocaml wrappers
-octave - Generate Octave wrappers
-perl - Generate Perl wrappers
-php - Generate PHP wrappers
-pike - Generate Pike wrappers
-python - Generate Python wrappers
-r - Generate R (aka GNU S) wrappers
-ruby - Generate Ruby wrappers
-sexp - Generate Lisp S-Expressions wrappers
-tcl - Generate Tcl wrappers
-uffi - Generate Common Lisp / UFFI wrappers
-xml - Generate XML wrappers

As a result you get three new files:

  • example.java
  • exampleJNI.java
  • example_wrap.c

The example_wrap.c can be used to compile the needed library file for your JNI access.
The two java Files are the basic JNI implementation:

    class exampleJNI {
        public final static native void My_variable_set(double jarg1);
        public final static native double My_variable_get();
        public final static native int fact(int jarg1);
        public final static native int my_mod(int jarg1, int jarg2);
    }

And a basic java example how to access these functions:

public class example {
    public static void setMy_variable(double value) {
        exampleJNI.My_variable_set(value);
    }
    public static double getMy_variable() {
        return exampleJNI.My_variable_get();
    }
    public static int fact(int arg0) {
        return exampleJNI.fact(arg0);
    }
    public static int my_mod(int n, int m) {
        return exampleJNI.my_mod(n, m);
    }
}

To get into working with SWIG i can advise the sources of the G4Java Project.
There is also a maven plugin to use SWIG from within your maven build: http://java.freehep.org/freehep-swig-plugin.
I am currently trying to create the necessary Interface files from the jack-audio sources to use them for a first run of SWIG. For python and tck you can use cmake to create these files.

instant jruby & derby environment für eine RoR Anwendung

Flattr this!

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.

Upgrade – Downgrade – Löschen – Upgrade: Läuft

Flattr this!

Mal wieder ne Stellungnahme:
Da ich u.a. eine Query machen möchte, ob zum Beispiel ein Benutzer mit einer bestimmten Email schon existiert, hatte ich bisher folgende URI zum Abfragen:
http://localhost:8080/cotodo/resources/users/like/?cat=email&val=Test@test.com/
Das lief auch wunderbar. Wen es interessiert, der Code dazu schaut so aus:

    @HttpMethod("GET")
    @UriTemplate("like/")
    @ProduceMime({"application/xml", "application/json"})
    public UsersConverter getLikeQuery(
            @QueryParam("val") @DefaultValue("") String val,
            @QueryParam("cat") @DefaultValue("email") String cat ) {
          try {
            return new UsersConverter(getEntitiesLike(cat, val), context.getAbsolute());
        } finally {
            PersistenceService.getInstance().close();
        }
    }

Allerdings wäre eine schönere URI ala

 http://localhost:8080/cotodo/resources/users/email/like/philipp@haussleiter.de/

denkbar.
Ich habe mich dann heute mal hingesetzt, um auf eine neuere JSR311 Version (Version 0.5) zu updaten. Eigentlich sollte so allmählich die Final kommen, aber nungut, man weiß ja nicht was für Fehler noch kommen mögen.
Kurzum: Es hat sich einiger geändert. Ist wohl das Problem, wenn man mit nicht spezifizierten Packeten arbeitet :-).
Hier mal ein paar Änderungen:
@HttpMethod ist verkürzt worden:
aus @HttpMethod(“GET”) wird @GET,
aus @HttpMethod(“POST”) wird @POST
usw.

getAbsolute() heißt nun getAbsolutePath(), ansonsten sind mir keine Änderungen aufgefallen.
Der URI Builder (eine statische Klasse, um URIs zusammen zu bauen) wurde umbenannt – was meiner Meinung nach einleuchtender ist nun:
Aus:

 Builder.created(context.getAbsolute().resolve(entity.getUserId() + "/")).build();

wird nun:

 Response.created(context.getAbsolutePath().resolve(entity.getUserId() + "/")).build();

Da in beiden Fällen der Rückgabewert vom Typ Response ist, ist letzteres einleuchtender.
Mit der neuen Version 0.5 ändert sich obige Methode folgendermaßen:

@GET
@Path("{cat}/like/{val}/")
@ProduceMime({"application/xml", "application/json"})

public UsersConverter getLikeQuery(
    @UriParam("val") @DefaultValue("") String val,
    @UriParam("cat") @DefaultValue("email") String cat
) {
    try {
        return new UsersConverter(getEntitiesLike(cat, val), context.getAbsolutePath());
    } finally {
        PersistenceService.getInstance().close();
    }
}

Und tut nun auch direkt was sie soll. Ein unschönes (weil sicherheitskritisches) Problem habe ich allerdings in der getEntitiesLike Methode:
Ich muss in den JPQL-Query-String die variabel cat direkt einfügen, über parameter scheint es nicht zu gehen (ist wohl wirklich nur für variable werte vorgesehen). Ich muss noch mal suchen, ob es eine Art SQL_escape methode gibt. Ich will ja nun keine SQL-Injektion hinauf beschwören.
Abschließen hat mich das Update einen guten Teil des Morgens gekostet.
Letztendlich war wohl eine Jar version von ASM (wird u.a. von maven2 benutzt, aber von glassfish benötigt) fehlerhaft.
Es kam andauernd:

java.lang.NoClassDefFoundError: org/objectweb/asm/ClassVisitor

Obwohl die Klasse definitiv im vorhandenen jar zu finden ist!
Letztendlich habe ich dann alle meine jars mal gelöscht und Schritt für Schritt neu hinzugefügt.
Es hat wohl tatsächlich etwas mit fehlerhaften Referenzen zu tun. Das gleiche Problem triff wohl auch bei der Benutztung von Hibernate auf.
Heute Abend, oder morgen schreibe ich dann noch etwas dazu, wie ich ein skizziertes HTML Formular per JS DOM Anweisungen erstelle.
Braucht ein wenig Übung, ist aber sauberer und schneller als sich Strings zusammen zu bauen und außerdem bleibt einem in Hinsicht auf AJAX und callback functions eh nichts anderes übrig.

hands-on: Maven(2)

Flattr this!

Bevor ich dann endlich mal wieder etwas über meine eigentliche Arbeit poste, noch mal ein kleiner Abstecher zu dem Thema “Dinge die man nebenher sich aneignet”.
Ich habe mich mal, nach dem Kommentar von Stefan bezüglich JRA umgesehen.
Leider fand ich zuerst nur eine Source Version vom JRA Code, sodass ich mir erstmal die Fähigkeit aneignen musste, das ganze zu kompilieren.
Als Build Tool kommt hier übrigens Maven 2 zum Einsatz.
Das ganze ist vom Apache Projekt und soll wohl irgendwann einmal die Nachfolge von Ant antreten. Wenn man sich so die Feature PlugIns Liste ansieht, ist das auch durchaus wahrscheinlich.
Der riesen Vorteil von Maven 2 – soweit ich das bisher verstanden habe – ist, dass man die Tools, welche man zum Erstellen/Installieren/Testen/Deployen benutzen will, nicht vorher installieren muss, sondern dass Maven 2 von der Versionierung der Sourcen bis hin zum letztendlichen Kopieren auf das Zielsystem alles übernimmt.
Um es kurz zu machen: Ich erhielt dann nach viel Installation und Tutorials lesen endlich meine jra-1.0-alpha-5-SNAPSHOT.jar 🙂 .

Nachdem ich dann noch mal auf der JRA Homepage gesucht habe, habe ich allerdings gesehen, dass es eine alpha 4 auch zum Download gibt. Nunja bin ich zumindest ein wenig aktueller. Jetzt will ich mal schaun, dass ich die Jar einbinden und mit meinem bisherigen Projekt zum Laufen kriege.