Nice Vagrant Script for setting up a LDAP VM for Testing

I found a nice Setup Script at https://github.com/gschueler/vagrant-rundeck-ldap for creating a working LDAP VM with a basic

vagrant up

You just need to do some more steps before:

  • make sure you have installed Version 4.2.12 of Virtualbox! (the latest version – 4.2.14 – breaks vagrant)
  • get your vagrant setup from here
  • download the necessary ubuntu vagrant box:
    vagrant box add precise32 http://files.vagrantup.com/precise32.box

The LDAP port will be mapped to port 3890 in your local machine (the host where virtualbox is installed)
You can login (e.g. with Apache Directory Studio) with the following settings:

Encryption: none
Host: localhost
Port: 3890
User: dc=Manager,dc=example,dc=com
Pass: password

play-i18ned

This Module provides support for converting Play! i18n Files into an Excel Sheet and from an Excel Sheet to i18n Files.

Usage

You need to create the message files first (e.g. conf/messages, conf/messages.de, conf/messages.en)
You may enter some key/value entries to the Files.

The prefered format is:

# Description key=value 

Add the Module to your dependencies:


require: 
... - local -> i18ned 0.1 
... repositories: 
    - local: 
          type: local
          artifact: ${application.path}/../modules/[module]/dist/[module]-[revision].zip 
     contains: - local -> * 


Then install the Module

play deps --sync 

Export (creating Excel File)

play i18ned:export 

Your will find the Excel File in APP_DIR/tmp/i18n.xls

Import (Moving Changes from the Excel File into the Messages Files)

play i18ned:import 

TODO

  • Adding SQL-Export with SQL-Templates
  • Adding Support for selective Actions (Im/Export only specific files)
  • Import from other i18n Formats

Link

https://github.com/phaus/play-i18ned

Starting work on a new ZFS Web Admin

Hello there.

After the Stats showed me, that the ancient Post about a Web based ZFS Interfaces produces a lot attention, i decided to restart with that project from scratch.

You can find the current sources here. I am currently working with the FreeBSD ZFS Version (so basically FreeNAS), but there are already some Test-Cases for Nexenta.
The basic idea of the system is, to use remote SSH Sessions for accessing the different systems and parse the receiving data. There is already a quite stable, JNA based Java Binding for ZFS, but it seems to be broken for the latest Versions of ZFS. And to have a simple solution to manage ZFS on different system, seems to me a great idea.

I have some ideas how to do some things, but it still seems a lot of work :-).

Building Native MacOS Apps with Java

Some Time ago, Java and MacOS were friends. You could just open XCode choose “Java Application” and start coding your app. But since the last version of Xcode 3 and finally with the release of Xcode 4 all the nice Cocoa/Java Bindings were gone. The normal way of Apple to cleanup their System and make space for the support of new Features.

But sometimes you have this great Java Library. Or you just want to create a nice UI for your CLI Java App, and the common SWING UI won’t work and other UI Libraries like macwidgets just lack support for a decent UI Designer and will just add some more graphics to your plain Java UI.

There is a solution for that kind of Problem. It is called rococoa and offers Java a native Binding to your Cocoa Libs. There is also one famous Application that uses this Library and doing very well: Cyberduck.
This App also managed to get into the _AppStore_ by Bundling its own JDK to the App Bundle. You can see the source of Cyberduck here.

So What is an App Bundle?

An App Bundle is basically just a folder with an .app in its nahe. It contains some common Folders:

– a Content Folder with
-> a plist File
-> a Resources Folder

App Bundle Structure

 

 

 

 

 

 

 

There is an old Project called JarBundler to create MacOS App Bundles from your Java Project.
But for this example we are using the maven plugin “osxappbundle-maven-plugin”, for creating the App Bundle and a DMG File for Installation. We also adding the necessary Files for ROCOCOA.

The first Step is to create the necessary NIB File for our Application. In Xcode 3 you could just create a basic NIB with Interface Builder and then add the Outlets and Actions to the NSObject Class (that is the default First Responder). In Xcode 4+ you need to create a dummy controller Class first. Then you can add your Outlets to this class and the the first Responder to this Class.

XCode 4+ NIB and Dummy Class

 

 

 

 

 

 

 

 

You can now create your ViewController Class in Java:

  
// we re-using some of the work done by the cyberduck developer.
import ch.cyberduck.ui.cocoa.application.NSTextField;
import ch.cyberduck.ui.cocoa.application.NSWindow;
import ch.cyberduck.ui.cocoa.foundation.NSBundle;
import ch.cyberduck.ui.cocoa.foundation.NSObject;

import org.rococoa.ID;
import org.rococoa.Rococoa;

public class WindowController {

    public WindowController() {
        String bundleName = "HelloWorld";
        // Load the NIB file and pass it our Rococoa proxy as the file owner.
        if (!NSBundle.loadNibNamed(bundleName, this.id())) {
            System.err.println("Couldn't load " + bundleName + ".nib");
            return;
        }
    }
    // Injected outlet from NIB
    private NSWindow mainWindow;

    private NSTextField textField;

    // Called when loading NIB using NSBundle. NIB has a mainWindow outlet defined.
    public void setMainWindow(NSWindow mainWindow) {
        System.out.println("Outlet set to: " + mainWindow.title());
    }

    // bind the Outlet to the Class Attribute.
    public void setTextField(NSTextField textField){
        this.textField = textField;
    }

    // NSButton in NIB has an action to the file owner named buttonClicked:
    public void buttonClicked(ID sender) {
        textField.setStringValue("Hello World from: " + sender);
    }

    /**
     * You need to keep a reference to the returned value for as long as it is
     * active. When it is GCd, it will release the Objective-C proxy.
     */
    private NSObject proxy;
    private ID id;

    public NSObject proxy() {
        return this.proxy(NSObject.class);
    }

    public NSObject proxy(Class type) {
        if (null == proxy) {
            proxy = Rococoa.proxy(this, type);
        }
        return proxy;
    }

    // Getter for ID for Rococoa Binding
    public org.rococoa.ID id() {
        return this.id(NSObject.class);
    }

    // Setter for ID for Rococoa Binding
    public org.rococoa.ID id(Class type) {
        if (null == id) {
            id = this.proxy(type).id();
        }
        return id;
    }
}

Your main methode is very simple. It just calls the ViewController and creates the AutoreleasePool for your App:

import ch.cyberduck.ui.cocoa.application.NSApplication;
import ch.cyberduck.ui.cocoa.foundation.NSAutoreleasePool;

/**
 * Hello world!
 *
 */
public class App {
    public static void main(String[] args) {
        final NSAutoreleasePool pool = NSAutoreleasePool.push();
        try {
            // This method also makes a connection to the window server and completes other initialization.
            // Your program should invoke this method as one of the first statements in main();
            // The NSApplication class sets up autorelease pools (instances of the NSAutoreleasePool class)
            // during initialization and inside the event loop—specifically, within its initialization
            // (or sharedApplication) and run methods.
            final NSApplication app = NSApplication.sharedApplication();
            WindowController w = new WindowController();
            // Starts the main event loop. The loop continues until a stop: or terminate: message is
            // received. Upon each iteration through the loop, the next available event
            // from the window server is stored and then dispatched by sending it to NSApp using sendEvent:.
            // The global application object uses autorelease pools in its run method.
            app.run();
        } finally {
            pool.drain();
        }
    }
}

I am using an updated version of this example from the rococoa Project Page.

Finally you have to put all the things together; Compiling your Java Files, adding your native Libs, Creating your App-Bundle and your DMG.
I updated the Plugin to be able to add non Java Dependencies to Your App Bundle (like dylibs and NIB Files). You can find the updated version here. I am currently working on creating patch files for upstreaming my changes to the codehaus project.

The important Call of the Maven-Plugins reads like this:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>de.javastream.rococoa</groupId>
    <artifactId>helloworld</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>Hello World</name>
    <url>https://github.com/phaus/rococoa-tests/helloworld</url>
    <build>
        <plugins>
...
 <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>osxappbundle-maven-plugin</artifactId>
                <version>1.0-SNAPSHOT</version>
                <configuration>
                    <!-- PLIST Settings -->
                    <workingDirectory>$APP_PACKAGE/Contents/Resources/Java</workingDirectory>
                    <vmOptions>-Xmx512m -Djava.library.path=$APP_PACKAGE/Contents/Resources/Java/lib -Djna.boot.library.path=$APP_PACKAGE/Contents/Resources/Java/lib -Djna.library.path=$APP_PACKAGE/Contents/Resources/Java/lib -Djna.nounpack=true -Djava.awt.headless=true -Dsun.jnu.encoding=utf-8 -Dfile.encoding=utf-8 -XX:-UsePerfData -XX:+ReduceSignalUsage -Xincgc -XX:-UseLoopPredicate -XX:-OptimizeStringConcat</vmOptions>
                    <mainClass>de.javastream.rococoa.apptest.App</mainClass>
                    <dictionaryFile>${basedir}/src/main/resources/Info.plist</dictionaryFile>
                    <iconFile>${basedir}/src/main/resources/helloworld.icns</iconFile>
                    <!-- adding additional files to the DMG -->
                    <additionalArchiveFiles>
                        <fileSet>
                            <directory>${basedir}/src/main/doc</directory>
                            <includes>
                                <include>COPYING</include>
                                <include>COPYING.LESSER</include>
                                <include>release-notes.txt</include>
                            </includes>
                        </fileSet>
                    </additionalArchiveFiles>
                    <!-- Adding additional Resources (like NIBs) -->
                    <additionalResources>
                        <fileSet>
                            <directory>${basedir}/xcode</directory>
                            <includes>
                                <include>*.lproj/**</include>
                            </includes>
                        </fileSet>
                    </additionalResources>
                    <!-- Adding Native Java Libs -->
                    <additionalBundledClasspathResources>
                        <fileSet>
                            <directory>${basedir}/src/main/lib</directory>
                            <includes>
                                <include>libjnidispatch.dylib</include>
                            </includes>
                        </fileSet>
                        <fileSet>
                            <directory>${basedir}/target</directory>
                            <includes>
                                <include>librococoa.dylib</include>
                            </includes>
                        </fileSet>
                    </additionalBundledClasspathResources>
                </configuration>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>bundle</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            
            ...
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>org.rococoa</groupId>
            <artifactId>rococoa-core</artifactId>
            <version>0.5</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.6.4</version>
        </dependency>
        <dependency>
            <groupId>net.java.dev.jna</groupId>
            <artifactId>jna</artifactId>
            <version>3.3.0</version>
        </dependency>
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.2.2</version>
        </dependency>
    </dependencies>
    
    ...
   <repositories>
        <repository>
            <id>maven.javastream.de</id>
            <name>javastream Repository</name>
            <url>http://maven.javastream.de</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
            <id>maven.javastream.de</id>
            <url>http://maven.javastream.de</url>
        </pluginRepository>
    </pluginRepositories>
    
...
</project>

 

You can find the whole project on Github. It is a very simple Hello World Programm. As soon as you click the Button the Labels text changes to “Hello World from: #CALLER-ID”.

App Window

 

 

 

 

 

 

 

 

The next step is to do further updates to the Plugin, for Bundling a JDK to your App Bundle for creating a real Standalone Application.

iPhoto crashes on Lion 10.7 after the update to 9.3

After the latest iPhoto update to Version 9.3 i experienced a reproducable crash of iPhoto.

This was the error i found in the Crah-Report.

Library not loaded: /System/Library/PrivateFrameworks/CoreMediaIOServices.framework/Versions/A/CoreMediaIOServices

After some time i found some solution in the apple support forums.
You just need to restore the folder /System/Library/PrivateFrameworks/CoreMediaIOServices.framework from your latest backup.

I really wounder what happened to apples QA. I mean thats the second update (after the thunderbolt 1.2 update), that affect other software or the system stability itself.

Fixing Redirects of a Play! App behind an Apache2 SSL Proxy

So you just finished your first Play! App. You want to run that thing behind an Apache2 as a HTTPS Proxy, because you do not want, that your User-Credentials are read as clear text.

So a very basic Apache Configuration looks like this:

    <IfModule mod_ssl.c>

        Listen 443
        SSLRandomSeed startup builtin
        SSLRandomSeed connect builtin

        <VirtualHost _default_:443>

            SSLEngine on
            ServerName example.com
            ServerAdmin admin@example.com
            ErrorLog /var/log/apache2/ssl_error_log

            SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL
            SSLCertificateFile /etc/apache2/ssl/example/newcert.pem
            SSLCertificateKeyFile /etc/apache2/ssl/example/webserver.nopass.key
            SSLCACertificateFile /etc/apache2/ssl/demoCA/cacert.pem
            SSLCARevocationPath /etc/apache2/ssl/certs/demoCA/crl

            ProxyPass               /play            http://127.0.0.1:9000/play
            ProxyPassReverse        /play            http://127.0.0.1:9000/play

        </VirtualHost>

    </IfModule>

I did already explained how to run a Play! Application within a Application Context. Here our Context is just “play”, but you can set it to something else. You can also change and add seperate instances with different ports (over 9000!!!).

You should alter two settings in your conf/application.conf

    # you need to add this
    context=/play

    # you need to uncomment this to prevent Play! from serving aside your Apache2 Proxy
    http.address=127.0.0.1

   # you may uncomment and change this port number for chaning it
   # http.port=9000

Time for a Test Run. At a first glance it seems to work pretty nice. But as soon as you want to use the nifty routing redirects from Play!, the whole system breaks, because Play! still things, it runs in plain http on port 9000. To solve this, you need to change to things:

  1. Make Apache2 to send a specific header, that the Request was send through a Proxy
  2. Make Play! to fix the redirect to the correct URL

The first part is pretty easy. Just add

    RequestHeader set X_FORWARDED_PROTO 'https'

within your VirtualHost Tag – you may need to enable the headers module first to make that work.

The second part is a little bit more difficult. You have to add a before filter to your application controller:

    public class Application extends Controller {

        @Before
        private static void checkSSL() {
            if (request.headers.get("x_forwarded_proto") != null
                    && "https".equals(request.headers.get("x_forwarded_proto").value())) {
                request.secure = true;
                request.port = 443;
            }
            if (request.headers.get("x-forwarded-server") != null) {
                request.domain = request.headers.get("x-forwarded-server").value();
            }
        }
        ...
    }

You can find the sources on GitHub.
B.t.w. the same problem also might appears in Rails Apps, i might write about this later on.

Hacking just for Fun: using Bookmarklets

So there are a handful of webtools using Bookmarklets for their services. The first i know was del.icio.us for saving a Webpage to your del.icio.us bookmarks. Another famous service is Instapaper (it uses internally read it later pocket, but that is another Story). I have a special service in mind, i want to create using a Bookmarklets, before i start, i played around with the Bookmarklet from Instapaper.

The Magic is just a normale HTML A Tag, in whith some javascript is embedded:

javascript:function%20iprl5(){var%20d=document,z=d.createElement('scr'+'ipt'),b=d.body,l=d.location;try{if(!b)throw(0);d.title='(Saving...)%20'+d.title;z.setAttribute('src',l.protocol+'//www.instapaper.com/j/foobar?u='+encodeURIComponent(l.href)+'&t='+(new%20Date().getTime()));b.appendChild(z);}catch(e){alert('Please%20wait%20until%20the%20page%20has%20loaded.');}}iprl5();void(0)

If we unwrap that script we got

function iprl5(){
    var d=document,
    z=d.createElement('scr'+'ipt'),
    b=d.body,
    l=d.location;
    try{
        if(!b)
            throw(0);
        d.title='(Saving...) '+d.title;
        z.setAttribute('src',l.protocol+'//www.instapaper.com/j/foobar?u='+encodeURIComponent(l.href)+'&t='+(new Date().getTime()));
        b.appendChild(z);
    }catch(e){
        alert('Please wait until the page has loaded.');
    }
}
iprl5();
void(0)

The command basically just creates a script tag in the active DOM-Tree and preloads some Javascript-File. The File is then executed by the Browsers JS Runtime.
I started a litte Demo Project. You find it here on GitHub. It is based on Play! 1.2.4 (Installation Guide here).

ATM there are just two JS Templates. The first one (app/views/Application/bookmarklet.js) just contains the source for the Script-Tag itself. The second (app/views/Application/input.js) will be loaded then after the Javascript behinde that link is called.

Hacking just for Fun: Get Mails from IMAP with Java

I have the feeling, that i might need this someday :-).

Collecting Mails from an IMAP Server with Java is pretty easy:

package de.javastream.imapcollector;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Properties;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.Multipart;
import javax.mail.Part;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.internet.MimeBodyPart;
import javax.swing.JOptionPane;

public class App {

    public static void getMail(String host, String user, String passwd) throws Exception {
        Session session = Session.getDefaultInstance(new Properties());
        Store store = session.getStore("imap");
        store.connect(host, user, passwd);
        Folder folder = store.getFolder("INBOX");
        folder.open(Folder.READ_ONLY);
        // the funny part is... you can count all the messages before you download them.
        Message[] messages = folder.getMessages();
        System.out.println("there are "+messages.length+" in your INBOX.");
        for (int i = 0; i <; messages.length; i++) {
            Message m = messages[i];
            System.out.println("Nachricht: " + i);
            System.out.println("From: " + m.getFrom()[0]);
            System.out.println("Subject: " + m.getSubject());
            // some Messages are multipart messages (e.g. text with an attachement)
            if (m.getContentType().equals("multipart")) {
                Multipart mp = (Multipart) m.getContent();
                for (int j = 0; j <; mp.getCount(); j++) {
                    Part part = mp.getBodyPart(j);
                    String disposition = part.getDisposition();
                    if (disposition == null) {
                        MimeBodyPart mimePart = (MimeBodyPart) part;
                        if (mimePart.isMimeType("text/plain")) {
                            BufferedReader in = new BufferedReader(
                                    new InputStreamReader(mimePart.getInputStream()));
                            for (String line; (line = in.readLine()) != null;) {
                                System.out.println(line);
                            }
                        }
                    }
                }
            } else {
                System.out.println(m.getContent());
            }
        }
        System.out.println("done :-)");
        folder.close(false);
        store.close();
    }

    public static void main(String[] args) throws Exception {
        // show some simple Dialogs to get server, username and password
        String server = JOptionPane.showInputDialog("enter your Mail Server e.g. mail.example.com");
        String user = JOptionPane.showInputDialog("enter your login e.g. user");
        String password = JOptionPane.showInputDialog("enter your mail password");
        getMail(server, user, password);
    }
}

Becource you will need the java mail lib as a dependency i just created a small maven project to add them.
Just unzip it and run

mvn exec:java

Download Maven Project for ImapCollector

Update:
A Colleague of mine asks for the imports of that Code. I just added them to the sources. You have to include the javamail lib from Sun Oracle as a dependency to run the code.