Apache Cayenne: supplying dynamically generated pr

2019-09-07 09:11发布

问题:

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?

回答1:

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.