> I was able to do this in six easily-understandable lines of code with
> a ServerRuntime(Modules) constructor, and I fear that your suggested
> approach requires me to create several separate classes, store
> configuration globally, and create new modules for each qualifier that
> I need to disable or change.

No, nothing like that :) I assume in both your and John's cases any number of 
runtimes created have application scope (runtimes are not cheap, so you won't 
be starting them ad-hoc). I noticed you have ServiceLocator, so keep using 
that. And just implement 2 methods there, each indicating the purpose and/or 
flavor of a given runtime, say:

- getCommonRuntime()
- getAdminRuntime()

And inside ServiceLocator in place where you create "common" runtime, create 
"admin" one as well from the same set of modules. And use the same 6 lines of 
code to customize the later. Those 6 lines you can either place in a subclass 
of XMLDataMapLoader (redefining it in a module), or do it after the runtime is 
created (like you are doing now). For the purpose of this discussion this is 
actually irrelevant, so I take back my earlier remark about pre and post 3.1 
way of doing things.

> And John's use case is even more straight-forward than my own.

Same solution. 

I guess I am too much of a dependency injection person, always assuming that 
referencing some common object is cheap and easy. So maybe I am overlooking 
something?

Andrus


On Sep 27, 2013, at 8:03 PM, Mike Kienenberger <[email protected]> wrote:

> While I can understand the desire for purity with that pattern, it
> seems to me that it's too expensive to maintain in this use case.
> 
> I don't want to have to maintain a factory for building runtimes and
> track all of the configuration needed to do that, just to turn off a
> qualifier.    The existing runtime contains everything necessary --
> there's just no easy way to get at it.
> 
> Maybe I am overlooking something.
> 
> I know you are busy, but can you provide an example of how I would
> perform the same task for which I provided code (turn off a qualifier
> in an otherwise duplicate ServerRuntime deep inside business logic)
> using modules?
> 
> I was able to do this in six easily-understandable lines of code with
> a ServerRuntime(Modules) constructor, and I fear that your suggested
> approach requires me to create several separate classes, store
> configuration globally, and create new modules for each qualifier that
> I need to disable or change.
> 
> And John's use case is even more straight-forward than my own.
> 
> 
> On Fri, Sep 27, 2013 at 12:49 PM, Andrus Adamchik
> <[email protected]> wrote:
>>> So it looks like I can reuse modules to create my own runtime.
>> 
>> Yes.
>> 
>>> However, the current 3.1 API isn't very friendly toward this approach.
>> 
>> 
>> Yes - see my other email. A common pattern is to have some kind of external 
>> factory that defines the modules.
>> 
>> Also I don't perceive 'copy' method as very useful. The point of a second 
>> runtime is that it is somehow different from the first, and modules is what 
>> makes it different. I think you are doing it in a pre-3.1-DI-way - creating 
>> a runtime first, then customizing it. I would usually place customization 
>> code inside the modules, which are kind of deferred "closures".
>> 
>> Andrus
>> 
>> 
>> On Sep 27, 2013, at 7:39 PM, Mike Kienenberger <[email protected]> wrote:
>> 
>>> So it looks like I can reuse modules to create my own runtime.
>>> However, the current 3.1 API isn't very friendly toward this approach.
>>> I had to clone the ServerRuntime class so that I could create my own
>>> version so I could call CayenneRuntime(Module... modules) in my
>>> constructor.
>>> 
>>> Having a cloned ServerRuntime on which to make customizations seems
>>> like a reasonable use case that we should support.   Can we add such a
>>> method to ServerRuntime?   I think that's a better choice than making
>>> it easier to create a ServerRuntime subclass.
>>> 
>>> private ServerRuntime(Module... modules) {
>>>   super(modules);
>>> }
>>> 
>>> public ServerRuntime copy() {
>>>       return ServerRuntime(serverRuntime.getModules());
>>> }
>>> 
>>> It might be reasonable to make the private constructor public so that
>>> someone can create ServerRuntimes where they are not required to pass
>>> configurationLocation data but can provide their own alternative to
>>> ServerModule.  This would have also worked in my case, removing the
>>> need to have a copy() method.   However, I think the copy() method
>>> provides assurance to the developer that this approach is viable.
>>> 
>>> 
>>> Here's what my application code ended up looking like (using my cloned
>>> class), and I think it's a good approach (except for the cloned class)
>>> for these cases:
>>> 
>>>       PaymentMethod paymentMethod = paymentHistory.getPaymentMethod();
>>>       if (null == paymentMethod) {
>>>           ServerRuntime currentRuntime = ServiceLocator.getCayenneRuntime();
>>> 
>>>           // Payment method was invalidated at this point -- create
>>> a runtime that can read invalidated payment methods
>>> 
>>>           CopiedServerRuntime copiedRuntime = new
>>> CopiedServerRuntime(currentRuntime);
>>>           DataDomain dataDomain = copiedRuntime.getDataDomain();
>>>           dataDomain.setSharedCacheEnabled(false);
>>> 
>>>           EntityResolver entityResolver = dataDomain.getEntityResolver();
>>>           ObjEntity paymentMethodObjEntity =
>>> entityResolver.getObjEntity(PaymentMethod.class.getSimpleName());
>>>           paymentMethodObjEntity.setDeclaredQualifier(null);
>>> 
>>>           ObjectContext unrestrictedObjectContext =
>>> copiedRuntime.getContext();
>>>           PaymentHistory unrestrictedPaymentHistory =
>>> unrestrictedObjectContext.localObject(paymentHistory);
>>>           paymentMethod = unrestrictedPaymentHistory.getPaymentMethod();
>>>       }
>>> 
>>> 
>>> On Fri, Sep 27, 2013 at 11:46 AM, Mike Kienenberger <[email protected]> 
>>> wrote:
>>>> The idea of creating a new ServerRuntime is good, but the
>>>> implementation leaves  me with a few questions.    My ServerRuntime is
>>>> created in the context of the web app.
>>>> 
>>>> Is it reasonable to try to create it using the information in the
>>>> existing ServerRuntime?   Can I pull the injector and modules out of
>>>> the existing Runtime and reuse them to create a new runtime, or do I
>>>> need to create copies of the existing modules and injector?   My guess
>>>> is that each runtime needs unique injector and modules objects, but I
>>>> want to minimize the work I need to do.
>>>> 
>>>> It looks like I have to pull my configurationLocation out of the
>>>> ServerModule, which doesn't really provide it.
>>>> 
>>>> I'm not seeing an easy way to create a new ServerRuntime from scratch
>>>> without having access to data which was only available back when the
>>>> web application started up, short of storing that information
>>>> somewhere globally and reusing it.
>>>> 
>>>> On Tue, Sep 24, 2013 at 2:04 PM, Andrus Adamchik <[email protected]> 
>>>> wrote:
>>>>>> The "special DataContext" case where the qualifier should be ignored can 
>>>>>> probably be handled by starting a separate ServerRuntime, where you can 
>>>>>> strip off the qualifiers. For whatever overhead it creates (ideally not 
>>>>>> much), this has an advantage of cleanly separating "spaces" with 
>>>>>> different ORM rules.
>>>>> 
>>>>> Elaborating on this a bit… The old Configuration allowed multiple 
>>>>> DataDomains, each of those requiring its own DataMap(s) saved in the 
>>>>> project upfront. Good idea, but hard to use in practice.
>>>>> 
>>>>> ServerRuntime (with single DD each) is more user-friendly. By starting 
>>>>> multiple independent runtimes you to easily reuse a single mapping 
>>>>> project, tweaking each in-memory copy local to each Runtime (as well as 
>>>>> tweaking other parameters like cache). 2 Runtimes can reuse a single 
>>>>> DataSource (JNDI, or otherwise), etc.
>>>>> 
>>>>> Andrus
>>>>> 
>>> 
>> 
> 

Reply via email to