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 <be...@googlemail.com> on 2006/10/02 15:03:41 UTC

Re: OSGi: First steps with Knopflerfish

On 9/30/06, Joachim Draeger <jd...@joachim-draeger.de> wrote:
> Am Samstag, den 30.09.2006, 12:07 +0200 schrieb Bernd Fondermann:
>
> > > Doing some POJOification can't be bad but I don't consider it a blocker.
> > > How do you know HOW to decouple components when you don't know where to
> > > go? When you decouple it from something you have to couple it to another
> > > thing. Being a bit container dependent can make things clearer.
> >
> > Agreed. But the situation as it is now is, that the components are
> > heavily coupled with
> > a. phoenix lifecycle interfaces
>
> What is the problem with them? In another container the Interface might
> be named Lifecycle and the methods activate() and deactive(). Just
> refactoring.  The question is how the things done in
> configure/start/stop/initialize/dispose fit into other frameworks.

Three problems:
1. component must import lifecycle stuff and becomes container aware
(_not_ IoC in the narrow sense!)
2. lifecycle methods cannot simply be "renamed" if there are
ServiceManagers stored in the component itself (bad. sometimes
difficult to refactor, when you get the SM in the first call (say:
initialize()) and need it in the second (say: configure()))
3. livecycle method of different containers are not neccessarily
compatible/interchangable

> > b. avalon configuration stuff
>
> Yes, some POJOification should be done here, too. Did we decide how to
> do this?

No, not yet. We have setters on most components, but much of the
configuration and intialization is still very very dependent on the
framework. some consider this as being ok, I don't.

> IMO classes with only a few configuration options should carry their
> attributes + getters/setters themselves. More complicated configs should
> be moved to separate pure POJO beans.

Exactly.

> > c. avalon/phoenix ServiceManager
>
> AFAIK POJOification in progress, or even finished?

in progress, sometimes delicate.

> > d. avalon logger (superclass)
>
> What do you suppose? I consider this as refactoring. :-)

Well, logging is not a semantical super-construct of a component, it
is a side-aspect.
By extending AbstractLogEnabled you hinder more semantically
beneficial class hierarchies. Bad.

> > e. verbose + redundant config in environment.xml, *.xinfo
>
> You mean assembly.xml?

Yes, sorry... should have checked that beforehand.

> Is there a possibility to avoid that redundancy
> in Avalon? Apart from that I find them both quite readable.

You have to do the following:
1. Declare a component
2. Declare for the component, which other components it references
3. Declare for the SM, which components it propagates to each component
4. Implement in the service() method a lookup and typecast.

This is not inversion of control, this is "all stages control".
It is redundant, since James uses full qualified class names everywhere.
With 4.) in place, 2) and 3) become uneccessary, no additional
information is added, being of any use for SM or the component.

> > This is bad (IMHO) even if you do _not_ want to change container.
> > For example, look at the unit tests and the setup() methods. much too
> > much has to be done there to execute a simple test. this is mock-up
> > hell ;-)
>
> I completely agree, but I don't consider this as a blocker for
> evaluating different containers or even try to wire some James stuff
> together in order to try it inside an OSGi bundle.

Right. BTW, I am not opposing OSGi. There have other containers been
brought into the discussion, like Spring, xbeans, AFAIR. Stefano did a
poll which one should be preferred, with diverging opinions.

My take on this is: Let's fix our components at first, then decide
about switching containers.

  Bernd

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


Re: OSGi: First steps with Knopflerfish

Posted by Bernd Fondermann <be...@googlemail.com>.
Didn't have the time to get back to this thread sooner, sorry.

more inline...

  Bernd

On 10/3/06, Stefano Bagnara <ap...@bago.org> wrote:
> Bernd Fondermann wrote:
> > On 10/2/06, Stefano Bagnara <ap...@bago.org> wrote:
> >> Bernd Fondermann wrote:
> >> >> > a. phoenix lifecycle interfaces
> >> >>
> >> >> What is the problem with them? In another container the Interface
> >> might
> >> >> be named Lifecycle and the methods activate() and deactive(). Just
> >> >> refactoring.  The question is how the things done in
> >> >> configure/start/stop/initialize/dispose fit into other frameworks.
> >> >
> >> > Three problems:
> >> > 1. component must import lifecycle stuff and becomes container aware
> >> > (_not_ IoC in the narrow sense!)
> >>
> >> THis is easy: don't implement interfaces in the main object, create an
> >> extension for that object implementing all of the lifecycle interfaces
> >> needed.
> >
> > :-) coming up with that solution strategy is easy. implementing this
> > solution isn't. ;-)
>
> The problem is not that the components are container aware: the problem
> is that the components do what the containers should do with
> child-components. So we have components that manually manage the
> lifecycle for the nested components. Removing this thing is not easy.

ok, I reviewed the lifecycle code and recognized those nested
components. I wasn't aware of this.

> If I find the time (I already have too much things in my todo list) I
> would like to elaborate something on component-factories to be used to
> be able to be container-agnostic when working on jspf: we started having
> a bunch of services (SPFChecker, DNSService, Logger, SPFParser) that
> could be used by child components.
> If I'll do this and I'll be happy with the result I will say something
> to get your opinions.

ok, fine.

> >> > 2. lifecycle methods cannot simply be "renamed" if there are
> >> > ServiceManagers stored in the component itself (bad. sometimes
> >> > difficult to refactor, when you get the SM in the first call (say:
> >> > initialize()) and need it in the second (say: configure()))
> >>
> >> Right. And we should try to isolate the service() call and the
> >> servicemanager references from our code: it should be easy.
> >
> > not always easy, but: yes.
>
> Can you point out a difficult scenario? I often think that trying to
> find a solution to one of the concrete (possibily one of the difficult
> issue) is much better than talking theoretically.

For example AbstractJamesService.
The service method receives the ServiceManager, which is then locally
stored and re-used in initialize().

Another case is the one you described above: when a component needs to
configure subcomponents, SM is stored locally and the component does
lifecycling on its own.

> >> >> > b. avalon configuration stuff
> >> >>
> >> >> Yes, some POJOification should be done here, too. Did we decide how to
> >> >> do this?
> >> >
> >> > No, not yet. We have setters on most components, but much of the
> >> > configuration and intialization is still very very dependent on the
> >> > framework. some consider this as being ok, I don't.
> >>
> >> I'm happy with avalon lifecycle dependencies: I would like to remove the
> >> Serviceable/ServiceManager stuff (in favor of setters/enabling
> >> interfaces). I would like to not be dependant on the
> >> Avalon-Configuration stuff (I don't know how).
> >
> > ok, that would be the base for a common goal. it would already be a
> > great achievement, even when still running under avalon lifecycle.
>
> I agree, and we can skip other container discussions until we have not
> fixed this starting points.
>
> I would like to know if you (and others) agree that the 2 points
> (Service / Configuration) are "must" steps anyway, indipendently from
> the final container we'll choose.

+1

> >> >> > d. avalon logger (superclass)
> >> >>
> >> >> What do you suppose? I consider this as refactoring. :-)
> >> >
> >> > Well, logging is not a semantical super-construct of a component, it
> >> > is a side-aspect.
> >> > By extending AbstractLogEnabled you hinder more semantically
> >> > beneficial class hierarchies. Bad.
> >>
> >> You simply have to remove "extends AbstractLogEnabled", add "implements
> >> LogEnabled" and add 2 methods copied from AbstractLogEnabled and you'll
> >> have fixed this. So this is a non-issue.
> >
> > a "non-issue"?? From writing unit test/mock up objects I am under the
> > impression it _is_ an issue, but I will have to have a look again to
> > come up with concrete examples.
>
> Yes please. Otherwise I fear I've not understood the problem.

Currently, for AbstractJamesServices, the class hierarchie is as follows:

o.a.j.core.AbstractJamesService
extends
o.a.a.cornerstone.services.connection.AbstractHandlerFactory
extends
o.a.a.framework.logger.LogEnabled

So in this case there is no _easy_ way to go from class
AbstractLogEnabled to interface LogEnabled.
And moving AbstractLogEnabled/LogEnabled from Avalon to James code is
not so simple, too. Because AbstractHandlerFactory is not from James.
AbstractJamesService is subclassed by NNTPServer, SMPTServer,
RemoteManager and POP3Server.

> Here is what I understood you want to do:
> 1) Search "extends AbstractLogEnabled" => 61 classes.
> 2) for each:
>    a. Remove "extends AbstractLogEnabled" add "implements LogEnabled"
>    b. add a "private Logger logger" field
>    c. add an enableLogging(Logger logger) method as the setter
>    d. add a Logger getLogger() method as the getter
> 3) Search "setupLogger" => 4 classes.
> 4) for each:
>    a. implement the setupLogger method that run a call a
> getLogger().getChildLogger() and call the enableLogging for the child
> component.
> 5) Champagne: we don't have an abstract root class (but Object) anymore.
>
> Is this what you want?
> What is the advantages you get from this change?

Champagne :-)
Plus the possibility to extend a super class which actually adds value
to the child class.

  Bernd

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


Re: OSGi: First steps with Knopflerfish

Posted by Stefano Bagnara <ap...@bago.org>.
Bernd Fondermann wrote:
> On 10/2/06, Stefano Bagnara <ap...@bago.org> wrote:
>> Bernd Fondermann wrote:
>> >> > a. phoenix lifecycle interfaces
>> >>
>> >> What is the problem with them? In another container the Interface 
>> might
>> >> be named Lifecycle and the methods activate() and deactive(). Just
>> >> refactoring.  The question is how the things done in
>> >> configure/start/stop/initialize/dispose fit into other frameworks.
>> >
>> > Three problems:
>> > 1. component must import lifecycle stuff and becomes container aware
>> > (_not_ IoC in the narrow sense!)
>>
>> THis is easy: don't implement interfaces in the main object, create an
>> extension for that object implementing all of the lifecycle interfaces
>> needed.
> 
> :-) coming up with that solution strategy is easy. implementing this
> solution isn't. ;-)

The problem is not that the components are container aware: the problem 
is that the components do what the containers should do with 
child-components. So we have components that manually manage the 
lifecycle for the nested components. Removing this thing is not easy.

If I find the time (I already have too much things in my todo list) I 
would like to elaborate something on component-factories to be used to 
be able to be container-agnostic when working on jspf: we started having 
a bunch of services (SPFChecker, DNSService, Logger, SPFParser) that 
could be used by child components.
If I'll do this and I'll be happy with the result I will say something 
to get your opinions.

>> > 2. lifecycle methods cannot simply be "renamed" if there are
>> > ServiceManagers stored in the component itself (bad. sometimes
>> > difficult to refactor, when you get the SM in the first call (say:
>> > initialize()) and need it in the second (say: configure()))
>>
>> Right. And we should try to isolate the service() call and the
>> servicemanager references from our code: it should be easy.
> 
> not always easy, but: yes.

Can you point out a difficult scenario? I often think that trying to 
find a solution to one of the concrete (possibily one of the difficult 
issue) is much better than talking theoretically.

>> The most
>> difficult part is how we currently propagate the ServiceManager to the
>> Mailets (via Mailet Context).
>> How should we propagate such dependencies to Mailets?
> 
> For Mailets, I don't know. There has been a thread about it and no one
> yet came up with a good solution, AFAIR.

I remember the same: I would like to use enabling interfaces for 
mailets, but it seems that at least Noel is on the opposite side 
proposing JNDI lookups.

>> > 3. livecycle method of different containers are not neccessarily
>> > compatible/interchangable
>>
>> And this is the bigger issue: "container agnostic components" are only
>> an utopia. As soon as you write not-hello-world componets you will have
>> requirements for the lifecycle and the dependencies behaviours and this
>> will need lines of code or much lines of container configurations to be
>> addressed. Saying that your component is container agnostic simply means
>> that the component is not complete and will need much more work in order
>> to make it working in any specific container.
> 
> ooh-kaay... do you consider the whole IoC approach,
> separation-of-concerns, low coupling, ... as utopia(s)? Up to some
> point it works quite well in reality, I think.

Maybe I have not been clear enough: I'm a big fan of IoC, but Avalon is 
all about IoC (just think that it is the only framework enforcing IoC 
for logging). This is unfortunately enough to be container agnostic.
Being container agnostic means simply separate the container agnostic 
things from the container specific things: you will still have both in 
the resulting application/component and most times the container 
specific part is not trivial.

Btw this is a too much theoretical discussion: I think that we all know 
what is the real world out there.

>> >> > b. avalon configuration stuff
>> >>
>> >> Yes, some POJOification should be done here, too. Did we decide how to
>> >> do this?
>> >
>> > No, not yet. We have setters on most components, but much of the
>> > configuration and intialization is still very very dependent on the
>> > framework. some consider this as being ok, I don't.
>>
>> I'm happy with avalon lifecycle dependencies: I would like to remove the
>> Serviceable/ServiceManager stuff (in favor of setters/enabling
>> interfaces). I would like to not be dependant on the
>> Avalon-Configuration stuff (I don't know how).
> 
> ok, that would be the base for a common goal. it would already be a
> great achievement, even when still running under avalon lifecycle.

I agree, and we can skip other container discussions until we have not 
fixed this starting points.

I would like to know if you (and others) agree that the 2 points 
(Service / Configuration) are "must" steps anyway, indipendently from 
the final container we'll choose.

I think that this is true for the first but I'm not yet sure about the 
Configuration thing: OSGi has 2 default services for Preferences and 
Configurations and they do not seem to have a direct mapping on 
Configurations used by other containers/framework.

>> >> > d. avalon logger (superclass)
>> >>
>> >> What do you suppose? I consider this as refactoring. :-)
>> >
>> > Well, logging is not a semantical super-construct of a component, it
>> > is a side-aspect.
>> > By extending AbstractLogEnabled you hinder more semantically
>> > beneficial class hierarchies. Bad.
>>
>> You simply have to remove "extends AbstractLogEnabled", add "implements
>> LogEnabled" and add 2 methods copied from AbstractLogEnabled and you'll
>> have fixed this. So this is a non-issue.
> 
> a "non-issue"?? From writing unit test/mock up objects I am under the
> impression it _is_ an issue, but I will have to have a look again to
> come up with concrete examples.

Yes please. Otherwise I fear I've not understood the problem.

Here is what I understood you want to do:
1) Search "extends AbstractLogEnabled" => 61 classes.
2) for each:
   a. Remove "extends AbstractLogEnabled" add "implements LogEnabled"
   b. add a "private Logger logger" field
   c. add an enableLogging(Logger logger) method as the setter
   d. add a Logger getLogger() method as the getter
3) Search "setupLogger" => 4 classes.
4) for each:
   a. implement the setupLogger method that run a call a 
getLogger().getChildLogger() and call the enableLogging for the child 
component.
5) Champagne: we don't have an abstract root class (but Object) anymore.

Is this what you want?
What is the advantages you get from this change?

>> I would like to keep the IoC style for Loggers: I always hated the
>> static way to access loggers that 99% of projects out there use. One of
>> the things because Avalon is great is for trying to enforce IoC for
>> logging (IMO).
> 
> IoC loggers are good... never thought about hating those static
> loggers, but will consider this for the future ;-)
> 
>  Bernd

If you'll manage *static* loggers in environment with complex 
classloaders hierarchy you will hate them for sure.. you'll revert to 
non-static loggers with static factories, but I already hate this anyway ;-)

Stefano


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


Re: OSGi: First steps with Knopflerfish

Posted by Bernd Fondermann <be...@googlemail.com>.
On 10/2/06, Stefano Bagnara <ap...@bago.org> wrote:
> Bernd Fondermann wrote:
> >> > a. phoenix lifecycle interfaces
> >>
> >> What is the problem with them? In another container the Interface might
> >> be named Lifecycle and the methods activate() and deactive(). Just
> >> refactoring.  The question is how the things done in
> >> configure/start/stop/initialize/dispose fit into other frameworks.
> >
> > Three problems:
> > 1. component must import lifecycle stuff and becomes container aware
> > (_not_ IoC in the narrow sense!)
>
> THis is easy: don't implement interfaces in the main object, create an
> extension for that object implementing all of the lifecycle interfaces
> needed.

:-) coming up with that solution strategy is easy. implementing this
solution isn't. ;-)

>
> > 2. lifecycle methods cannot simply be "renamed" if there are
> > ServiceManagers stored in the component itself (bad. sometimes
> > difficult to refactor, when you get the SM in the first call (say:
> > initialize()) and need it in the second (say: configure()))
>
> Right. And we should try to isolate the service() call and the
> servicemanager references from our code: it should be easy.

not always easy, but: yes.

> The most
> difficult part is how we currently propagate the ServiceManager to the
> Mailets (via Mailet Context).
> How should we propagate such dependencies to Mailets?

For Mailets, I don't know. There has been a thread about it and no one
yet came up with a good solution, AFAIR.

> > 3. livecycle method of different containers are not neccessarily
> > compatible/interchangable
>
> And this is the bigger issue: "container agnostic components" are only
> an utopia. As soon as you write not-hello-world componets you will have
> requirements for the lifecycle and the dependencies behaviours and this
> will need lines of code or much lines of container configurations to be
> addressed. Saying that your component is container agnostic simply means
> that the component is not complete and will need much more work in order
> to make it working in any specific container.

ooh-kaay... do you consider the whole IoC approach,
separation-of-concerns, low coupling, ... as utopia(s)? Up to some
point it works quite well in reality, I think.

> >> > b. avalon configuration stuff
> >>
> >> Yes, some POJOification should be done here, too. Did we decide how to
> >> do this?
> >
> > No, not yet. We have setters on most components, but much of the
> > configuration and intialization is still very very dependent on the
> > framework. some consider this as being ok, I don't.
>
> I'm happy with avalon lifecycle dependencies: I would like to remove the
> Serviceable/ServiceManager stuff (in favor of setters/enabling
> interfaces). I would like to not be dependant on the
> Avalon-Configuration stuff (I don't know how).

ok, that would be the base for a common goal. it would already be a
great achievement, even when still running under avalon lifecycle.

> >> > d. avalon logger (superclass)
> >>
> >> What do you suppose? I consider this as refactoring. :-)
> >
> > Well, logging is not a semantical super-construct of a component, it
> > is a side-aspect.
> > By extending AbstractLogEnabled you hinder more semantically
> > beneficial class hierarchies. Bad.
>
> You simply have to remove "extends AbstractLogEnabled", add "implements
> LogEnabled" and add 2 methods copied from AbstractLogEnabled and you'll
> have fixed this. So this is a non-issue.

a "non-issue"?? From writing unit test/mock up objects I am under the
impression it _is_ an issue, but I will have to have a look again to
come up with concrete examples.

> I would like to keep the IoC style for Loggers: I always hated the
> static way to access loggers that 99% of projects out there use. One of
> the things because Avalon is great is for trying to enforce IoC for
> logging (IMO).

IoC loggers are good... never thought about hating those static
loggers, but will consider this for the future ;-)

  Bernd

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


Re: OSGi: First steps with Knopflerfish

Posted by Stefano Bagnara <ap...@bago.org>.
Bernd Fondermann wrote:
>> > a. phoenix lifecycle interfaces
>>
>> What is the problem with them? In another container the Interface might
>> be named Lifecycle and the methods activate() and deactive(). Just
>> refactoring.  The question is how the things done in
>> configure/start/stop/initialize/dispose fit into other frameworks.
> 
> Three problems:
> 1. component must import lifecycle stuff and becomes container aware
> (_not_ IoC in the narrow sense!)

THis is easy: don't implement interfaces in the main object, create an 
extension for that object implementing all of the lifecycle interfaces 
needed.

> 2. lifecycle methods cannot simply be "renamed" if there are
> ServiceManagers stored in the component itself (bad. sometimes
> difficult to refactor, when you get the SM in the first call (say:
> initialize()) and need it in the second (say: configure()))

Right. And we should try to isolate the service() call and the 
servicemanager references from our code: it should be easy. The most 
difficult part is how we currently propagate the ServiceManager to the 
Mailets (via Mailet Context).
How should we propagate such dependencies to Mailets?

> 3. livecycle method of different containers are not neccessarily
> compatible/interchangable

And this is the bigger issue: "container agnostic components" are only 
an utopia. As soon as you write not-hello-world componets you will have 
requirements for the lifecycle and the dependencies behaviours and this 
will need lines of code or much lines of container configurations to be 
addressed. Saying that your component is container agnostic simply means 
that the component is not complete and will need much more work in order 
to make it working in any specific container.

>> > b. avalon configuration stuff
>>
>> Yes, some POJOification should be done here, too. Did we decide how to
>> do this?
> 
> No, not yet. We have setters on most components, but much of the
> configuration and intialization is still very very dependent on the
> framework. some consider this as being ok, I don't.

I'm happy with avalon lifecycle dependencies: I would like to remove the 
Serviceable/ServiceManager stuff (in favor of setters/enabling 
interfaces). I would like to not be dependant on the 
Avalon-Configuration stuff (I don't know how).

>> IMO classes with only a few configuration options should carry their
>> attributes + getters/setters themselves. More complicated configs should
>> be moved to separate pure POJO beans.
> 
> Exactly.

How to manage this for parent-child components? We have many of them.
Who parses the configuration file for the child components created by a 
top-level component? Currently we delegate the parsing to the child, but 
we can't keep this if we want POJOs/Setters as the configuration.

>> > c. avalon/phoenix ServiceManager
>>
>> AFAIK POJOification in progress, or even finished?

I would say in progress.. But we have not made progresses lately.

> in progress, sometimes delicate.

sometimes => often

>> > d. avalon logger (superclass)
>>
>> What do you suppose? I consider this as refactoring. :-)
> 
> Well, logging is not a semantical super-construct of a component, it
> is a side-aspect.
> By extending AbstractLogEnabled you hinder more semantically
> beneficial class hierarchies. Bad.

You simply have to remove "extends AbstractLogEnabled", add "implements 
LogEnabled" and add 2 methods copied from AbstractLogEnabled and you'll 
have fixed this. So this is a non-issue.
I would like to keep the IoC style for Loggers: I always hated the 
static way to access loggers that 99% of projects out there use. One of 
the things because Avalon is great is for trying to enforce IoC for 
logging (IMO).

>> > e. verbose + redundant config in environment.xml, *.xinfo
>>
>> You mean assembly.xml?
> 
> Yes, sorry... should have checked that beforehand.
> 
>> Is there a possibility to avoid that redundancy
>> in Avalon? Apart from that I find them both quite readable.
> 
> You have to do the following:
> 1. Declare a component
> 2. Declare for the component, which other components it references
> 3. Declare for the SM, which components it propagates to each component
> 4. Implement in the service() method a lookup and typecast.
> 
> This is not inversion of control, this is "all stages control".
> It is redundant, since James uses full qualified class names everywhere.
> With 4.) in place, 2) and 3) become uneccessary, no additional
> information is added, being of any use for SM or the component.

So you think that autodiscovery is the way? Imho is not sufficient that 
a class implement an interface to say that it is the choosen 
implementation for that service, so you'll need the assembly for 
non-trivial configurations.

>> > This is bad (IMHO) even if you do _not_ want to change container.
>> > For example, look at the unit tests and the setup() methods. much too
>> > much has to be done there to execute a simple test. this is mock-up
>> > hell ;-)
>>
>> I completely agree, but I don't consider this as a blocker for
>> evaluating different containers or even try to wire some James stuff
>> together in order to try it inside an OSGi bundle.
> 
> Right. BTW, I am not opposing OSGi. There have other containers been
> brought into the discussion, like Spring, xbeans, AFAIR. Stefano did a
> poll which one should be preferred, with diverging opinions.
> 
> My take on this is: Let's fix our components at first, then decide
> about switching containers.
> 
>  Bernd


I almost agree on this, because I think we should stick to avalon as 
long as possible ;-) but I think that the configuration thing and the 
dependency management thing cannot and will never been container 
agnostic, so we'll have to make a choice before and implement it after.

If there was a container providing a good infrastructure for reloadable, 
gui administrable configurations I would try to use it. Maybe eclipse 
will release its own preference framework sooner or later but it has a 
lot of dependencies on SWT and other eclipse bundles.

Stefano


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