JPz'log Coin Coin and Plop da Plop

26Jan/100

How I use DropBox

On popular request, here is how I use DropBox. In case you had never heard about it, DropBox gives you a "web folder" (a-la Mobile.me) which is synchronized between your different machines. DropBox works on Mac OS X, Windows and Linux. You can use it to share files with friends too (which is useful for sharing... well... Linux distros and Stallman-compliant software).

You can get a 2 GB free account which is way sufficient for most usages, but switching to a paid account is certainly a good idea if you can afford to. I should also mention that the service is rock-solid, and the software clients work seamlessly in the background.

There are a bunch of files that I need to share between my laptops at home and at work, and DropBox is just way better than a USB key or a geeky rsync-based solution (or worse, a Subversion-based one). The only thing is that I never store sensitive informations in my DropBox folder, as this data is to be hosted in the clound, and you never know what may happen to it.

Whenever we need to exchange stuff with friends, we simply drop something into our shared archive. It can't really be any simpler. Another nicety about DropBox is that it stores revisions of your files, so that you can always revert a deletion or switch back to a previous version. It is not as powerful as a true version control system, but it does a fine job as long as you spot where the option is (only in the web interface).

But the true geeky usage that I have is when combined with Git (or any other DVCS of your choice). The power of DVCS lies in the fact that they store the whole history locally and as such, they do not require a server. You can thus store your Git branches in a DropBox folder, or put a symlink in it. This way you get the benefits of both DropBox and Git (or Hg, Bzr, ...): powerful VCS, automatic remote backups and synchronization between workstations.

How about yourself? How do you use DropBox?

4Nov/0912

Guice it up (or AOP can be made simple sometimes)

Juice

I have been knowing about the Google Guice dependency injection container features for quite some time. Guice is a really pleasant DI framework that does its job with brilliant simplicity from a developer point of view (oh yes, and you don't have to describe the classes wiring in a dumb XML file like Spring does).

Guice has more than DI capabilities though, as long as you spice it up with extensions libraries. Today I'll show you the AOP capabilities that Guice offers.

I must admit that I have always been puzzled by this thing called aspect-oriented programming. While the idea of separating actual code from cross-cutting concerns (e.g., security, transactions) makes a lot of sense, one may easily end-up writing spaghetti code.

If you don't believe me, have a look at Spring ROO, I am really curious to know if one can come up with serious arguments for not calling that mess of Java, AspectJ and Spring XML oddities "spaghetti code".

Anyway, AOP flourished rapidly a few years back, as advanced developers, methodologists and event academics all went crazy about it through books, frameworks and claims of the death of OOP. The good news is that for a change, the AOP hype faded away in a flashlight (I whish the same could have been true for those silly things called SOAP and BPEL). However, AOP is still very useful in non-dynamic languages like Java, and reasonable use can make code quite elegant.

Let's get back to Guice, as I will quickly go through some code snippets. I wanted to play with Guice through the trivial use-case of a declaratively access-restricted contacts manager. The code that you will see exhibits AOP and DI features in Guice. As far as the quality is concerned, it will show you the approach, but in an industrial case one would of course need something a bit more elaborated.

First of all, I created a wonderful Person model class:

package app;
 
public class Person {
 
    private final String name;
 
    private final String email;
 
    public Person(String name, String email) {
        this.name = name;
        this.email = email;
    }
 
    public String getName() {
        return name;
    }
 
    public String getEmail() {
        return email;
    }
 
    @Override
    public String toString() {
        return new StringBuffer(name)
                .append(" <")
                .append(email)
                .append(">")
                .toString();
    }
 
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
 
        Person person = (Person) o;
 
        if (!email.equals(person.email)) return false;
        if (!name.equals(person.name)) return false;
 
        return true;
    }
 
    @Override
    public int hashCode() {
        int result = name.hashCode();
        result = 31 * result + email.hashCode();
        return result;
    }
}

Disgression: it would have been much more concise in Scala or Groovy.

I then designed a ContactManager interface:

package app;
 
public interface ContactManager {
 
    public ContactManager add(Person person);
 
    public ContactManager remove(Person person);
 
    public Person lookup(String name);
 
}

Note that I made it minimalistically fluent so that add and remove calls could be chained.

I then wanted to design a basic access control mechanism, so that an implementation of ContactManager could declaratively restrict its access to a certain type of user profile, much like what we can do with EJB 3.x (incidentally, good implementations like Glassfish use AOP and bytecode engineering under the hood).

Hence, I designed annotations to let classes and methods specify access-control policies:

package app.auth;
 
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface WithUserProfileVerification {
}

and

package app.auth;
 
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequiresProfile {
 
    UserProfile value();
 
}

along with a user profile enumeration (anonymous user, regular user and administrator):

package app.auth;
 
public enum UserProfile {
    ANONYMOUS, USER, ADMIN
}

Now we are able to define a basic ContactManager implementation with declarative access-control policies:

package demo;
 
import app.ContactManager;
import app.Person;
import app.auth.RequiresProfile;
import static app.auth.UserProfile.ADMIN;
import static app.auth.UserProfile.USER;
import app.auth.WithUserProfileVerification;
 
import java.util.HashSet;
import java.util.Set;
 
@WithUserProfileVerification
public class ContactManagerImpl implements ContactManager {
 
    private final Set<Person> contacts = new HashSet<Person>();
 
    @RequiresProfile(ADMIN)
    public ContactManager add(Person person) {
        contacts.add(person);
        return this;
    }
 
    @RequiresProfile(ADMIN)
    public ContactManager remove(Person person) {
        contacts.remove(person);
        return this;
    }
 
    @RequiresProfile(USER)
    public Person lookup(String name) {
        for (Person person : contacts) {
            if (person.getName().equals(name)) {
                return person;
            }
        }
        return null;
    }
}

From this definition, anonymous users cannot do anything, regular users can perform lookups and administrators can add/remove contacts.

This can be summarized by this class diagram:

guiceaop-1

Cables

The next question is of course: how do you make that actually work?

First, let's design a profile checker interface along with a dumb implementation:

package app.auth;
 
public interface UserProfileChecker {
 
    public UserProfile getCurrentUserProfile();
 
    public UserProfile login(String login, String password);
 
    public UserProfile logout();
 
}
package demo;
 
import app.auth.UserProfile;
import static app.auth.UserProfile.*;
import app.auth.UserProfileChecker;
 
public class DumbUserProfileChecker implements UserProfileChecker {
 
    private UserProfile userProfile = ANONYMOUS;
 
    public UserProfile getCurrentUserProfile() {
        return userProfile;
    }
 
    public UserProfile login(String login, String password) {
        if (login.equals("Julien") && password.equals("secret")) {
            userProfile = ADMIN;
        } else if (login.equals("Jean-Jacques") && password.equals("1234")) {
            userProfile = USER;
        } else {
            userProfile = ANONYMOUS;
        }
 
        return getCurrentUserProfile();
    }
 
    public UserProfile logout() {
        userProfile = ANONYMOUS;
        return userProfile;
    }
 
}

guiceaop-2

Sounds great isn't it? :-) Still, the link is missing between our contact manager implementation, and this user profile checker.

The idea is to design an aspect for that: each class that uses our declarative access-control policies will have method calls beeing intercepted by the aspect. Here is the code:

package demo;
 
import app.auth.RequiresProfile;
import app.auth.UserProfile;
import static app.auth.UserProfile.ADMIN;
import static app.auth.UserProfile.USER;
import app.auth.UserProfileChecker;
import com.google.inject.Inject;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
 
public class UserProfileInterceptor implements MethodInterceptor {
 
    @Inject
    private UserProfileChecker profileChecker;
 
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        UserProfile required = methodInvocation.getMethod().getAnnotation(RequiresProfile.class).value();
        UserProfile current = profileChecker.getCurrentUserProfile();
 
        if (insufficientProfile(required, current)) {
            throw new RuntimeException("The current user profile (" + current + ") is not sufficient: " + required);
        } else {
            return methodInvocation.proceed();
        }
    }
 
    private boolean insufficientProfile(UserProfile required, UserProfile current) {
        return (required == ADMIN && current != ADMIN)
                || (required == USER && (current != USER && current != ADMIN));
    }
 
}

The user profile checker will be injected by Guice in the aspect (see the @Inject annotation). The interesting work is performed by the invoke method that looks at the required user profile (through the invoked method annotation) and checks it against the user profile checker. When the profile matches, the method actually gets invoked, otherwise a RuntimeException is raised.

From there what is missing is simply the Guice wiring definitions. Before we look at that, I also designed an aspect for logging method calls (hence, we will inject two aspects):

package demo;
 
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
 
import java.util.logging.Level;
import java.util.logging.Logger;
 
public class LoggingInterceptor implements MethodInterceptor {
 
    private Logger logger = Logger.getLogger(LoggingInterceptor.class.getName());
 
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        logger.logp(
                Level.INFO,
                methodInvocation.getClass().getName(),
                methodInvocation.getMethod().getName(),
                "invocation",
                methodInvocation.getArguments());
 
        Object result = null;
 
        try {
            result = methodInvocation.proceed();
        } finally {
            logger.logp(
                    Level.INFO,
                    methodInvocation.getClass().getName(),
                    methodInvocation.getMethod().getName(),
                    "return",
                    result);
 
            return result;
        }
    }
 
}

guiceaop-3

Finally, here is the Main class that has the Guice wiring configuration and a simple use-case:

package demo;
 
import app.ContactManager;
import app.Person;
import app.auth.RequiresProfile;
import app.auth.UserProfileChecker;
import app.auth.WithUserProfileVerification;
import com.google.inject.*;
import static com.google.inject.matcher.Matchers.*;
 
public class Main {
 
    public static void main(String[] args) {
        new Main().execute();
    }
 
    private Module guiceModule = new AbstractModule() {
 
        @Override
        protected void configure() {
 
            bind(ContactManager.class)
                    .to(ContactManagerImpl.class)
                    .in(Singleton.class);
 
            bind(UserProfileChecker.class)
                    .to(DumbUserProfileChecker.class)
                    .in(Singleton.class);
 
            UserProfileInterceptor userProfileInterceptor = new UserProfileInterceptor();
            requestInjection(userProfileInterceptor);
 
            bindInterceptor(
                    annotatedWith(WithUserProfileVerification.class),
                    annotatedWith(RequiresProfile.class),
                    userProfileInterceptor);
 
            bindInterceptor(
                    subclassesOf(ContactManager.class),
                    any(),
                    new LoggingInterceptor());
        }
 
    };
 
    private Injector injector = Guice.createInjector(guiceModule);
 
    private void execute() {
        ContactManager contacts = injector.getInstance(ContactManager.class);
        UserProfileChecker profileChecker = injector.getInstance(UserProfileChecker.class);
 
        profileChecker.login("Julien", "secret");
 
        contacts.add(new Person("Julien Ponge", "julien.ponge@gmail.com"));
        contacts.add(new Person("Jean-Jacques", "jean.jacques@gmail.com"));
 
        profileChecker.logout();
        profileChecker.login("Jean-Jacques", "1234");
 
        System.out.println(contacts.lookup("Julien Ponge"));
    }
 
}

guiceaop-4

You can easily modify the execute method call to check that access-control is enforced (e.g., have an anonymous user attempt to add an entry and see that an exception is raised).

The wiring defined in the module configuration is straightforward. One should only pay attention to the requestInjection(userProfileInterceptor) call. Indeed, aspects are not managed by the DI container. As we request an injection in the corresponding class, this call will make it on-demand.

As we saw in this small showcase, Google Guice is a very compelling DI framework with simple and efficient AOP capabilities.

Don't you think so? :-)

29Sep/093

ScalaTest in Maven

ScalaTest is a wonderful testing framework written in Scala that embraces several styles of testing (JUnit-style, behavior-driven, etc). Of course we live in a polyglot programming world, hence you don't have to code in Scala to leverage its power :-)

I recently coded in Scala and found that running ScalaTest from Maven is all but a straightforward thing to do.

First of all, I suggest that you jump on the 1.0-SNAPSHOT versions as they contain a JUnit bridge (and other refinements).

Add this to your pom.xml:

(...)
        <dependency>
            <groupId>org.scalatest</groupId>
            <artifactId>scalatest</artifactId>
            <version>1.0-SNAPSHOT</version>
            <scope>test</scope>
        </dependency>
(...)
        <repository>
            <id>scala-tools.org releases</id>
            <name>Scala-tools Maven2 Releases Snapshots Repository</name>
            <url>http://scala-tools.org/repo-snapshots</url>
        </repository>
(...)
    <pluginRepositories>
        <pluginRepository>
            <id>scala-tools.org</id>
            <name>Scala-tools Maven2 Repository</name>
            <url>http://scala-tools.org/repo-releases</url>
        </pluginRepository>
    </pluginRepositories>
(...)

You then need to make sure that your Scala code is properly compiled from the tests classes location:

(...)
    <build>
        <sourceDirectory>src/main/scala</sourceDirectory>
        <testSourceDirectory>src/test/scala</testSourceDirectory>
        <plugins>
            <plugin>
                <groupId>org.scala-tools</groupId>
                <artifactId>maven-scala-plugin</artifactId>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                            <goal>testCompile</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
(...)

In my case, I am writing tests as specifications that I want to be run from JUnit:

import org.scalatest.junit.JUnitRunner
import org.junit.runner.RunWith
import org.scalatest.Spec
import org.scalatest.matchers.ShouldMatchers
 
@RunWith(classOf[JUnitRunner])
class AutomatonSpec extends Spec with ShouldMatchers {
    (...)
}

Finally, make sure that the Maven Surefire plugin will pick up the specification classes and pass them to JUnit:

(...)
    <reporting>
        <plugins>
(...)
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <configuration>
                    <includes>
                        <include>**/*Spec.class</include>
                    </includes>
                </configuration>
            </plugin>
        </plugins>
    </reporting>
(...)
22Aug/092

The limits of opensource for small shops

Opensource

There is no definite business model for opensource software. That's a topic I had the chance to discuss with many people in the past such as my friend Alexis. Clearly, each software is its own case, and what works well for one project is probably not a very good recipe for another one.

Among the factors that you have to consider, we have:

  • who you are (big corporation, small shop, individual developer, ...)
  • the size of your "market"
  • what you expect people to do with your software (is that an application? framework? library?)
  • do you make that for pure fun? for taking control of a significant market share?
  • do you want to monetize your work?

That's clearly not easy, and stuff may be moving rapidly from the birth of your project to the point where you hit success.

One striking example that I recently found is Nokia launching the PySide project, whose goal is to provide Qt bindings for Python.

PySide

For many years, there was a (relatively) small company called then Trollech, based in Norway, that was editing the excellent Qt framework, a cross-platform C++ GUI toolkit of excellence. It even moved into a full-blown C++ framework for cross-platform development, abstracting the disparities between operating systems (threading, I/O, networking and so on).

Qt from Nokia

Trolltech was making a living by dual-licensing Qt:

  • under the GPLv2 for opensource development (e.g., the nice KDE environment)
  • , and

  • under a commercial license for proprietary software.

Qt was a typical example of a business model based around the evilness of the GPL: the opensource license helped the framework gain momentum while the nasty GPL forced non-opensource developers into buying a commercial license and support bundle.

Another company called Riverbank had developed PyQT,a binding for the Python language, resulting in a powerful combination of a solid dynamic language and a first-class GUI toolkit.

The company behind PyQT was not developing it for philantropic reasons: they opted for the very same dual-licensing scheme too, thus deriving revenues from their work on PyQT.

Meanwhile Nokia acquired Trolltech, meaning that Qt would now be owned and developed by a big corporation rather than a small/mid-sized shop. Nokia does not depend on the Qt commercial licensing revenues, and decided that it was more important to grow the Qt market share than anything else. The outcome is that while there is still a commercial support for Qt, it is now licensed under the GPL, the commercial license and the LGPL.

As someone who is more inclined toward permissive licenses, I appreciate this move, as now anybody can use Qt in a project under any license, simply because the LGPL is not boring you as long as you do not modify Qt itself.

Money

In the meantime, Riverbank is still releasing PyQT under the GPL and its own commercial license, as otherwise they can reasonably expect a drop in their revenues (i.e., "apart from paid support, why would you bother paying for their commercial license if it's under the LGPL?"). One may argue that paid support is often more lucrative than licensing revenues, but it again depends on what you are developing: PyQT is the kind of opensource code that does not really require paid support. Just think that it targets good developers than have no problems digging into Python code (plus, PyQT is already mature and solid).

The Python + Qt combination is highly valued and praised by developers, and Nokia decided that they would need a LGPL Python binding in their bid to grow the Qt marketshares. Given that Riverbank cannot afford to release PyQT under the LGPL, Nokia launched their own bindings. Even better, they made the bindings compatible at the API level.

The following excerpt from their FAQ is eloquent:

What about PyQt?

Nokia’s initial research into Python bindings for Qt involved speaking with Riverbank Computing, the makers of PyQt. We had several discussions with them to see if it was possible to use PyQt to achieve our goals. Unfortunately, a common agreement could not be found , so in the end we decided to proceed with PySide.

We will however maintain API compatibility with PyQt (you can use the same method names but can’t inter-operate with PyQt), at least for the initial release. To import PySide you have to use “import PySide” instead of “import PyQt4″.

As you see, this is clearly a limit of opensource for small shops like Riverbank. What a company like Nokia can afford to consent, a small shop like this cannot unless they find another business model. In this specific case, I however don't see any other way to monetize their hard work...

On a personal note, I have ambivalent feelings towards such a story. I am quite happy to finally see a LGPL Python binding for Qt, as even when I develop opensource software, I do not appreciate to be bound by the terms of the GPL. However, I feel the pain for the Riverbank guys who made a terrific job but did not have much chances to find an alternative business model. Time will tell wether PySide gains some mindshare or not, but I honestly think that they have a great chance of doing so.

Given that this is a very complex topic, I would be very interested in hearing from you through comments on this post!

   

JPz'log is Digg proof thanks to caching by WP Super Cache