Try Git

31. December, 2007

I’m not cutting edge. I was a long time ago but today, I prefer mature stuff. That’s why I cultivate the luxury to ignore brand new, cool software until it’s not only cool but most of the wrinkles have been ironed out by those guys who like to bleed (it’s not called “cutting edge” for nothing).

So when Subversion came out, I stayed with CVS until version 1.2. I installed it and liked it immediately. Now, some years later, even the Eclipse plugins (Subclipse and Subversive) work so well that using them becomes uninterruptive.

The same is true for GIT. When Linus (of Linux fame) announced it, I knew that this guy was probably smart enough to know when to start a new version control system and when to stay with the flock. Alas, I never had the pressure to try it.

Actually, I had the pressure but I didn’t notice because I didn’t know enough about GIT, specifically what it does different than, say, Subversion (a.k.a “the worlds largest patch for CVS”). In nutshell, GIT is a set of commands to manage one or more repositories with the same or different versioned objects.

Confused? An example: You work at a paranoid company that won’t allow you to connect to some OSS CVS/SVN server to update the files of a project which you’re using in your daily work. Sad but quite common. Let’s ignore for a minute the relative dangers of using CVS (which you aren’t allowed to use) and using HTTP (which you can use). What options do you have?

You can download the files at home, put them on a USB drive and take them to work. That works pretty well. Now, one day, you make a change to the sources at home and at work. Only, you forget to commit one of them. So you keep updating the sources and eventually, you will run into problems merging the files because of that one uncommitted change.

This happens because neither CVS nor SVN allow you to “clone” the source repository. GIT works differently: When you start, you either create an empty repository or you copy an existing one. When you do that, you get everything. If that other repository gets corrupted, it could be restored completely from your copy. (Remember? “Backups are for wimps; real man put their software on public FTP servers and let the world mirror them!”)

Also, GIT will track the work in each clone repository in an individual branch (unlike SVN where everyone usually works on the same branch). When you checkout the latest version in your working directory, you don’t work on the same branch as any other developer. If you commit something, that’s in your local branch only. If you break something, no one but you will notice.

Only when you’re satisfied with your work, you “push” your changes over to other people. You needn’t even push it to everyone at once. You can send your changes to a few colleagues first, before pushing them to the main project repository for everyone to see. Or you can keep it. GIT will happily download all the branches from the main repository without disturbing yours unless you say “Hey, I want to merge to main development into my code.”

At that time, you will notice something: GIT will ask you to commit all your work first if you have uncommitted files in your working directory. In SVN this isn’t possible or at least not that simple; you’d have to setup a SVN branch for each merge you do. For GIT, it’s simple because from its point of view, the changes are not related in the first place. True, the do have a common ancestor somewhere but after that, they are as independent as they can be.

So you have the great luxury to be able to commit all changes you made, saving all your work before you do the actual merge. You can even save stuff away that you don’t want to merge, so every modified file after that is actually part of the merge. This also means if something goes wrong, you can simply roll back all changes by checking out the head of your local development branch. Even better, you can create better diffs. It’s simple to create a diff for a) everything you changed (diff common-ancestor local-branch-head), b) everything everyone else changed (common-ancestor global-branch-head) and c) everything you changed to do the merge (diff local-branch-head working-copy). In SVN, you usually see a mix of a) and c), at least.

So, if you usually work from several places and can’t keep a network connection to the central server all the time, give GIT a try when you start your next project. It’s worth it.


Weird Path Twist in Blender

29. December, 2007

If you ever ran into the “Weird Path Twist” (a.k.a Z-Twist or curve singularity twist) in Blender, I’ve opened a bug against it: [#8022] Some operations on control points can introduce weird twists in paths

If you don’t know Blender, here is what I did in two days:

It’s the entrance to a public bath on the TAURUS. Since the corridor outside is perpendicular to the bath’s ground, it’s a gravity lock; in the center of the circular walkway, you can see the floor make a 90° turn downwards to align visitors with the gravity field of the bath. If you want to gaze, you can stay on the circular walkway and have a great view of the bath without craning your neck.


N&N in Eclipse 3.4M4: StringBuffer “Optimization”

18. December, 2007

Another one for the futile/harmful optimization awards: The New & Noteworthy page for Eclipse 3.4M4 says:

The new ‘Convert to StringBuffer’ quick assist (Ctrl+1) transforms string concatenations into more efficient, albeit less compact, code using an explicit StringBuffer:

Hello? Since when is using StringBuffer more efficient than using String concatenation? Answer: It was upto Java 1.3 (or maybe 1.2; I’m too lazy to look it up right now).

With Java 1.4, the compiler used StringBuffer as well, so this optimization doesn’t buy anything but makes the code harder to read.

Worse, with Java 1.5, the compiler generates more optimal code by using StringBuilder instead of StringBuffer. The builder is not synchronized; since string concatenation doesn’t suffer from threading issues, this is safe and faster!

And the morale: If you optimize something, make sure you don’t rely on some myth about X being faster than Y.

PS: Of course, there is already a bug tracking this.


Mixins in Java

14. November, 2007

Mixins are powerful programming concept in dynamic languages because they allow you to implements aspects of classes in different places and then “plug” them together. For example, the “tree” aspect of a data structure (something having parents and children) is well understood. A lot of data can be arranged in hierarchic trees. Yet, in many languages, you cannot say:

   class FileTreeNode extends File mixin TreeNode

to get a class which gives you access to all file operations and allows to arrange the items in a tree at the same time. This means you can’t directly attach it to a tree viewer. In some languages, like Python, this is trivial since you can add methods to a class any time you want. Other languages like C++ have multiple inheritance which allows to do something like this. Alas, not at runtime.

For Java, the Eclipse guys came up with a solution: adapters. It looks like this:

    public  T getAdapter (Class desiredType)
    {
        ... create an adapter which makes "this" behave like "desiredType" ...
    }

where “desiredType” is usually an interface of some kind (note: The Eclipse API itself is still Java 1.4, this is the generics version to avoid the otherwise necessary cast).

How can you use this?

In the most simple case, you can just make the class implement the interface and “return this” in the adapter. Not very impressive.

The next step is to create a factory which gets two bits of information: The object you want to wrap and the desired API. On top of that, you can use org.eclipse.core.internal.runtime.AdapterManager which allows to register any number of factories for adapters. Now, we’re getting somewhere and the getAdapter() method could look like this:

    @SuppressWarnings("unchecked")
    public  T getAdapter (Class desiredType)
    {
        return (T)AdapterManager.getDefault ().getAdapter (this, desiredType);
    }

This allows me to modify the behavior of my class at runtime more cheaply and safely than using the Reflection API. Best of all, the compiler will complain if you try to call a method that doesn’t exist:

    ITreeNode node = file.getAdapter(ITreeNode.class);
    ITreeNode parent = node.getParent(); // okay
    node.lastModification(); // Sorry, this is a file method

Try this with reflection: Lots of strings and no help. To implement the above example with an object that has no idea about trees but which you want to manage in a tree-like structure, you need this:

  • A factory which creates a tree adapter for the object in question.
  • The tree adapter is the actual tree data structure. The objects still have no idea they are in a tree. So adding/removing objects will happen in the tree adapter. Things get complicated quickly if you have some of the information you need for the tree in the objects themselves. Think files: You can use listFiles() to get the children. This is nice until you want to notify either side that a file has been created or deleted (and it gets horrible when you must spy on the actual filesystem for changes).
  • The factory must interact with the tree adapter in such a way that it can return existing nodes if you ask twice for an adapter for object X. This usually means that you need to have a map to lookup existing nodes.

A very simple example how to use this is to allow to override equals() at runtime. You need an interface:

interface IEquals {
    public boolean equals (Object other);
    public int hashCode ();
}

Now, you can define one or more adapter classes which implement this interface for your objects. If you register a default implementation for your object class, then you can use this code in your object to compare itself in the way you need at runtime:

    public boolean equals (Object obj)
    {
        return getAdapter (IEquals.class).equals (obj);
    }

Note: I suggest to cache the adapter if you don’t plan to change it at runtime. This allows you to switch it once at startup and equals() will still be fast. And you should not try to change this adapter when the object is stored as a key in a hashmap … you will have really strange problems like set.put(obj); ... set.contains(obj) -> false etc.

Or you can define an adapter which looks up a nice icon depending on the class or file type. The best part is that you don’t have API cross-pollution. If you have a file, then getParent() will return the parent directory while if you look at the object from the tree API, it will be a tree node. Neither API can “see” the other, so you will never have to rename methods because of name collisions. ITreeNode node = file.getAdapter(ITreeNode.class) also clearly expresses how you look at the object from now on: as a tree. This makes it much more simple to write reliable, reusable code.


Hollow Sphere in Blender

12. November, 2007

For a scene in one of my books (a public bath on the TAURUS), I need a ball of water suspended around the center of a large sphere. The sphere outside is the “ground” (you can walk around in it; it’s like the Hollow Earth theory but my version is just the product of careful alien design using magic a.k.a hi-tech to control gravity). I decided to render this in Blender to get a feeling how such a thing might look. What would my character actually see when they step into the bath?

Boolean operators are traditionally a weak spot of Blender (they are a major strength of POV-Ray, if you like text-file driven modeling). I had some trouble to get it to work and if you want to achieve a similar effect, here is how I pulled it off.

Inside

First add the inner object (this makes selecting more simple). In my case that would be an Icosphere (Press “Space”, Select “Add” -> “Mesh” -> “Icosphere”) with 3 subdivisions (to make it appear somewhat round even at the edges) and a radius of “4.000”. This should look roughly like this:

Since this is supposed to be the inner volume of the object, there is a problem: Blender thinks it defines the outside. The key information are the “face normals”. Open the mesh tools (Press “F9”) and select “Draw Normals” on the far right (in the “Mesh Tools1” tab; use the middle mouse button to drag the tab into view if you have to – it’s on the far right). Now the sphere sprouts little cyan pimples. Zoom in and rotate the sphere and you’ll see that they start on the center of each face and extend outwards. This is how Blender knows “outside” from “inside”: The direction in which the face normals point is “outside”.

To turn this into the inner volume, all you have to do is to click on “Flip Normals” (“Mesh Tools” Tab, third line, last button). If you have “Solid” rendering active, the face normals will become tiny dots because the triangle faces now hide the rest of them. The object will still look the same but now, you’re “inside” of it. Since all objects in Blender are hollow, it doesn’t mean much … for now.

I want a ball of water and water doesn’t have edges, so I also smooth the surface (“Set Smooth” at the bottom in the “Link and Materials” tab). This doesn’t change the actual geometry; it just draws the object smoothly. In my version of Blender, the object suddenly went all black at this point. Probably because I haven’t assigned a material, yet. Selecting “Solid” rendering helps.

Connecting Hole

I needed a connection between the two sides (there is a “hole” in the hollow water ball where you can swim from one side to the other if you don’t want to dive through it or use the walking spires or elevators in the restaurants), so I cut a hole in the inner sphere by selecting one vertice and deleting it (press “X” and select “Vertices”). In the image, you can see the lighter inside of the sphere shine through the hole:

Outside

Before I can create the outside, I must make sure that nothing is selected (or Blender would add the new points to the active object): Enter “Object Mode” (“Tab”) and select nothing (Press “A” until nothing is highlighted anymore).

For the outside, I create another sphere. Make sure the cursor hasn’t moved, so the centers of both objects are the same. If it isn’t, select the sphere, press “Shift+S” (Snap) and then “Cursor -> Selection”. When everything is ready, add the second icosphere: “Space” -> Add -> Mesh -> Icosphere, 3 subdivisions, Size “5.00”. I also make that smooth but I leave the face normals alone (this is the outside after all).

Again, I delete the face where the connecting hole is supposed to be: Select a point (in “Edit Mode”) and press “X” -> “Vertices”. Now, you might face two problems: a) the hole in the inner sphere is somewhere else and b) the hole might be below the one you just cut but it’s not perfectly aligned. If that is the case, you were in the wrong view.

When creating an icosphere (a sphere made of triangles instead of rectangles), the triangles don’t have all the same size. If you rotate the sphere, you can see that they are uneven somewhat. I found that the triangles touching the horizontal axis are very even. The solution: Create the spheres in one view (for example YZ) and cut the holes in another (for example XZ). So after doing everything again and cutting in the right views, it should look like this:

As you can see, I did erase the vertice on the Y axis. Next, shift select both objects (use the outliner if you have problems with the inner sphere) and join the objects (use the menu or “Ctrl+J”).

Smoothing Out the Wrinkles

After joining, it’s simple to close the whole: Switch to “Edit Mode”, select all vertices (six on the inner sphere, six on the outer, sequence doesn’t matter) and “fill” them with faces (in the menu Edit -> Faces -> Fill or Shift+F). If you rotate the scene, you’ll see that new triangles have been created but they look ugly in the otherwise smooth surface of the ball. Even using “Set Smooth” doesn’t help; the angles between the hole and the rest of the surface is just too big (mostly perpendicular). To fix this, use “Subdivide” (“Mesh Tools” tab) and “Smooth” (same tab). This halves the selected faces, creating new ones and the smooth step evens the angles. For me, it now looked like this:

Holy ugly! What’s wrong? I’ve left a hint … can you find it?

It’s the face normals again. For some reason, they point into the wrong direction around the hole. After a few undo steps (press “U”), I’m back at the point where the faces have just been created (before the smooth/subdivide steps). One “Flip Normals” later, the color transitions around the hole look much smoother. Back to another round of subdividing and smoothing. After the hole was as I wanted it, I noticed that the “horizon” of the ball still looked rough, so I selected all vertices, did another subdivide and several smooth to end with this result:

Pretty smooth, eh?

Rendering … With POV-Ray

After fumbling with water that looks at least a bit realistic, I created the same scene with KPovModeler (with water but without the hole *sigh*) to give you an idea what someone, standing on the “ground” would see:

Each piece of the red-white checker pattern on the walking spires is 10x10m, the ball hovers 1250m above the observer, has a diameter of 500m and the water is 50m thick/deep. The two blue cubes are both 100m big, one is standing on the opposite side on the “ground”, the other floats on the water. Anyone wants to add the water-slides, diving platforms (1250m jump!), etc.? With that much water and these dimensions, we’ll probably also have clouds, too. The spires don’t hold the water there, by the way, they are just a means of transport (if you don’t want to jump or use the slides).


Five Easy Ways to Fail

25. October, 2007

It’s been said over and over again and now, once more: Five Easy Ways to Fail lists five simple ways to make sure a project will fail:

  • Hire without brains
  • Sloppy schedules
  • Demand reality matches your deadlines
  • Spread tasks evenly
  • Work as many hours as you can

Another insight by Joel Spolsky


Undo for Webapps

25. September, 2007

While AJAX webapps grow more and more functionality, a very important one was missing so far: Undo. Imagine Word without Undo. ‘Nuff said.

Aza Raskin has a solution. Well done!


Downloading Sources for Maven2 Projects

25. September, 2007

If you ever needed to download the source artifacts for a Maven2 project, there were several options: If you use the Eclipse plugin (either the Eclipse plugin for Maven2 or the Maven Plugin for Eclipse, also called “Maven Integration for Eclipse”), you can use the option -DdownloadSources=true from the command line or enable the “Download sources” preferences option.

Both have some drawbacks. When you use the Maven Plugin in the Eclipse IDE, it will try to download the sources all the time which blocks the workflow. If you just want to do it once, you have to enable and disable the option all the time plus you have to force the plugin to start the download (with 0.12, you can add and delete a space in the POM and save it). But it will only download the sources for a single project.

If you use the command line version to download the sources, it will overwrite the .project file and modify your preferences, etc. Also not something you will want.

There are two solutions. One would be the “-Declipse.skip=true” option of the command line plugin. Unfortunately, this option doesn’t work. It will prevent the plugin from doing anything, not only from writing the project files.

So if you have a master POM which includes all other projects as modules and all your projects are checked into CVS, you can run:

mvn eclipse:eclipse -DdownloadSources=true

to download all sources and then restore the modified files from CVS. I’ve opened a bug which contains a patch for the skip option. After applying it, -Declipse.skip=true will just skip writing the new project files but still download the source artifacts.


Spammers “Cracking” Accounts on Blogger

10. September, 2007

There seems to be a recent increase in spammers “cracking” blogger accounts and replacing the blogs with spam/porn/etc.

If you want to save yourself from some hazzle (like your boss asking why you advertise porn on your blog), here are a few tips:

  • Don’t blog while connected via WLAN.
  • Always log out after blogging.

If you have to blog via WLAN, always assume that everyone on this planet watches what you do. In our case here, the spammers don’t actually “crack” your account; they just copy the cookie which your browser uses to identify itself against the server.

Anyone who can present that cookie is “you”. So they listen for it when you talk to the server on a WLAN and, after you’re gone, they run a little script which deletes your blog and replaces it with spam. Takes a few seconds and is almost impossible to track down afterwards.

If you want to be safe, don’t use hotspots to connect to the internet. If you have to, you must set up a VPN, otherwise it’s just a matter of time until your blog will be “cracked”.


Unit Testing jsp:include

19. August, 2007

If you’re stuck with some JSPs and need to test them with MockRunner, you’ll eventually run in the problem to test jsp:include. MockRunner doesn’t come with built-in support for this, but this itch can be scratched with a few lines of code:

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;

import com.mockrunner.mock.web.MockRequestDispatcher;
import com.mockrunner.servlet.ServletTestModule;

/**
 * Allow to use jsp:include in tests.
 */
public class NestedMockRequestDispatcher extends MockRequestDispatcher
{
    public ServletTestModule servletTestModule;
    public HttpServlet servlet;

    public NestedMockRequestDispatcher (
            ServletTestModule servletTestModule,
            Class servletClass)
    {
        this.servletTestModule = servletTestModule;
        servlet = servletTestModule.createServlet(servletClass);
    }

    @Override
    public void include (ServletRequest request, ServletResponse response)
            throws ServletException, IOException
    {
        servlet.service(request, response);
    }
}

In your test case, add this method:

    public void prepareInclude(Class servletClass, String path)
    {
        NestedMockRequestDispatcher rd = new NestedMockRequestDispatcher (createServletTestModule(), servletClass);

        getMockRequest().setRequestDispatcher(path, rd);
    }

The path is absolute but without the servlet context. So if the included JSP is named “foo.jsp” and the context is “/webapp”, then path is "/foo.jsp". If that doesn’t work, print the result of getMockRequest().getRequestDispatcherMap() after the test and you’ll see the paths which are expected.

All that’s left is to call this method in setUp() for all JSPs that you need to test. If you forget one, the jsp:include just won’t do anything (i.e. you won’t get an error). To make sure you don’t miss any includes (especially ones which you lazy co-workers added after you wrote the test), I suggest that you check the map after the test run for entries which aren’t instances of NestedMockRequestDispatcher.