I have been doing some exploratory work around running the TextUML Toolkit‘s compiler as a standalone Java application. In other words, without OSGi. You Eclipse/OSGi heads out there might ask: why would anyone want to do that? The answer is: enhanced applicability. Severing ties with the Eclipse runtime/OSGi means the compiler would become usable in other contexts, and by more people. Think Ant or Maven-driven builds, or (the horror!) other IDEs.
The TextUML compiler’s dependencies
The TextUML compiler is not very different from any ordinary 3GL compiler. It reads a bunch of source files and spits another bunch of object files. For reading and writing files, the TextUML compiler uses EFS, the Eclipse File System. For generating the object files, which are UML models, the compiler uses UML2 and EMF.
Luckily, all these components are expected to work on a standalone application, although some restrictions in functionality might apply. At a first glance, one would expect that running the TextUML compiler without OSGi should be quite feasible. But, as I should have learned by now, it is never that simple…
Extension registry without OSGi
The TextUML compiler, and some of its dependencies use the extension registry to receive contributions to their extension points or make contributions to other components’ extension points. Since Eclipse 3.2, the extension registry API provides support for creating registries without OSGi. Basically, you can add any extension and extension points you want, all you need to do is to provide the XML markup for them.
Problem: in a standalone Java application, it is the application’s responsibility to somehow find the plugin manifests and populate the extension registry.
Solution: I started with the example Paul Webster posted on the platform newsgroup almost two years ago. It basically starts from a file system location which it assumes to hold plugins, both on JAR’d and directory form. It will find plugin manifests (plugin.xml), recognize translation resources (plugin.properties), and even discover the bundle name by parsing the bundle manifest (MANIFEST.MF), and use that to populate the extension registry. Pretty cool, thanks PW. I just cleaned-up the code a bit and enhanced it to also find plugin manifests using the application’s classloader. I also had to add support for setting the default extension registry, which is the one other components will get when invoking Platform.getExtensionRegistry() or RegistryFactory.getRegistry(). Finally, I had to implement basic support for creating executable extensions, which was not too hard given that I could assume the entire application is using the same (application) classloader.
EFS without OSGi
Also since 3.2, the Eclipse File System does not require OSGi to operate, however it does require a functional registry as it uses an extension point to allow file system implementations to be plugged in. So, provided one manages to populate the default extension registry, EFS works fine on a standard Java app. No action required here (yay!).
EMF and UML2 without OSGi
EMF has long been advertised as being mostly functional when running in non-managed mode. However, when running in an standalone app, EMF does not process extensions to its extension points (such as resource factories, metamodel packages and URI mappings), so a standard Java application needs to explicitly initialize EMF, which is clearly suboptimal. That is because EMF only processes contributions to its extension points right during bundle activation. There is no alternative way to trigger processing of the registry (see bug #271253), which sucks, given that the registry is there just waiting to be used. With no OSGi, there is no such thing as bundle activation, and thus EMF goes into autistic mode. This is also true for UML2 (not surprisingly, as they share many implementation traits), the main difference being that UML2′s extension points are much less used than EMF’s.
Problem: Ecore won’t process the extension registry when running in a standalone Java application.
Solution: Change Ecore so it allows clients to explicitly trigger processing of the contributions to Ecore’s extension points. My local hacky solution was to make Ecore’s extension registry parsers to be publicly visible so any client could invoke them.
‘platform:’ URLs without Equinox
Extensions to Ecore’s URI mapping extension often translate to ‘platform:’ URLs, which are another common Eclipse-ism, and thus not supported in plain Java applications.
Problem: No support for ‘platform:’ URL schemes in standalone mode.
Solution: I implemented a simple URL stream handler for the ‘platform’ protocol. The current implementation complete ignores the path component that determines what bundle the resource is in. That is clearly something that needs to be improved, but should not be too hard.
Well, it wasn’t really a walk in the park, but other than the issue that requires a change in EMF (bug #271253, which I am hoping could be addressed for Ganymede Galileo), I am pretty happy with the results of this exploration.
I made all the code I wrote (including my version of Paul Webster’s registry loader) available on the TextUML Toolkit’s SVN repository on SourceForge. Feel free to use it and submit improvements. I wonder if this sort of stuff could find a home in Eclipse.org, as I think many people currently developing for non-OSGi targets would like to take advantage of some great OSGi-agnostic Eclipse APIs.