Search code examples
apache-cayenne

Apache Cayenne: supplying dynamically generated project definition


following on from this question:

Apache Cayenne: user-defined tables: examples?

As part of my design, I'm intending to allow operations which modify the database schema at run time. As discussed in the above question, it does seem that Cayenne supports this.

I was interested in how I can supply my new project definition to the ServerRuntime, without using the file system.

After looking at the source it looks as though I have two options:

(1) Implement a custom classloader, set it as the thread-local class loader, and allow Cayenne to find it using ClassLoaderResourceLocator.

(2) Implement a custom ResourceLocator, and bind it in using injection.

It is pretty clear how I would do (1) but arguably (2) is a bit neater as it doesn't rely on the behaviour of ClassLoaderResourceLocator.

Is (2) reasonable, and how would I code this?


Solution

  • Assuming your dynamic project definition is still in XML, a custom ResourceLocator binding is pretty simple and is probably the way to go. So if you have your own XyzResourceLocator, you'd simply do this:

    // using lambda for the Module interface (assumes java 8)
    ServerRuntime r = new ServerRuntime(
        "somelocation", 
         binder -> binder.bind(ResourceLocator.class)
                         .to(XyzResourceLocator.class));
    

    How XyzResourceLocator is implemented depends on where your dynamically-generated project definition resides.

    Also, looking at the source code I see a small caveat. ResourceLocator is (incorrectly IMO) used in a different context to load some of the internal Cayenne XML descriptors. So when you implement your own locator, you may need to do a check like this:

    if(name.endsWith("types.xml")) { .. revert to ClassLoaderResourceLocator ..}
    else { .. use your own algorithm .. }
    

    We'll need to decouple these 2 uses in Cayenne eventually.