Using UML2 in a server-side application? Read this.

For those of you who didn’t know, AlphaSimple, our web-based modeling tool, is strongly based on Eclipse technologies:

  • the server runs Equinox with the web server (Jetty) running as an OSGi bundle
  • we use UML2 for building models (during model compilation), or for traversing them for execution, code generation, diagram rendering etc

UML2 is quite a piece of software. It implements the huge UML spec more thoroughly than any other alternative library (open source or not). Much of what I learned about UML in the last 5 years I learned by dealing with the UML2 API. Kenn Hussey and James Bruck have done a great job on the front of compliance.

On the not-so-great side, development seems to have stopped. IBM, which founded (and funded) the project, apparently pulled the plug last year. The current UML version supported is 2.2 whereas UML 2.4 is coming out soon. The newsgroup has no one that actually knows the code answering questions (I try, but I am far from familiar with the internals of UML2). This is not only an impediment to adoption, but may scare existing adopters away.

But even ignoring those strategic issues, there are technical problems as well: the one we faced with UML2 is thread-safety, which currently makes it unusable for long-running/highly concurrent applications. For a server-side application like AlphaSimple, that is a showstopper. Case at hand: even if we create, load and dispose UML2 resources in a single thread, internally UML2 uses a singleton object that caches cross-references between elements – for all models, and across all threads. That  introduces unnecessary contention between threads that are doing fundamentally unrelated work, but worse, this cache is not fully thread-safe (see bugs 335135 and 332057), and I suspect can’t be made thread-safe by design.

Q: how does one deal with showstoppers? A: with drastic measures.

In the case of AlphaSimple, where we explicitly unload all UML2/EMF resources in the same thread we loaded them (instead of relying on garbage collection), there really is no place for a singleton complex data structure that is intensively used for anything model-related. So our drastic measure (which I am not proud of) was to patch UML2 so the cache adapter is thread specific (by replacing CacheAdapter.INSTANCE with CacheAdapter.getInstance() and returning a thread-specific “singleton”). Luckily the changes required were quite small:


retrieving revision 1.43
diff -r1.43
< 		return CacheAdapter.INSTANCE;
> 		//RC - hack to avoid thread safety issues with CacheAdapter
> 		return CacheAdapter.getInstance();


retrieving revision 1.88
diff -r1.88
< 			CacheAdapter.INSTANCE.adapt(stereotypeApplication);
> 			//RC - hack to avoid thread safety issues with CacheAdapter
> 			CacheAdapter.getInstance().adapt(stereotypeApplication);


retrieving revision 1.26
diff -r1.26
< 	public static final CacheAdapter INSTANCE = createCacheAdapter();
> 	//RC - hack to avoid thread safety issues with CacheAdapter
> 	private static final ThreadLocal<CacheAdapter> INSTANCE = new ThreadLocal<CacheAdapter>() {
> 		protected CacheAdapter initialValue() {
> 			return createCacheAdapter();
> 		}
> 	};
> 	public static CacheAdapter getInstance() {
> 		return INSTANCE.get();
> 	}

This is not a real fix in the sense that it may not work for all applications – for instance, applications that read/create models across different threads. So now we need to manage this patch instead of just getting UML2 from the target platform. But comparing to having a server that keeps failing, we are quite happy with that.

If you can see an issue with this workaround, or if you think I am wrong by believing UML2 cannot be made thread-safe without radical modifications, speak up.

Email this to someoneShare on FacebookShare on LinkedInShare on Google+Tweet about this on Twitter

3 thoughts on “Using UML2 in a server-side application? Read this.

  1. Kenn Hussey

    January 27, 2011 at 2:46pm

    Rafael, I don’t think we can make exactly the changes you propose due to API compatibility restrictions. But perhaps we could add a getInstance() method which, depending on whether a system property is set, would either return a thread local instance (stored in a new private static field) or the default global one. If this sounds reasonable, let’s work toward getting something committed for M6.

  2. rafael.chaves

    January 27, 2011 at 2:51pm

    Right, that makes sense. Do you want to make that change, or should I submit a patch? I could change my patch and submit it on the bug report mentioned above. Cheers.

  3. Kenn Hussey

    January 27, 2011 at 3:47pm

    I’ll put together a patch and post it…

Comments are closed.