An important issue when implementing this is how are the
different configurations merged. Being EasyConf a generic
configuration library the main problem is that different
applications may need different merging strategies.
One way to deal with this is to let decide the POJOs which
will act as the configuration objects specific to each
application. For example, if the configuration files contain:
<conf>
<item id="1" ...>
<item id="2" ...>
</conf>
Ant the second:
<conf>
<item id="3" ...>
<item id="2" ...>
</conf>
If the items are stored in a list then they will be added as
the different configuration files are read. And there will
be to items with id=2. On the other side if the items are
stored in a hashtable or any Set using the id with the key
then the definition made in the second file for item 2 will
override the first one (which is what we'll probably want in
this example).
There is one implementation difficulty with this approach.
If digester is used separately to read each file, two
different toplevel configuration objects will be created
(assuming object-create-rule is used), so no merging will
occur. One way to deal with this would be: once the first
file is read the result is pushed into the stack. Instead of
using object-create-rule we should implement a variant of
this rule which will look in the stack first and if there is
already another object of the same type then grab it instead
of creating a new one.
This solves the issue of merging second-level elements such
as the 'item's of the previous example. A more difficult
issue is to allow merging elements of any level. For example:
<conf>
<item id="1">
<subitem id="1"/>
<subitem id="2"/>
</item>
</conf>
And:
<conf>
<item id="1">
<subitem id="3"/>
<subitem id="2"/>
</item>
</conf>
Wants to be merged into the same result as if there was only
one file with the following content:
<conf>
<item id="1">
<subitem id="1"/>
<subitem id="2"/>
<subitem id="3"/>
</item>
</conf>
The strategy defined for merging second-level elements could
work, but now it is needed a more elaborate strategy to
retrieve the previous item. In this case instead of always
creating an 'item' object when its element is found the top
level object should be queried to check if it already exists
and in that case retrieve it. It shouldn't be so hard to
create a Digester rule which implements this behaviour. :)
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
A very different strategy would be to merge the XML files as
a first step before passing them to Digester. The main
advantage is that Digester can be used the regular way. But
the problem of how to deal with different merging strategies
is still there. One way to deal with it would be to
implement an XML Merger which is configurable. In fact it
has already been implemented as part of Liferay, and the way
to configure it is through a POJO. Is this enough or should
it be configurable through a configuration file? Probably a
POJO is good enough if there is a default one which covers
the more usual cases.
This solution seems much simpler to understand and implement
than the previous one but it implies hidden duplication: the
configuration POJOs already state how elements should be
merged by using lists or sets to represent collections. This
same information will be present in the file which
configures the merging strategy (be it another POJO or a
configuration file).
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Logged In: YES
user_id=954801
An important issue when implementing this is how are the
different configurations merged. Being EasyConf a generic
configuration library the main problem is that different
applications may need different merging strategies.
One way to deal with this is to let decide the POJOs which
will act as the configuration objects specific to each
application. For example, if the configuration files contain:
<conf>
<item id="1" ...>
<item id="2" ...>
</conf>
Ant the second:
<conf>
<item id="3" ...>
<item id="2" ...>
</conf>
If the items are stored in a list then they will be added as
the different configuration files are read. And there will
be to items with id=2. On the other side if the items are
stored in a hashtable or any Set using the id with the key
then the definition made in the second file for item 2 will
override the first one (which is what we'll probably want in
this example).
There is one implementation difficulty with this approach.
If digester is used separately to read each file, two
different toplevel configuration objects will be created
(assuming object-create-rule is used), so no merging will
occur. One way to deal with this would be: once the first
file is read the result is pushed into the stack. Instead of
using object-create-rule we should implement a variant of
this rule which will look in the stack first and if there is
already another object of the same type then grab it instead
of creating a new one.
This solves the issue of merging second-level elements such
as the 'item's of the previous example. A more difficult
issue is to allow merging elements of any level. For example:
<conf>
<item id="1">
<subitem id="1"/>
<subitem id="2"/>
</item>
</conf>
And:
<conf>
<item id="1">
<subitem id="3"/>
<subitem id="2"/>
</item>
</conf>
Wants to be merged into the same result as if there was only
one file with the following content:
<conf>
<item id="1">
<subitem id="1"/>
<subitem id="2"/>
<subitem id="3"/>
</item>
</conf>
The strategy defined for merging second-level elements could
work, but now it is needed a more elaborate strategy to
retrieve the previous item. In this case instead of always
creating an 'item' object when its element is found the top
level object should be queried to check if it already exists
and in that case retrieve it. It shouldn't be so hard to
create a Digester rule which implements this behaviour. :)
Logged In: YES
user_id=954801
A very different strategy would be to merge the XML files as
a first step before passing them to Digester. The main
advantage is that Digester can be used the regular way. But
the problem of how to deal with different merging strategies
is still there. One way to deal with it would be to
implement an XML Merger which is configurable. In fact it
has already been implemented as part of Liferay, and the way
to configure it is through a POJO. Is this enough or should
it be configurable through a configuration file? Probably a
POJO is good enough if there is a default one which covers
the more usual cases.
This solution seems much simpler to understand and implement
than the previous one but it implies hidden duplication: the
configuration POJOs already state how elements should be
merged by using lists or sets to represent collections. This
same information will be present in the file which
configures the merging strategy (be it another POJO or a
configuration file).