dev@glassfish.java.net

Heads up : change in configuration handling

From: Jerome Dochez <jerome.dochez_at_oracle.com>
Date: Thu, 10 Jun 2010 21:07:59 -0700

This is a bit long, please make the effort to read through...

While helping Ludo with Rest stuff I stumbled upon code in V3 that were
assuming that certain configuration elements were present in the
domain.xml. Sometimes the code was needing these configuration elements
to get default values as they are defined on the config-api interfaces.
Although there is nothing awfully wrong about this behavior, the fact it
expects configuration entries to be always present is fragile.

I have therefore decided to add a feature to be able to express that
requirement. Now elements on the domain configuration that should always
be created (when the parent exist) can be annotated with the javax
validation @NotNull annotation. When such annotation is placed along the
@Element annotation, you are guaranteed that the getter will not return
null. Also, if you try to set the element to null, it will fail
validation and the transaction will be rollbacked.

Let's see how it works :

@Configured
public interface Domain {
     @Element
     Applications getApplications();

     void setApplications(Applications apps);
}

and the xml :

<domain>
     ... no applications child ...
</domain>

domain.getApplications() will return null;
domain.setApplications(null) will succeed.

if the domain is :
<domain>
<applications> .... </applications>
</domain>

then

domain.getApplications() will return an Applications instance from the
xml snippet
domain.setApplications(null) will succeed.

Now let's change our definition :

@Configured
public interface Domain {
     @Element
     @NotNull
     Applications getApplications();

     void setApplications(Applications apps);
}

and the xml :

<domain>
     ... no applications child ...
</domain>

domain.getApplications() will return an Applications instance (with the
attributes default available);
domain.setApplications(null) will fail.

if the domain is :
<domain>
<applications> .... </applications>
</domain>

then

domain.getApplications() will return an Applications instance from the
xml snippet
domain.setApplications(null) will fail.

The feature works also recursively, so the newly created instance
triggered by a NotNull presence will also trigger more instance creation
if getters methods of its class are annotated with @NotNull as well.

Another side effect of that change is that I stopped writing out empty
elements. An empty element is characterized by :
     - all it's attributes values are either null or the default value
     - all its collections of elements are empty lists
     - all its elements are null or empty themselves.

so for instance in the past we had things like :
<domain>
<applications/>
<config...
</config>
</domain>

Even though an empty Applications instance is in the configuration tree
(because it's annotated with @NotNull), when writing out, the resulting
xml will be :

<domain>
<config...
</config>
</domain>

The end result might be a few regressions where elements that used to be
in the domain.xml are not present any longer (because they were empty)
and code expecting such elements will fail unless the @NotNull
annotation is used.

I have placed the annotation in 2 places which I realized were needed by
the runtime.

With this feature, it is now very easy to have configuration objects
always present in the runtime (yet not in the resulting xml) allowing
the user code to get the default values from these configuration
objects. If you have code that were creating configuration objects or
duplicating the default values definition just because the configuration
might not be present, it would be a very good idea to leverage this feature.

I have tested what I could, nothing seems obviously broken, but let me
know if something is weird, in particular watch for unresolved
configuration objects dependency injection.

jerome