Monday, 12 October 2015

NetBeans Diff API Extracted as a Standalone Project

Inspired by Emilian Bold who extracted the Progress bar API as a separate OSS project out of NetBeans source code, I started to work with the aim of extracting the Diff API out as a separate project. I had this thought in 2012 or so and it has taken 3 years to actually make it (and only the textual part!)

In the meantime, came to know that the amazing Geertjan had done something better at https://github.com/GeertjanWielenga/netbeans-visual-diff-standalone
(which I got to know via a post at http://forums.netbeans.org/viewtopic.php?t=63551&highlight=).

Nevertheless, I went ahead and completed the task that I started and also posted the code in my github repo. You can take a look if you are interested. Also, I created a test project at github repo which you can follow to make use of this library.

Also, would like to note down my experiences when trying to make a NetBeans project into an OSS which might be useful for others:

My idea was to make the diff library work with jut JDK. So, wherever I encountered external dependencies, I modified them, such as:

a) NbBundle replaced with ResourceBundle
NbBundle is used quite a lot. I replaced it with ResourceBundle, like:
ex: return ResourceBundle.getBundle("Bundle").getString("BuiltInDiffProvider.shortDescription");

b) org.openide.ErrorManager
This is used in logging exceptions. The Javadoc provides a general guidline where  clearly provides the simple alternative - "Rather then using the {@link ErrorManager} consider using JDK's {@link Logger}
 * for reporting log events, unwanted exceptions, etc."

So, I followed the advice and did the same.

c) ImageUtilities.loadImage:
This was from the package org.openide.util.ImageUtilities - source shows that class loader and ImageIO are used to load images plus provides caching.
I have simply used classloader with ImageIO.

d) The API uses NetBeans lookup mechanism throughout even though both interfaces and implementations are present in the same diff module. There are however, two ways of using lookup to find services - one is the usage of "@org.openide.util.lookup.ServiceProvider" annotation to mark the implementation. This is pretty straightforward and maps to java.util.ServiceProvider usage.
The other way used is also via using Lookup, but, registration of services is done in an old manner (which I think is deprecated now). This is explained in http://wiki.netbeans.org/DevFaqLookupDefault and http://wiki.netbeans.org/DevFaqSystemFilesystem

How did I find this? After reading the above links, I happened to look at the manifest.mf file - which has a reference to "OpenIDE-Module-Layer: org/netbeans/modules/diff/mf-layer.xml"
So, I opened the mf-layer.xml where the DiffProvider implementations are provided and also refer to other .settings file(s). These files in turn have the implementation class name.
It took quite a bit of time to figure this out.

Initially, I started with trying to have the complete visual part as a separate project, but, then decided to do only the textual part. For this, some of the useful code was present as part of the visual stuff. So, while working on this, I also extracted out some inner classes into top-level classes.
For example, the TextDiffVisualizer class has utility method 'differenceToLineDiffText' - which is very useful. I moved this out to a separate class named Util.

Finally, completed this and posted the code at my github repo

No comments:

Post a Comment