Total Pageviews

Sunday, December 22, 2013

How to install Jira 6.0.6 on a QNAP TS-569 Pro

The QNAP TS-569 Pro is a Intel Atom based NAS system. Therefore it should be no problem to run any Java based application on it.
I managed to get JDK 7 up and running as well, so Jira should be possible too. I installed version 6.0.6, 32 bit edition, but newer versions should run as well.
Keep in mind that the QNAP TS-569 Pro is running a 32 Bit Linux, despite the fact that the underlying architecture is 64 bit.
I upgraded my RAM to 4GB because running Java server applications like Jira or Confluence need more than the stock 1GB.

Assumptions:

  1. All commands are executed using a ssh connection (admin user) to the TS-569 Pro
  2. I did not use a bash environment. Only the built in sh shell was used.
  3. In general you don't need a separate installation of Java 6 or 7, because Jira comes with a bundled JRE 7. My NAS already had a JDK 7 installation with JAVA_HOME pointing to that location. But in principle this should not be necessary.
  4. To configure the MySQL service I used the phpmyadmin QPKG installation
  5. To make things a little bit easier for me and to have more Linux feeling I installed Optware IPKG 
Brief installation instructions:
  1. Create an installation directory for Jira. I chose /share/MD0_Data/Opt/jira but this is totally free and up to you.
  2. Download the 32 Bit installer version of Jira. and save it to a folder on your NAS. It is a script which contains the complete Jira distribution. You don't have to extract anything manual. 
  3. Change into the directory where the downloaded file resides
  4. If not already done make the script executable: chmod +x atlassian-jira-6.0.6-x32.bin
  5. Start the script by executing: ./atlassian-jira-6.0.6-x32.bin
  6. You will get an error saying:
    Sorry, but I could not find gunzip in path. Aborting
  7. I found the solution for that problem in this forum post:
    The gunzip Version on the QNAP seems to be a different one than the script is expecting. The option -V is not recognized by the QNAP gunzip version.
    So just load the script into an editor of your choice (I used the ipkg emacs version) and remove these lines from the script and save it afterwards:
  8.  gunzip -V > /dev/null 2>&1  
     if [ "$?" -ne "0" ]; then  
      echo "Sorry, but I could not find gunzip in path. Aborting."  
      exit 1  
     fi  
    
  9. Start the script again and wait a couple of minutes (yes indeed, it took 2-3 minutes on my NAS)
  10. The console installer starts after the script extracted the installation files and you can continue your Jira installation just like described in the official Jira installation documentation.
  11. You may tweak the JVM settings in the setenv.sh file of your Jira installation to adjust memory settings.
  12. That's it. The next thing would be to create start/stop scripts for the runlevels to make the Jira service start whenever the NAS is starting. This is stuff for one of the next articles.

Monday, December 09, 2013

Useful Subversion pre-commit hook script for Linux servers

Looking for useful subversion pre-commit hooks? Maybe this script is for you. It's a Linux bash shell script and makes also use of python.
The script does the following:

  1. Checks whether the commit message is not empty
  2. Checks whether the commit message consists of at least 5 characters
  3. Checks if the committed files are UTF-8 compliant
  4. Checks whether the svn:eol-style property is set to LF on newly added files
  5. Checks if the committed files have no TAB characters

The UTF-8 and TAB checks are performed on the following file suffixes
  • *.java
  • *.js
  • *.xhtml
  • *.css
  • *.xml
  • *.properties (only check for TABs here, no check for UTF-8 compliance)
It should be easy to adjust those settings to your needs.

 #!/bin/bash  
   
 REPOS="$1"  
 TXN="$2"  
   
   
 # Make sure that the log message contains some text.  
 SVNLOOK=/usr/bin/svnlook  
 ICONV=/usr/bin/iconv  
   
 SVNLOOKOK=1  
 $SVNLOOK log -t "$TXN" "$REPOS" | \  
 grep "[a-zA-Z0-9]" > /dev/null || SVNLOOKOK=0  
 if [ $SVNLOOKOK = 0 ]; then  
  echo "Empty log messages are not allowed. Please provide a proper log message." >&2  
  exit 1  
 fi  
   
 # Comments should have more than 5 characters  
 LOGMSG=$($SVNLOOK log -t "$TXN" "$REPOS" | grep [a-zA-Z0-9] | wc -c)  
   
 if [ "$LOGMSG" -lt 6 ]; then  
  echo -e "Please provide a meaningful comment when committing changes." 1>&2  
  exit 1  
 fi  
   
 # Make sure that all files to be committed are encoded in UTF-8.  
 while read changeline;   
 do  
   
   # Get just the file (not the add / update / etc. status).  
   file=${changeline:4}  
   
   # Only check source files.  
   if [[ $file == *.java || $file == *.xhtml || $file == *.css || $file == *.xml || $file == *.js ]] ; then  
     $SVNLOOK cat -t "$TXN" "$REPOS" "$file" | $ICONV -f UTF-8 -t UTF-8 -o /dev/null  
     if [ "${PIPESTATUS[1]}" != 0 ] ; then  
       echo "Only UTF-8 files can be committed ("$file")" 1>&2  
       exit 1  
     fi  
   fi  
 done < <($SVNLOOK changed -t "$TXN" "$REPOS")  
   
 # Check files for svn:eol-style property  
 # Exit on all errors.  
 set -e  
 EOL_STYLE="LF"  
 echo "`$SVNLOOK changed -t "$TXN" "$REPOS"`" | while read REPOS_PATH  
 do  
  if [[ $REPOS_PATH =~ A[[:blank:]]{3}(.*)\.(java|css|properties|xhtml|xml|js) ]]  
  then  
   if [ ${#BASH_REMATCH[*]} -ge 2 ]  
     then  
   FILENAME=${BASH_REMATCH[1]}.${BASH_REMATCH[2]};  
   
   # Make sure every file has the right svn:eol-style property set  
    if [ $EOL_STYLE != "`$SVNLOOK propget -t \"$TXN\" \"$REPOS\" svn:eol-style \"$FILENAME\" 2> /dev/null`" ]  
     then  
     ERROR=1;  
       echo "svn ps svn:eol-style $EOL_STYLE \"$FILENAME\"" >&2  
    fi  
   fi  
  fi  
  test -z $ERROR || (echo "Please execute above commands to correct svn property settings. EOL Style LF must be used!" >& 2; exit 1)  
 done  
   
   
   
 # Block commits with tabs  
 # This is coded in python  
 # Exit on all errors  
 set -e  
   
 $SVNLOOK diff -t "$TXN" "$REPOS" | python /dev/fd/3 3<<'EOF'  
 import sys  
 ignore = True  
 SUFFIXES = [ ".java", ".css", ".xhtml", ".js", ".xml", ".properties" ]  
 filename = None  
   
 for ln in sys.stdin:  
   
     if ignore and ln.startswith("+++ "):  
         filename = ln[4:ln.find("\t")].strip()  
         ignore = not reduce(lambda x, y: x or y, map(lambda x: filename.endswith(x), SUFFIXES))  
   
     elif not ignore:  
         if ln.startswith("+"):  
           
            if ln.count("\t") > 0:  
               sys.stderr.write("\n*** Transaction blocked, %s contains tab character:\n\n%s" % (filename, ln))  
               sys.exit(1)  
   
         if not (ln.startswith("@") or \  
            ln.startswith("-") or \  
            ln.startswith("+") or \  
            ln.startswith(" ")):  
   
            ignore = True  
   
 sys.exit(0)  
 EOF  
   
 # All checks passed, so allow the commit.  
 exit 0  
   

Friday, November 08, 2013

Hit Ctrl+F9 in Intellij IDEA when JRebel does not work as expected

Often the solution for a problem is so damn easy when you know the cause of the problem ...
Intellij IDEA doesn't have an autocompile feature similar to Eclipse. So if you want your new code to be generated as a class file you have to hit Ctrl+F9 manually.
Well, the same is true when using JRebel. This great piece of software can only detect a change in a class file if the changed class file is generated by a compiler first.
So in case you are using IDEA in conjunction with JRebel and you wonder, why the heck this new code isn't replaced by JRebel on the fly you must hit Ctrl+F9 to generate a new class version and to trigger JRebel afterwards.

One other thing to keep in mind when working with WAR or EAR artifacts in IDEA is to deploy those artifacts as exploded ones!


Monday, October 07, 2013

Installing Android 4.3 OTA Update on rooted Nexus 7

Ok, the 4.3 OTA update is out now for a few months, but I didn't find the time to do the update on my rooted Nexus 7 device.
Another reason for the delay was the fact, that the Nexus 7 Toolkit wasn't released until a few weeks ago. My Nexus 7 already showed me the information that a new update was downloaded and ready to install.
Well, finally I decided to do the install (making a full Nandroid backup prior to the update), but when hitting the button "Reboot and Install" nothing happened.
Usually after waiting 10 seconds the device should reboot and install the update, but the reboot did not occur. My battery wasn't the problem, because it was almost fully charged.
First thing coming to my mind was to flash back the stock recovery. Unfortunately that didn't solve the problem.
The next thing I did was do hit the button "Delete data" of the app "Google Service Framework". This usually forces the system to reset the update state and check for newly available system updates.
And this did the trick. Clicking on "System Updates" the device told me that it was uptodate with a last check date of January 1st, 1970. So I manually hit the button to check for new updates and my device started to download a fresh copy of the 4.3 stock rom.
Now hitting the button "Reboot and Install" rebooted the device and installed the Android 4.3 update.

Wednesday, September 11, 2013

Pitfalls installing wordpress on a Linux box using Multisite with sub directories

This post is not about installing wordpress on a Linux box. It just covers two problems I have faced when installing wordpress 3.6 on my Ubuntu 12.04 box at home.
I did install wordpress using the distributed zip archive following the detailed instructions on the wordpress site. Setting up the database and editing the PHP config files was no problem.
The installation went smooth and everything was working as expected.

Problem 1: Configuring Multisite

Multisite is a great feature of wordpress. It gives you the ability to create more than one site (or blog) within your wordpress installation.
I did the setup using this step-by-step guide. So far so good. With my new multisite feature enabled I wanted to create a new site and filled in the necessary informations for it. The creation succeeded without an error and when I clicked on the dashboard of the newly created site I got a "Page Not Found" error.
Hm ... googling around I didn't really find a good answer.
I decided to check the network administration guide of the wordpress documentation and found a really helpful paragraph about using mod_rewrite (multisite feature needs mod_rewrite) and Apache Virtual Hosts.
My Apache installation is using virtual hosts so what finally did the trick was to add these lines to my VirtualHost section:


 <VirtualHost *:80>    
  <Directory /var/www/vhosts/wordpress>  
   AllowOverride Fileinfo Options  
  </Directory>  

Problem 2: Changing the domain name (or change the URL)

I am using DynDNS and I (and my users) want to access the wordpress installation from the internet. During the installation I did not realize that this was so important, because I thought I can change it easily afterwards. Well, changing it in a Non-Multisite environment is easy, but it turns out that a change of the domain name in a multisite installation is a little bit harder.
What helped me a lot was this documentation on the wordpress site.
Because my installation was totally fresh I skipped the step to make a backup of my database. I walked through all tables of the database and replaced every occurrence of my old domain name with the new DynDNS domain name.
Finally I changed the DOMAIN_CURRENT_SITE attribute in the wp-config.php file to point to the DynDNS name as well and after that my multisite wordpress installation was accessible via the DynDNS url.

I can't say whether it would have been easier to change the domain name before I activated the multisite feature, but it would make sense to me.

Anyway, it works now.

Thursday, July 04, 2013

Referencing a Derby database column with a reserved name using DBUnit

DBUnit is a pretty good tool to achieve reproducible results when unit testing your code. It puts your database in a known state before each test run.
In my case I use JPA with Hibernate as implementation to create the DB schema before each test run. Furthermore I use an embedded in-memory Derby database.

I ran into problems when inserting dbunit datasets into the created schema. A column was named interval which is a reserved word in Derby.

No problem I thought, when escaping the column name (using ' or " ticks) the problem would be solved. Well it turns out to be not that simple :-(

The solution is to set a DBUnit related property/feature to tell DBUnit how to config and use the underlying database. Here is the relevant code snippet

   IDatabaseConnection memDbConnection = new DatabaseDataSourceConnection(  
       (InitialContext) context, DEFAULT_DATASOURCE);  
   DatabaseConfig dbConfig = memDbConnection.getConfig();  
   dbConfig.setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, new DefaultDataTypeFactory());  
   dbConfig.setProperty(DatabaseConfig.PROPERTY_ESCAPE_PATTERN, "\"?\"");  


The line
dbConfig.setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, new DefaultDataTypeFactory());

tells DBUnit to use the default data type factory which works well with Derby. You don't have to set this property explicitly when using Derby.

The second line
dbConfig.setProperty(DatabaseConfig.PROPERTY_ESCAPE_PATTERN, "\"?\"");  

solved my issue. You have to explicitly declare an escape pattern. In my case this was "\"?"".
With default settings DBUnit uses no escape pattern.

Using this solution, a clean insert into the database with a column that uses a reserved name works as expected.

Wednesday, June 26, 2013

Howto create a DB field with a reserved name using Hibernate and JPA

I stumbled upon this problem when I switched from a SQLServer 2008 database to a MySQL database 5.5 using Hibernate in Version 3.6.6 with JPA implementation 2.0.

The goal

Generating a MySQL database schema or updating a database schema automatically using Hibernate's hbm2ddl.auto feature.

The problem

Using SQLServer for a long time everything worked fine. When switching to MySQL the schema generation failed. In particular, one single table was not created and I couldn't find a hint in Hibernate's log statements.

The solution

My persistence.xml file uses the auto update of a database schema using this property

      <property name="hibernate.hbm2ddl.auto" value="update" />

So far so good. Nothing special here.
I changed the Hibernate dialect to use the MySQL dialect (org.hibernate.dialect.MySQLDialect) and when deploying the application it generates the database schema and it should populate the database with default values. When populating starts it immediately fails with the following Hibernate error message:

"You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'interval) values (0, '10', 9, 4, 7, 1)' at line 1"

After a few minutes it came to my mind that the column name "interval" might be a keyword in MySQL. So googling around I found out that I was right. "interval" is a keyword in MySQL (but not in SQLServer).

Ok, reason found. But what is the best way to fix this issue?
Stackoverflow is your friend :-)
Just read this answer from Stackoverflow and you are done.

To summarize shortly:
With Hibernate as JPA 1.0 provider you have to annotate the entity field with enclosing backticks like this:

@Column(name="`interval`")
 
and when using JPA 2.0 the syntax was standardized you have to escape the column name like this

@Column(name="\"interval\"")

This is mentioned in chapter 2.13 (Naming of database objects) of the JPA 2.0 specification:

"It is possible to specify on a per-name basis that a name for a database object is to be inter-
preted as a delimited identifier as follows:
• Using annotations, a name is specified as a delimited identifier by enclosing the name
within double quotes, whereby the inner quotes are escaped, e.g.,
@Table(name="\"customer\"").
• When using XML, a name is specified as a delimited identifier by use of double
quotes, e.g.,
<table name="&quot;customer&quot;"/>"


Using the first (but deprecated) solution you can force Hibernate to quote an identifier in the generated SQL by enclosing the table or column name in backticks in the mapping document. Hibernate will use the correct quotation style for the SQL Dialect. This is usually double quotes, but the SQL Server uses brackets and MySQL uses backticks.

The second solution is the modern and standardized way of forcing your JPA 2.0 and above provider to quote the identifier.

Sunday, June 23, 2013

Lösung für "mit Windows Update kann derzeit nicht nach Updates gesucht werden"

Wer unter einem Windows 7 (64 Bit) die Funktion "Nach Updates suchen" ausführt und obige Fehlermeldung bekommt fängt erstmal an zu googeln.
Das Problem sollte eigentlich relativ einfach zu beheben sein - dachte ich.
Nun, es gibt diverse Antworten zu dem Problem:
Der letzte Eintrag erwähnt auch das Werkzeug winUpdRestore!v28.exe, welches allerdings mit einem Link in SkyDrive ins Leere läuft.
Die FixIt Lösung von Microsoft hat bei mir nicht funktioniert. Viele Blogeinträge erwähnten jedoch die erfolgreiche Behebung des Problems beim Einsatz des Tools winUpdRestore!v28.exe.

Leider ist dieses Tool so gut wie gar nicht im Web aufzutreiben. Ich habe es dann doch auf dieser Webseite gefunden.

Da ich hoffe, dass dieser Blogartikel auch schnell im Google Index auftaucht, gebe ich hier zwei funktionierende Links für diese Datei an:

  1. https://www.dropbox.com/s/n40u1jzphk3bsgs/winUpdRestore!v28.zip
  2. https://dl.dropboxusercontent.com/u/27481342/winUpdRestore!v28.zip
Das Tool ist kein offizielles Microsoft Produkt und Microsoft wird seine Gründe haben, warum das Werkzeug nicht mehr zu bekommen ist. Bei mir hat das Tool aber das Problem behoben.

Wednesday, May 22, 2013

Essential resources when building Android Apps using Maven (and Eclipse)

If you plan to build your Android application on a build server like Jenkins, Hudson, etc ... you should switch from building your project with your IDE (in my case Eclipse) to a build system like Maven or Gradle.

I tried Gradle (using the new Gradle Build export in Eclipse ADT plugin) because the new Android Studio preview release by Google supports Gradle builds, but was totally disappointed by the poor performance of Gradle on my Jenkins CI build server. So I decided to use maven instead and found out about these resources which you have to read and understand:

  1. Maven Android Plugin:
    You need the plugin to build android projects using maven. With Android API 17 the latest stable release 3.5.3 doesn't work. You have to pull the plugin's source from GitHub and build version 3.5.4-SNAPSHOT by yourself.
  2. Android SDK Deployer:
    "Typically artifacts are available in Maven Central, however only the platform versions available in the Android Open Source Project are published to Maven Central. Newer versions of the platform as well as the compatibility package and proprietary extensions like the Google Maps support are not available there and need to be published to your Maven repository, if you want to use them in your Android project.
    The artifacts published to Maven central are available as dependencies under the groupId com.google.android with the artifactId android and android-test.
    The Maven Android SDK Deployer has been created to publish artifacts from the Android SDK into your local repository or repository server when using components that are not available in Central."


    I have taken this from the online book Maven - The Complete Reference by Sonatype.
    With Android API 17 you might run into the same bug like described above. So before building this project you must build version 3.5.4-SNAPSHOT of the Maven Android Plugin
  3. m2e-android:
    In case you use Eclipse, you can use this m2e plugin to add maven support to your Eclipse Android project.

Monday, May 20, 2013

Thursday, April 18, 2013

VirtualBox - Let Host-Only mode access the internet

In an earlier post I described networking modes in VirtualBox. Combining those modes you'll get some kind of swiss knife in realizing somehow exotic networking modes in your VMs.
What if you want your VM that is configured for Host-Only mode access the internet?
Port forwarding using NAT is an option. But for me that sounded to complicated. I had the following requirements:
  1. The host should be able to access services like Apache or GlassFish on the guests (the virtual machine)
  2. The guests should be able to access the outside world (intranet/internet)
  3. The guests should be able to talk to each other using fixed IP adresses
  4. The host should be able to talk to the guests using fixed IP adresses
A working solution for these requirements is described in this blog article.

Sunday, March 10, 2013

Using symbolic links under Windows

Since Windows Vista it is possible to use symbolic links just like you know it under Linux/Unix systems.
Warning: You have to use the command line to use this tool ;-)
The syntax is as follows:

 mklink [[/d] | [/h] | [/j]] <Link> <Target>  

Most of the time I use it with the /d option. This lets the link point to a directory.

Sunday, February 17, 2013

Fixing poor performance (lagging) on Samsung Galaxy Nexus GSM (i9250) phones

Woohoo, I can't believe it. My Galaxy Nexus phone is affected by a bug which causes the phone to slow down and to behave very laggy after a while. Some users reported this might happen when they uploaded or downloaded huge files (e.g. movies).
I can't tell whether huge files caused this problem on my Galaxy Nexus, but from one day to another the phone was reacting very slow. It was no longer usable for me. Typing a single character on the keyboard was a pain in the ass ...
I started to google around and found this posting on XDA which saved my phone's life ;-)
If you are experiencing the same behavior on your Galaxy Nexus you might consider following the steps there. But be careful not to HARD BRICK your phone, because your phone must have a special chipset.
My phone was produced in 08/2012 and really has the "suspicious" V3U00M chipset mentioned in the XDA posting. I checked it using the eMMC Brickbug Check app from the play store.
If your phone is not rooted you can't fix the problem. Either you root it now, or you send it to Samsung and let them repair/swap it. It's up to you.
The next thing to do was to run the LagFix (fstrim) free app or paid version. I now use the paid version, because it has a built in scheduler which runs fstrim every night.
The script mentioned in the posting isn't necessary if you use the paid version of LagFix.
After running the LagFix app my phone was reacting as fast as on the day I bought it and it remains fast until now.

Thursday, February 07, 2013

Multi Line Table Cells in Vaadin 6

I had a hard time figuring out how to wrap content in a table cell using Vaadin 6.7.
Content in row headers can be forced to wrap using a simple "<br/>" tag in the string. Unfortunately it isn't that simple with non-header cells.
I found a working solution in this Vaadin forum post.
You simply have to create your own CSS stylesheet definition and add the following code to it:

 .v-table-cell-wrapper {   
  white-space: normal;   
 }  

Tuesday, February 05, 2013

Howto compress and uncompress a Java byte array using JDK Deflater/Inflater

If you ever came across the requirement to store binary data somewhere (e.g. filesystem or database) it might be handy to compress those data.
Besides the common ZIP algorithm Java offers the Deflater and Inflater classes that uses the ZLIB compression library. ZLIB is part of the PNG standard and not protected by any patents.
Here is a small code snippet which shows an utility class that offers two methods to compress and extract a Java byte array.

 package de.qu.compression.demo;  
   
 import java.io.ByteArrayOutputStream;  
 import java.io.File;  
 import java.io.FileInputStream;  
 import java.io.FileOutputStream;  
 import java.io.IOException;  
 import java.io.InputStream;  
 import java.util.List;  
 import java.util.Map;  
 import java.util.zip.DataFormatException;  
 import java.util.zip.Deflater;  
 import java.util.zip.Inflater;  
   
 public class CompressionUtils {  
  private static final Logger LOG = Logger.getLogger(CompressionUtils.class);  
    
    
  public static byte[] compress(byte[] data) throws IOException {  
   Deflater deflater = new Deflater();  
   deflater.setInput(data);  
   
   ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length);   
       
   deflater.finish();  
   byte[] buffer = new byte[1024];   
   while (!deflater.finished()) {  
    int count = deflater.deflate(buffer); // returns the generated code... index  
    outputStream.write(buffer, 0, count);   
   }  
   outputStream.close();  
   byte[] output = outputStream.toByteArray();  
   
   deflater.end();

   LOG.debug("Original: " + data.length / 1024 + " Kb");  
   LOG.debug("Compressed: " + output.length / 1024 + " Kb");  
   return output;  
  }  
   
  public static byte[] decompress(byte[] data) throws IOException, DataFormatException {  
   Inflater inflater = new Inflater();   
   inflater.setInput(data);  
   
   ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length);  
   byte[] buffer = new byte[1024];  
   while (!inflater.finished()) {  
    int count = inflater.inflate(buffer);  
    outputStream.write(buffer, 0, count);  
   }  
   outputStream.close();  
   byte[] output = outputStream.toByteArray();  
   
   inflater.end();
   
   LOG.debug("Original: " + data.length);  
   LOG.debug("Uncompressed: " + output.length);  
   return output;  
  }  
 }  
   

It is also possible to receive better compression results by calling the method setLevel of the Deflater class and specify the constant Deflater.BEST_COMPRESSION.

Thursday, January 03, 2013

Howto install icinga with the new PHP based web interface on Ubuntu 12.04

I had a hard time finding good articles about how to install icinga with the new web based PHP interface on Ubuntu 12.04.
I didn't want to grab the sources and compile it. Not that I am not able to do that, but in my opinion it should be an easier way to install it. We are living in 2013 and not in the last century ...
Anyway, to make a long story short I found a very good step by step guide on askubuntu which worked for me exactly the way it was described.
Kudos!

Tuesday, January 01, 2013

Google Kontakte in Roundcube Webmail nutzen

Die Einbindung von Google Kontakten in das Adressbuch von Roundcube ist mittels eines Plugins problemlos möglich.
Diese Anleitung beschreibt das Verfahren genau und ausführlich. Der dort aufgeführte Link auf die Zend GData API funktioniert aber nicht mehr.
Ich habe die aktuelle Version (1.12.1) von dieser URL heruntergeladen. Damit funktioniert es einwandfrei.