0

I have a Wicket application and I'm trying to implement separate configuration that can be changed remotely. That's the end goal, anyway.

What I'm trying to do is set up Cayenne to work by starting it manually, rather than using the web.xml file. I have tried a bunch of different things, but I'm not sure I fully understand how the context is applied to all threads.

I have tried creating a ServerRuntime in my Application class. I've also tried on my custom BasePage class that each page uses. I can get it to kind of work by doing the following on the BasePage, but it is inconsistent:

public class BasePage ....
    public static ServerRuntime runtime = new ServerRuntime("cayenne-config.xml");//This is in my BasePage class, but I've also tried this in the Application class

    @Override
    protected void init() { 
BaseContext.bindThreadObjectContext(Application.runtime.getContext());//This is in my BasePage class
    }

Like I said, that kind of works, but it isn't consistent. I keep getting errors on

BaseContext.getThreadObjectContext();

Error is this:

java.lang.IllegalStateException: Current thread has no bound ObjectContext.

I can't seem to find much information on this. I tried doing stuff like this, and accessing the runtime using these as well, but nothing is working consistently.

WebUtil.setCayenneRuntime(this.getServletContext(), runtime);
BaseContext.bindThreadObjectContext(WebUtil.getCayenneRuntime(((Application)getApplication()).getServletContext()).getContext());

Any help would be greatly appreciated.

adprocas
  • 1,863
  • 1
  • 14
  • 31

1 Answers1

0

I figured out a way to do this on my own.

I'm extending CayenneFilter and overriding the init method.

In there I copied nearly their exact code. I will be able to check for any config here and load the proper xml file. This obviously isn't the ironed out solution, but is definitely a step forward, and could be the way I end up doing this.

Either way, here's what I have tested to be working.

@WebFilter(filterName = "cayenne-config", displayName = "cayenne-config", urlPatterns = {"/*"})
public class TestFilter extends CayenneFilter
{
    @Override
    public void init(FilterConfig config) throws ServletException
    {
        this.checkAlreadyConfigured(config.getServletContext());
        this.servletContext = config.getServletContext();
        WebConfiguration configAdapter = new WebConfiguration(config);
        Collection modules = configAdapter.createModules(new Module[]{new WebModule()});
        ServerRuntime runtime = new ServerRuntime("cayenne-test.xml", (Module[])modules.toArray(new Module[modules.size()]));
        WebUtil.setCayenneRuntime(config.getServletContext(), runtime);
    }
}

I don't think the annotation is needed (I am specifying it all in the web.xml file), but I thought I would leave it here so you could see that it is changing.

If I could find a way to change the config (FilterConfig) values (the init parameters), then I could just change that to the name of the xml file I want to use and not override this entire method. I couldn't figure out how to do that, but I'll look further later.

If anyone has another better answer, I would love to hear it.

adprocas
  • 1,863
  • 1
  • 14
  • 31
  • CayenneFilter and thread-bound ObjectContext is just one example of how Cayenne can be bootstrapped. If you are using any kind of dependency injection framework, you can do away with this approach completely, and create ServerRuntime singleton as yet another DI-managed service. And then create ObjectContexts as needed (e.g. one shared ObjectContext for reads, and short-living page- or method-scoped ObjectContexts for writes. – andrus_a Oct 14 '17 at 06:32
  • @andrus_a, thank you. We aren't using a DI framework at the moment, but is something we are interested in introducing. Would I be using DataContext.getThreadObjectContext() still? We have a lot of applications that use this, so it would be a fairly large change. I haven't done a lot with DI, so any resources to bring me up to speed would also be appreciated. – adprocas Oct 16 '17 at 16:05
  • DI is of course a big topic beyond a short post here. There's Spring[Boot] thing available. Also bootique.io - an open source project based on Google Guice DI, that I am involved with, that provides Cayenne integration out of the box. DataContext.getThreadObjectContext() API will still be available if you need it. It is simple and easy to use. Just keep in mind that it is not the only option, and you can fine-tune ObjectContext scopes in the app to fit specific needs. – andrus_a Oct 17 '17 at 05:31