You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by Bernd Fondermann <bf...@brainlounge.de> on 2006/06/28 22:15:40 UTC

[LONG] Re: [jira] Commented: (JAMES-495) Decide how to replace Avalon Configuration

I'd like to share some thoughts on a future configuration architecture 
within James.

= Roles involved in configuration process =

Trying to identify the 'players' in the game:

ConfigReader -
   parses configuration file into a ConfigContainer

ConfigContainer:
   holds more or less raw configuration data represented in a
   hierarchical form.

ConfigMapper -
   maps/injects the read data from the ConfigContainer into the 
Configurables

Configurable -
   all components receiving their configuration data from a ConfigContainer

Configurator -
   a component doing changes to the configuration of a Configurable,
   either by
   (a) manipulating the ConfigContainer or by
   (b) manipulating the Configurable directly

ConfigWriter -
   serializing the current configuration to make run-time changes permanent

= James =

In James, these roles are represented like that:
ConfigReader: Phoenix/Avalon internal code
ConfigContainer: DefaultConfiguration, a generic, all-purpose implementation
ConfigMapper: Configurables do that themselves, their relevant 
ConfigContainers are injected by the kernel
Configurable: all the service components implementing interface 
org.apache.avalon.framework.configuration.Configurable
Configurator: (a) Phoenix/Avalon at startup/initialisation,
(b) JMX MBeans
ConfigWriter: n/a

= Postage =

Just to give another view to it, in Postage, it looks a little bit 
different:
ConfigReader: commons-configuration
ConfigContainer: one concrete class per Configurable, more or less 1:1
ConfigMapper: mapping is done by PostageRunner and others
Configurable: beans on various levels, parameter injection per setter or 
constructor
Configurator: the bootstrap class
ConfigWriter: n/a

= Some observations =

- Tight coupling between Configuration and Configurable -

In James, Configurables themselves read and even parse values from the 
ConfigContainer once on startup (method configure()) and often there are 
no setter methods (probably to make the components public interface more 
lean). That makes it difficult to change those values dynamically at 
runtime, e.g. through JMX.

The mandatory use of DefaultConfiguration here also makes the unit test 
code much more verbose than neccessary.

- Dumb ConfigContainers -

Postage has 1:1 relationship between ConfigContainer and Configurable 
classes. But its ConfigContainers don't inhabit any logic. They are 
simple Data Transfer Objects. There is a mapper (class 
ConfigurationLoader) to get the data from the ConfigReader into the 
appropriate ConfigContainers and another mapper (class PostageRunner) to 
get data out of ConfigContainers into Configurables. This is a bit of an 
overkill and not a perfect solution either. But the decoupling of 
Configurable and the rest of the system works pretty well.

= Propositions =

- Setters -

Let's add setters for all kinds of configuration parameters to the 
Configurables in James. If a parameter cannot be set after a component 
has become ready or live, the setter throws an 
AlreadyConfiguredRuntimeException.
This would signal that the component is unable to cope with the change 
and that the component would have to be restarted for the change to 
become effective.
Let's not have the Configurables parse textual configuration parameters 
into IPs, integers etc.

This could be started soon.

(BTW, this topic is not exactly JAMES-494, which deals with dependent 
service injection. Here, I am talking about the internal fields a 
Configurable populates by reading the configuration.)

- Restarting components -

Restarting (=redeploying) a component as the configuration was altered 
is not an easy thing to do, IMHO. (Its easy if components are idle, 
don't hold any resources and there are no dependencies between 
components. That's not the canonical case.) It probably in the end 
appears that the only reliable solution is to shut down the server and 
reboot. So I would propose to support only dynamic changes the component 
can handle while running and not support changes which would need 
components to be restarted. The latter would have to be done offline then.

Maybe there is a solution to this problem in some container we come up 
with. It's enough work to cope with simple configuration changes in the 
first place.

- Configuration Mappers -

Let's introduce a bunch of Mapper objects, which are each able to take a 
sub-Avalon-DefaultConfiguration, parse the Strings etc and inject the 
specific data into the specific Configurable objects. When the avalon 
configuration is eventually abandoned or deprecated, let's have another 
bunch of Mappers for mapping from commons-configuration or whatever we 
decide upon.
Let's not use those dumb ConfigContainers with no logic. The mappers 
could also be the ConfigContainers. (I'd volunteer to refactor Postage 
accordingly.)

Step by step we would move the access to DefaultConfiguration out of the 
Configurables into specialized mapper classes.

- JMX -

MBeans would more or less directly execute operations by using the 
Configurable's setters and methods like it is done at present. They 
would not necessarily use the configuration framework.

JMX is not good at internally exposing component management. Geronimo 
has explicitly moved away from being a MBean-based kernel, JBoss kind of 
suffers from being one.

The reason for that is that the intended JMX granularity (the way a 
remote managing person would like to have it) often does not match with 
the server-internal granularity of Configurables/modules/components/classes.
JMX is good for being a remote 'high-level' API for management.

Let's go on with using JMX as we currently do, more or less.


(Sorry for the long post, any misuse of the english language and my 
weird thoughts.)

   Bernd


Stefano Bagnara wrote:
> Steve Brewin wrote:
> 
>> Steve Brewin wrote:
>>
>>> See attached component diagram. Obviously I can elaborate to
>>> Class diagrams
>>> if required.
>>>
>>> All, please remember, this is just one way to solve the problem and is
>>> posted for discussion.
> 
> 
> If I understood the diagram you are for using simple java beans as 
> configuration object (or even interfaces like we already do with 
> protocol handlers or with the fetchmail configuration) and refactor our 
> components to use a setConfiguration(ComponentConfigurationBean conf) 
> instead of the avalon configure(Configuration conf).
> 
> Then you would use an Mbean implementation using CommonsConfiguration 
> (possibly mutable configurations) for the load/save operations.
> 
> This is clean and I like it, but maybe this works fine only for top 
> level components and not for generated components.
> 
> How would you handle the SMTP Command Handler configuration, for example?
> 
> Currently the SMTPHandlerChain read the Avalon's Configuration received 
> and look for "handler" sub-configuration. The handlers are Configurable 
> objects and they know how to load their own configuration.
> 
> If SMTPHandlerChain received a Bean and not a hierarchical Configuration 
> object this would not be possible if you don't want to read and evaluate 
> the handlers configuration when you instantiate the first top level 
> component.
> 
> Currently we have 11 classes (excluding tests) using the 
> "ContainerUtil.configure(" method: This means that in 11 instances we 
> directly delegate the configuration to a child object (like the example 
> I did for SMTPHandlerChain).
> 
> To apply the pattern you proposed we have to find out a solution for 
> each of this 11 specific use of the Configuration object.
> 
> 2 on 11 are not a problem: POP3Server and SMTPServer. But we want to 
> remove the usage of a hierarchical Configuration object (being it Avalon 
> Configuration or the direct use of Commons' HiearchicalConfiguration) we 
> should refactor the other 9.
> 
> The analysis of the 9 solutions is too much for this discussion: I will 
> concentrate on the SMTPHandlerChain issue I spotted before. Have you any 
> proposal on that?
> 
> Stefano
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
> For additional commands, e-mail: server-dev-help@james.apache.org
> 
> 


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


Re: [LONG] Re: [jira] Commented: (JAMES-495) Decide how to replace Avalon Configuration

Posted by "Alan D. Cabrera" <li...@toolazydogs.com>.
Stefano Bagnara wrote:
> This is a big message and I don't have too much time, but it deserve 
> some questions/answers
>
> Bernd Fondermann wrote:
>> I'd like to share some thoughts on a future configuration 
>> architecture within James.
>>
>> = Roles involved in configuration process =
>> [...
>> = Some observations =
>>
>> - Tight coupling between Configuration and Configurable -
>>
>> In James, Configurables themselves read and even parse values from 
>> the ConfigContainer once on startup (method configure()) and often 
>> there are no setter methods (probably to make the components public 
>> interface more lean). That makes it difficult to change those values 
>> dynamically at runtime, e.g. through JMX.
>>
>> The mandatory use of DefaultConfiguration here also makes the unit 
>> test code much more verbose than neccessary
> >
>> = Propositions =
>>
>> - Setters -
>>
>> Let's add setters for all kinds of configuration parameters to the 
>> Configurables in James. If a parameter cannot be set after a 
>> component has become ready or live, the setter throws an 
>> AlreadyConfiguredRuntimeException.
>> This would signal that the component is unable to cope with the 
>> change and that the component would have to be restarted for the 
>> change to become effective.
>> Let's not have the Configurables parse textual configuration 
>> parameters into IPs, integers etc.
>>
>> This could be started soon.
>>
>> (BTW, this topic is not exactly JAMES-494, which deals with dependent 
>> service injection. Here, I am talking about the internal fields a 
>> Configurable populates by reading the configuration.)
>
> I would not like to use setters for components that have a lot of 
> configurations. This would bloat the whole code.

Can you explain your assertion?  The reason for me asking this is 
probably because I'm not totally up to speed w/ the architecture.


Regards,
Alan



---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


Re: [LONG] Re: [jira] Commented: (JAMES-495) Decide how to replace Avalon Configuration

Posted by Bernd Fondermann <bf...@brainlounge.de>.
Stefano Bagnara wrote:
> This is a big message and I don't have too much time, but it deserve 
> some questions/answers
> 
> Bernd Fondermann wrote:
> 
>> = Propositions =
>>
>> - Setters -
>>
>> Let's add setters for all kinds of configuration parameters to the 
>> Configurables in James. If a parameter cannot be set after a component 
>> has become ready or live, the setter throws an 
>> AlreadyConfiguredRuntimeException.
>> This would signal that the component is unable to cope with the change 
>> and that the component would have to be restarted for the change to 
>> become effective.
>> Let's not have the Configurables parse textual configuration 
>> parameters into IPs, integers etc.
>>
>> This could be started soon.
>>
>> (BTW, this topic is not exactly JAMES-494, which deals with dependent 
>> service injection. Here, I am talking about the internal fields a 
>> Configurable populates by reading the configuration.)
> 
> 
> I would not like to use setters for components that have a lot of 
> configurations. This would bloat the whole code.
> Maybe we should use configuration objects (dto) for complex configurations.
> ConfigurationObjects (or single configuration properties) should be 
> immutable, so if you want to reconfigure you have to create a new 
> configuration and use the setter to reconfigure the component.

If objects have too much setters they probably have too much fields. 
Having too much fields makes classes smell and they should become 
refactoring targets. the bloat should not be the setters problem.

The refactoring could be to group field variables into 1..n classes 
depending on which belong together semantically.

This magically reduces the amount of setters.

> 
> When do we validate a configuration?

Syntactically: on mapper level. semantically: on Configurable level.

> Syntax validation and some logical validation could be done in the 
> mapper, but what for business logic configuration constraints?
> 
> Maybe we currently have code in the configure methods that could not be 
> done outside the component (Sorry I don't  have examples now).

Definitively. Very important point.
We'd still in many cases have to initialize a component. I am currently 
trying to get (as far as possible) this code/logic out of 
initialize()/configure() into separate and (for now) private methods. 
These are candidates to be called from outside in the future.

It is the very nice side-effect that those sometimes a bit bloated 
methods look much more fresh.

> 
>> - Restarting components -
>>
>> Restarting (=redeploying) a component as the configuration was altered 
>> is not an easy thing to do, IMHO. (Its easy if components are idle, 
>> don't hold any resources and there are no dependencies between 
>> components. That's not the canonical case.) It probably in the end 
>> appears that the only reliable solution is to shut down the server and 
>> reboot. So I would propose to support only dynamic changes the 
>> component can handle while running and not support changes which would 
>> need components to be restarted. The latter would have to be done 
>> offline then.
>>
>> Maybe there is a solution to this problem in some container we come up 
>> with. It's enough work to cope with simple configuration changes in 
>> the first place.
> 
> 
> Imho we should find a way to reconfiugre some of them.
> As an example I this we should be able to restart the SpoolManager 
> without restarting SMTPServer and POP3Server, restart the SMTPServer 
> without restarting the SpoolManager and so on.
> It would be really useful now that we also have fastfail to restart and 
> reconfigure SMTPServer or SpoolManager without having to restart the 
> whole server!
> Imho it should not be so difficult to do this at least for major 
> indipendend components (SpoolManager, SMTPServer, POP3Server, 
> RemoteManager...).

Certainly would be great to have it. Just want to make one step before 
the other.
We'll surely all get into a nice life(re)cycling discussion one sunny 
day. ;-)

> I also would really like to know what are the ideas of Peter Royal on 
> configuration. He worked on Avalon/Phoenix and he now works with OSGi so 
> I think he could give us really precious hints about this issue!

Should we put together some concrete questions for him?

   Bernd

---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


Re: [LONG] Re: [jira] Commented: (JAMES-495) Decide how to replace Avalon Configuration

Posted by Stefano Bagnara <ap...@bago.org>.
This is a big message and I don't have too much time, but it deserve 
some questions/answers

Bernd Fondermann wrote:
> I'd like to share some thoughts on a future configuration architecture 
> within James.
> 
> = Roles involved in configuration process =
> [...
> = Some observations =
> 
> - Tight coupling between Configuration and Configurable -
> 
> In James, Configurables themselves read and even parse values from the 
> ConfigContainer once on startup (method configure()) and often there are 
> no setter methods (probably to make the components public interface more 
> lean). That makes it difficult to change those values dynamically at 
> runtime, e.g. through JMX.
> 
> The mandatory use of DefaultConfiguration here also makes the unit test 
> code much more verbose than neccessary
 >
> = Propositions =
> 
> - Setters -
> 
> Let's add setters for all kinds of configuration parameters to the 
> Configurables in James. If a parameter cannot be set after a component 
> has become ready or live, the setter throws an 
> AlreadyConfiguredRuntimeException.
> This would signal that the component is unable to cope with the change 
> and that the component would have to be restarted for the change to 
> become effective.
> Let's not have the Configurables parse textual configuration parameters 
> into IPs, integers etc.
> 
> This could be started soon.
> 
> (BTW, this topic is not exactly JAMES-494, which deals with dependent 
> service injection. Here, I am talking about the internal fields a 
> Configurable populates by reading the configuration.)

I would not like to use setters for components that have a lot of 
configurations. This would bloat the whole code.
Maybe we should use configuration objects (dto) for complex configurations.
ConfigurationObjects (or single configuration properties) should be 
immutable, so if you want to reconfigure you have to create a new 
configuration and use the setter to reconfigure the component.

When do we validate a configuration?

Syntax validation and some logical validation could be done in the 
mapper, but what for business logic configuration constraints?

Maybe we currently have code in the configure methods that could not be 
done outside the component (Sorry I don't  have examples now).

> - Restarting components -
> 
> Restarting (=redeploying) a component as the configuration was altered 
> is not an easy thing to do, IMHO. (Its easy if components are idle, 
> don't hold any resources and there are no dependencies between 
> components. That's not the canonical case.) It probably in the end 
> appears that the only reliable solution is to shut down the server and 
> reboot. So I would propose to support only dynamic changes the component 
> can handle while running and not support changes which would need 
> components to be restarted. The latter would have to be done offline then.
> 
> Maybe there is a solution to this problem in some container we come up 
> with. It's enough work to cope with simple configuration changes in the 
> first place.

Imho we should find a way to reconfiugre some of them.
As an example I this we should be able to restart the SpoolManager 
without restarting SMTPServer and POP3Server, restart the SMTPServer 
without restarting the SpoolManager and so on.
It would be really useful now that we also have fastfail to restart and 
reconfigure SMTPServer or SpoolManager without having to restart the 
whole server!
Imho it should not be so difficult to do this at least for major 
indipendend components (SpoolManager, SMTPServer, POP3Server, 
RemoteManager...).

> - Configuration Mappers -
> 
> Let's introduce a bunch of Mapper objects, which are each able to take a 
> sub-Avalon-DefaultConfiguration, parse the Strings etc and inject the 
> specific data into the specific Configurable objects. When the avalon 
> configuration is eventually abandoned or deprecated, let's have another 
> bunch of Mappers for mapping from commons-configuration or whatever we 
> decide upon.
> Let's not use those dumb ConfigContainers with no logic. The mappers 
> could also be the ConfigContainers. (I'd volunteer to refactor Postage 
> accordingly.)
> 
> Step by step we would move the access to DefaultConfiguration out of the 
> Configurables into specialized mapper classes.

I agree.

> - JMX -
> 
> MBeans would more or less directly execute operations by using the 
> Configurable's setters and methods like it is done at present. They 
> would not necessarily use the configuration framework.
> 
> JMX is not good at internally exposing component management. Geronimo 
> has explicitly moved away from being a MBean-based kernel, JBoss kind of 
> suffers from being one.
> 
> The reason for that is that the intended JMX granularity (the way a 
> remote managing person would like to have it) often does not match with 
> the server-internal granularity of 
> Configurables/modules/components/classes.
> JMX is good for being a remote 'high-level' API for management.
> 
> Let's go on with using JMX as we currently do, more or less.

I agree also on this.

I also would really like to know what are the ideas of Peter Royal on 
configuration. He worked on Avalon/Phoenix and he now works with OSGi so 
I think he could give us really precious hints about this issue!

Stefano


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org