users@javaee-spec.java.net

[javaee-spec users] Re: Persistent application configuration

From: Craig Ringer <ringerc_at_ringerc.id.au>
Date: Sun, 29 Jul 2012 11:56:48 +0800

On 07/28/2012 03:39 AM, Bill Shannon wrote:
>
>>
>> Accessing them has improved, but defining them hasn't. It's still a
>> PITA that requires an EAR wrapper or, if you're lucky,
>> container-specific admin command line incantations - even a web
>> console in some containers.
> You don't need an ear wrapper. You can define them in web.xml.
>
I should've been clearer. I know you can include env entries in a
web.xml file, but editing it involves unpacking and repacking the .war,
which isn't something I think the end user should ever have to do. I
should've included that option, though.

>> I can't produce an application with "download, edit a few details in
>> a config file, deploy/run" complexity if the user has to repackage it
>> into an EAR to use it, or if I have to provide per-app-server
>> listings of command line incantations, web UI nav paths,
>> server-specific descriptors, etc to explain how to set some
>> environment entries up.
> Understood.
>
> I know many users would like us to standardize the command line tools
> used for operations such as application deployment, but I haven't seen
> a lot of enthusiasm from vendors for that! :-)
Ugh. That sounds like a nightmare, a recipe for weird "standard wart"
syntax where the std stuff is a hacked on alternative that doesn't fit
with the rest of the tool, like some kind of weird growth. No matter
what you'd always quickly hit the limits of the standard syntax and have
to switch to the vendor one anyway, or use properties/hints like hacks.
Since there's not even a skeleton plan for how that'd be done, a huge -1
from me on that.

> Still, if you could provide an xml file with the settings and the user
> could modify that file and then supply it along with the application
> when they deploy the application (even if such deployment uses
> different tools for each vendor), I think that would help a lot.
That's much more like what I'm thinking of, yes.

>> I guess it all just seems like a lot of hoops to jump through to
>> configure an application - instead of just deploying a configuration
>> file directly.
> Instead of saying "deploy foo.war", is it sufficient to be able to say
> "deploy --config myconfig.xml foo.war"? Or do you want a way to
> deploy the config file separately, before the application is deployed?
I don't have a strong preference personally. I don't see much point
deploying a configuration file that can't do anything without the
application anyway.

The only reason I held back from suggesting it be a co-deployment
artifact was that clean co-deployments using deployment by copying an
artifact to a folder didn't seem simple. In retrospect though it's
trivial, nothing more than requiring the same base name and a suffix, eg
"bobabb-config.xml" for "bobapp.war". There's a race between archive and
config file copy, but that's nothing more than needing a small
deployment scanner delay or copying the config file first.

A co-deployed config file seems ideal to me. I'd be very interested in
others' thoughts on this area, though, as I'm sure there are traps and
pitfalls I'm not aware of.
>> A JNDI access wrapper isn't exactly hard to write where injection
>> isn't available, though it does require the user to understand JNDI -
>> something that's obvious to you and is now obvious to my, but I
>> assure you is /not/ obvious when learning.
> What *would* be obvious when learning?
>
> I'm not sure Preferences is obvious; most people don't even know about it.
Good question. Maybe I phrased that poorly. Not necessarily obvious
(that's what the docs and tutorials are for) so much as simple to use
for basic purposes without a good understanding of how they work.

When learning EE during the EE 5-to-6 transition period I found JNDI
confusing because the name syntax varied from place to place (now mostly
fixed), the java: prefix appeared to be significant but optional,
portable names only work in some places, etc. I'm still muddy about some
areas of JNDI. I find it one of the more confusing parts of Java EE.
This may shine more light on my intellect and reading/comprehension
skills than on EE, but nonetheless may be informative because it could
indicate an area where learning could be made easier.

One answer may well be to use JNDI and env entries (with app-setting
extensions) - and tweak the JavaDoc and tutorials. If the docs provide
simple examples of how it works in common use cases or references to
those examples, so it's simple to just get going with the basics, it'd
be a lot more accessible. Have the @Resource docs mention different ways
an env entry can be set, for example.

It may be worth reading this:
http://docs.oracle.com/javaee/6/api/javax/annotation/Resource.html while
doing your best to think about what a newbie would know - or not know.

Maybe the issue is just that it's hard to get started. You need to know
how it all fits together, which descriptors accept env entries, etc.

As for not knowing about Preferences: Most EE devs certainly don't,
because it isn't very useful in EE, it's never referred to in the docs
or tutorials, etc. Many SE devs don't know about JNDI or EJBs either. If
it were useful and documented for use in an EE context, they'd learn
about it through the usual channels - tutorials, blogs, training,
"what's new" guides, etc. I'm not saying it's the best answer, just that
being unfamiliar isn't a big barrier. After all, CDI was not only
unfamiliar but nonexistent before EE 6, but is now widespread.


> I guess I was expecting that for people just getting started, the
> classes they were going to write are the classes that support
> injection. Still, I agree that at some point it might be confusing to
> people that injection doesn't just work everywhere.

Like @Entity classes? Nope, not CDI injection at least, and attempting
to use injection just silently fails and leaves the injection site null.

@EntityListener? Nope, though that'll be fixed in EE 7 via JPA 2.1.

@FacesConverter? Not without Seam 3 Faces or a revised JSF version, it
wasn't supported in stock EE 6.

There are still /highly/ visible holes.

The inconsistency of injection was one of the single biggest challenges
for me when learning EE. It broke all the nice clean abstractions and
forced me to delve into the guts or use hacky workarounds with
singletons. It's improved somewhat as Glassfish 3 and Jboss AS 7 have
matured, but some areas are still injection dead zones by design.

>> Actually, injection can still work for non-primitives. That's an
>> interesting idea. Something like CDI's Instance<T> could easily be
>> used for injection of mutable properties, with a suitable set(..)
>> method. Essentially an injected wrapper for the entry.
> Which suddenly becomes a lot less obvious. But yes, doable.
Less obvious, but easily teachable. Also, importantly, consistent with
other already-standard API styles.

Nobody just "knows" to use @Resource and they're not just going to
discover it through the they need to learn about it through docs,
tutorials, etc.

> And a related issue... If configuration entries can be changed
> externally, does there need to be a way to notify the application of
> any such changes?
CDI observers seem like an ideal candidate for this. The container just
needs to fire an event through CDI and let any registered @Observes
methods trap it. Think:

void observeConfigChanges(@Observes @EnvEntry(name="myappEnvEntry1")
EnvEntryChangedEvent evt) {
  ...
}

where the @EnvEntry qualifier would be optional and, if omitted, default
to a sensible default. Maybe the default should be reporting events on
every java:app, java:comp/ and java:module/ scoped env entry, and on any
global scoped entries the application has injected references to.

>
>> This could work if env entries were only app-settable if explicitly
>> marked as such, and such entries could *only* be injected via an
>> Instance<T>-like wrapper to prevent accidents like the above.
> That's starting to get pretty complex...
Agreed, but any scheme based on resources and injection is going to have
to be because injection sites can't be final so it's (IMO) unsafe to
just proxy.

Also, it's getting a little complex to implement, but IMO not
significantly complex to use, and very similar to existing facilities in
CDI.

One alternative would be to let any env entry be app-settable and just
trust the programmer to only use wrapper injection when they knew they
might change that entry. That seems like a terrible idea to me - false
simplicitly that creates development- and debugging-time confusion and
chaos.

Another alternative would require that the container stop time when an
application changes an env entry, freezing all the app's threads then
going around and substituting a direct reference to the new entry into
all injection sites. That sounds like a recipe for difficult
implementation and exciting concurrency bugs to me; people are used to
injection sites only changing at quite well defined points in time.

I guess a 3rd option would be exactly that: The injection sites only
update when managed objects are injected or re-injected, and if you want
updates sooner, use a wrapper. Given the way injection varies so much
across the various parts of EE I suspect this would land up being
confusing - "why does my configuration update after each request in my
JSF @RequestScoped beans, but not update in my @Singleton session beans?".

Note that I'm not strongly advocating the idea of using instance-wrapper
injection to support modifiable env entries. The idea of modifiable env
entries you raised was an interesting one, and I just want to explore it
to see if it can be a usable alternative. Your points about the prefs
API below do make it significantly less attractive for the purpose.

>
> If you want to support external configuration of arbitrary Java
> objects, this all becomes much more complex. If you can live with
> strings, it's a lot easier.
Strings (and preferably links of strings) are enough to build anything
else, and are probably fine.

My impulse is to make the configuration file XML so it can easily
describe maps, sets and lists, but maybe that's just going down the
complicator road. It'd certainly be simpler for users if the config was
just a properties file, at the cost of flexibility. Since I'm all about
making this easier to use, and since EE certainly doesn't lack
complicated but powerful options for configuration, maybe simple is best.

I still can't help thinking that an XML file would be plenty simple for
simple cases, and have room for lists, maps and sets of strings too.
Damn trade-offs...

>
> Yes, the implementation details can be hidden, but the
> application-visible semantics need to be defined. If I change a
> configuration parameter and then write an entry to the database, will
> other instances of the application see those changes in the same
> order? Do configuration changes need to be transactional?
I take your point. When you put it that way it's not simple at all, and
potentially harder to retrofit for the purpose than new API. I can see
what you mean about the Windows-registry-like API now that you point it out.

>>> Or we could just define a way to initialize JNDI environment entries
>>> using a properties file. That would be a really cheap solution for
>>> a part of the problem, but can it go far enough or is it a dead end?
>> It'd be a real pain for containers that want to offer web UI or
>> command line management of the JNDI env. When the props file is
>> updated, what's the container to do?
>>
>> It doesn't answer application updates either.
> Right, it solves 40% of the problem but costs 5% of a complete
> solution. It's a cost/benefit tradeoff.

... which is fine, so long as it doesn't put roadblocks in front of
future solutions to those problems.

If this approach was to enter the EE7 standard, how would that affect
containers that already allow admins to modify env entries (albeit
clumsily), like Glassfish? Would they have to rewrite the properties
file? Let the properties file be stale relative to the in-server
registry of entries? How could they cope correctly when the properties
file is updated after they have already had changes made by the admin to
their in-server registry?

Maybe a shrug and a "container-specific/undefined" is the answer, but we
know how popular that response is.

Maybe the answer is to make the properties file little more than an
external deployment descriptor. It pre-seeds env entries at deploy time,
and later updates are applied only when the app is redepoyed -
explicitly or by a container restart.

I'm not convinced that adding a 40% solution like this won't hold back a
95% solution quite badly and/or leave conflicts and more legacy to work
around. OTOH, as you pointed out, it might be that only a 40% solution
can be realistically done in the available timeframe, so the question is
whether it's best to half-do it nor not do it at all.

> It's conceivable that a solution could be delivered independently of
> Java EE 8, and could be applied to Java EE 7 products. Depending on
> the complexity of the solution, a portable implementation might be
> possible, although the biggest challenge is probably cluster support.
>
>> I wonder if there a reasonable subset of functionality that can be
>> considered, one container vendors can extend for other needs?
> I hope it's been clear in this conversation that there's a lot of
> issues to address, even if it means deciding *not* to address them.
> You didn't seem particularly willing to give up the aspects that were
> important to you in order to have a simpler solution, and I think
> you're very representative of everyone else who has been involved in
> this discussion. And that's why it's going to take longer than you
> think. :-)
>

Well made. I was /really/ hoping this wouldn't have to turn into
yet-another-jsr, but it isn't looking good. I don't know if there's
anyone with the time, enthusiasm and qualifications to carry a
configuration JSR for EE through, either; I certainly don't have the
general experience or the knowledge of the bigger end's needs.

I'm now wondering what can be done with the tools CDI already offers,
plus maybe a container extension to handle storing and retrieving
settings in a way suited to each container. If I can come up with
something then there'd at least be something to throw rotten tomatoes at
when designing a solution.

--
Craig Ringer