You are viewing a plain text version of this content. The canonical link for it is here.
Posted to mailet-api@james.apache.org by Serge Knystautas <sk...@gmail.com> on 2006/11/11 01:55:21 UTC

Re: injection and/or JNDI WAS Re: On Global vs Local jndi naming

On 11/9/06, Andrew C. Oliver <an...@superlinksoftware.com> wrote:
> (I do not presuppose EJB3 or this form of attribute based configuration,
> just it was what immediately came to mind
> when you asked for an example)

Thanks.

> on the
> other hand with no jndi its simple and reduces a requirement on
> implementors of mailets and mailet containers.

Yeah, I'm biased, but I like think this is part of the advantages of
just dependency injection.

I guess I'm in the same boat as you though Andy... I'm not absolutely
against JNDI, and if there are some conventions that can be
standardized, so be it.

-- 
Serge Knystautas
Lokitech >> software . strategy . design >> http://www.lokitech.com
p. 301.656.5501
e. sergek@lokitech.com

Re: injection and/or JNDI WAS Re: On Global vs Local jndi naming

Posted by Stefano Bagnara <ap...@bago.org>.
I agree with Andrew.

1) Imho we can target java 5 for next mailet apis (so we can use 
annotations)
2) Mailets dependencies/configurability *declaration* must be defined by 
the api
3) Mailets configuration and deployment wiring are vendor specific and 
anyone will decide how to provide this.

If we don't want to require java 5 then we have to define a mean for the 
mailet to declare their dependencies: an xml file (maybe xdoclet 
generated) or the implementation of specific declaring interfaces are 
two alternative solutions. My personal idea is that we are discussing a 
future api while sun is releasing java 6 and java 2 1.4 will be probably 
EOLed soon.

Stefano

Andrew C. Oliver wrote:
> (sorry if there are two I fat fingered)
>> I'm still waiting for someone to give a sensible DI example that would
>> show how we deal with the fact that there can be an unlimited number
>> of unknown dependancies. 
> [...]
> CONTRACTS:
> Constructors are called in any order.  Each mailet has a method called 
> start.
> Each mailet has a method called stop.
> Attributes are "set" after construction but before "start".
> Interfaces are proxies (ala java.lang.reflect.Proxy) and thus can be 
> passed before the service is started
> Start is then called once dependencies are satisfied (below).
> Mailets with no <depends>true</depends> are started first.
> Mailets whose dependencies are satisfied are started next (loop).
> Mutual and circular dependencies are not allowed (error).
> JNDI dependencies are satisfied when the jndi lookup exists and the 
> service has been started.
> stops are called in reverse order that starts were called.
> 
> Notes:
> attribute annotations can be either on the implementation or the 
> interface.  constructor annotations must be on the implementation (duh)
> annotations and/or XML are equivalent
> annotations should not be used for configuration (vendor specific 
> example in xml above)
> 
> This is more or less the same idea used for JBoss XMBeans, Geronimo 
> GBeans, and EJB3.


Re: injection and/or JNDI WAS Re: On Global vs Local jndi naming

Posted by Norman Maurer <nm...@byteaction.de>.
I think java5 whould be great...

bye
Norman

Stefano Bagnara schrieb:
> I agree with Andrew.
>
> 1) Imho we can target java 5 for next mailet apis (so we can use
> annotations)
> 2) Mailets dependencies/configurability *declaration* must be defined
> by the api
> 3) Mailets configuration and deployment wiring are vendor specific and
> anyone will decide how to provide this.
>
> If we don't want to require java 5 then we have to define a mean for
> the mailet to declare their dependencies: an xml file (maybe xdoclet
> generated) or the implementation of specific declaring interfaces are
> two alternative solutions. My personal idea is that we are discussing
> a future api while sun is releasing java 6 and java 2 1.4 will be
> probably EOLed soon.
>
> Stefano
>
> Andrew C. Oliver wrote:
>> (sorry if there are two I fat fingered)
>>> I'm still waiting for someone to give a sensible DI example that would
>>> show how we deal with the fact that there can be an unlimited number
>>> of unknown dependancies. 
>> [...]
>> CONTRACTS:
>> Constructors are called in any order.  Each mailet has a method
>> called start.
>> Each mailet has a method called stop.
>> Attributes are "set" after construction but before "start".
>> Interfaces are proxies (ala java.lang.reflect.Proxy) and thus can be
>> passed before the service is started
>> Start is then called once dependencies are satisfied (below).
>> Mailets with no <depends>true</depends> are started first.
>> Mailets whose dependencies are satisfied are started next (loop).
>> Mutual and circular dependencies are not allowed (error).
>> JNDI dependencies are satisfied when the jndi lookup exists and the
>> service has been started.
>> stops are called in reverse order that starts were called.
>>
>> Notes:
>> attribute annotations can be either on the implementation or the
>> interface.  constructor annotations must be on the implementation (duh)
>> annotations and/or XML are equivalent
>> annotations should not be used for configuration (vendor specific
>> example in xml above)
>>
>> This is more or less the same idea used for JBoss XMBeans, Geronimo
>> GBeans, and EJB3.
>
> !EXCUBATOR:1,4558701f53074833495395!



Re: injection and/or JNDI WAS Re: On Global vs Local jndi naming

Posted by "Andrew C. Oliver" <ac...@apache.org>.
(sorry if there are two I fat fingered)
> I'm still waiting for someone to give a sensible DI example that would
> show how we deal with the fact that there can be an unlimited number
> of unknown dependancies. 

mailet.xml
<mailets>
<mailet>
   <name>MyMailet</name>
   <class>org.foo.MyMailetImpl</class>
   <interface>org.foo.MyMailet</interface>
   <constructors>
     <constructor/>
     <constructor>
       <arguments>
         <argument>java.lang.String</argument>
       </arguments>
     </constructor>
   </constructors>
   <attributes>
      <attribute>
         <name>foo</name>
         <type>java.lang.String</type>
         <getter>getFoo</getter>
         <setter>setFoo</setter>
      </attribtue>
      <attribute>  
         <name>MyOtherMailet</name>
         <type>org.foo.MyOtherMailet</type>
         <setter>getMyOtherMailet</setter>
         <depends>true</depends>
      </attribute>
      <attribute>  
         <name>YetAnotherMailet</name>
         <type>org.foo.YetAnotherMailet</type>
         <setter>setYetAnotherMailet</setter>
         <jndi>true</jndi>
         <depends>true</depends>
      </attribute>
   </attributes>
</mailet>
</mailets>

OR 

@org.apache.mailet.Mailet(name="MyMailet"
                          class="org.foo.MyMailet)
public class MyMailetImpl implements MyMailet {
  ... public members snipped ...
  @org.apache.mailet.Constructor
  public MyMailetImpl() {}   

  @org.apache.mailet.Constructor
  public MyMailetImpl(String bar) {
     this.bar = bar;
  }

  @org.apache.mailet.Attribute
  public void setFoo(String foo) {
      this.foo = foo;
  }

  public String getFoo() {
      return this.foo;
  }

  @org.apache.mailet.Attribute(depends=true)
  public void setMyOtherMailet(MyOtherMailet mailet) {
     this.mom = mailet;
  }

  @org.apache.mailet.Attribute(depends=true jndi=true)
  public void setYetAnotherMailet(YetAnotherMailet yam) {
      this.yam = yam;
  }

  public void start() {
  }

  public void stop() {
  }
}


myserver-specific-config.xml (unspecified but example)

<mailet-instance>
  <mailet>
     <name>MyMailet</name>
     <instance-name>MyMailet1</instance-name>
     <constructor>
        <arguments>
          <argument type="java.lang.String">Hi man</argument>
        </arguments>
     </constructor>
     <attributes>
        <attribute name="foo">Hello</attribute>
        <attribute name="MyOtherMailet">MyOtherMailet1</attribute>
        <attribute name="YetAnotherMailet">java://yam</attribute>
     </attributes>
  </mailet>
</mailet-instance>

CONTRACTS:
Constructors are called in any order.  
Each mailet has a method called start.
Each mailet has a method called stop.
Attributes are "set" after construction but before "start".
Interfaces are proxies (ala java.lang.reflect.Proxy) and thus can be 
passed before the service is started
Start is then called once dependencies are satisfied (below).
Mailets with no <depends>true</depends> are started first.
Mailets whose dependencies are satisfied are started next (loop).
Mutual and circular dependencies are not allowed (error).
JNDI dependencies are satisfied when the jndi lookup exists and the 
service has been started.
stops are called in reverse order that starts were called.

Notes:
attribute annotations can be either on the implementation or the 
interface.  
constructor annotations must be on the implementation (duh)
annotations and/or XML are equivalent
annotations should not be used for configuration (vendor specific 
example in xml above)

This is more or less the same idea used for JBoss XMBeans, Geronimo 
GBeans, and EJB3.


Re: injection and/or JNDI WAS Re: On Global vs Local jndi naming

Posted by Joachim Draeger <jd...@gmx.de>.
Am Samstag, den 11.11.2006, 09:14 +0000 schrieb Danny Angus:

> In what way is injection preferable to lookup?

Sorry, I forgot one important point in my previous posting:

Security. When using DI I have full and easy control which services a
Mailet is allowed to use. 
A commercial mailet may come in a binary form without source code.

Joachim



Re: injection and/or JNDI WAS Re: On Global vs Local jndi naming

Posted by "Andrew C. Oliver" <ac...@apache.org>.
Danny Angus wrote:
> On 11/11/06, Serge Knystautas <sk...@gmail.com> wrote:
>
>> Yeah, I'm biased, but I like think this is part of the advantages of
>> just dependency injection.
>
> I'm still waiting for someone to give a sensible DI example that would
> show how we deal with the fact that there can be an unlimited number
> of unknown dependancies.
>
I posted one but for some reason it didn't make it to the list.  I will 
post it again
when I get motivation on Monday.

> Service location allows the consumer of the services to look them up
> as needed, DI requires that the container be made aware of the
> dependance and invoke some mechanism to inject an instance which
> satisfies it.
>
> In what way is injection preferable to lookup?
Lookup doesn't necessarily help with dependence at all.  Meaning you 
just get NPEs all
over the place because the other service isnt' start.  Dependence, 
injection and lookup are
all orthogonal. 
>
> d.



Re: injection and/or JNDI WAS Re: On Global vs Local jndi naming

Posted by Stefano Bagnara <ap...@bago.org>.
100% agreed! I quote it all because this deserve better indexing by 
search engine ;-)

This is one of the most comprehensive list of JNDI (and service locator 
pattern in general) issues I don't like.

And that is to be completed with what Joachim already replied to 
himselft: security. Managing security with JNDI is much harder because 
you need nested contexts and complex containers.

Stefano

Joachim Draeger wrote:
> Am Samstag, den 11.11.2006, 09:14 +0000 schrieb Danny Angus:
>> On 11/11/06, Serge Knystautas <sk...@gmail.com> wrote:
>>
>>> Yeah, I'm biased, but I like think this is part of the advantages of
>>> just dependency injection.
>> I'm still waiting for someone to give a sensible DI example that would
>> show how we deal with the fact that there can be an unlimited number
>> of unknown dependancies.
> 
> IMO exactly "unlimited number of *unknown* dependencies" is a strong
> argument for DI. 
> In a big application it is important to know the dependencies exactly.
> 
>> Service location allows the consumer of the services to look them up
>> as needed, DI requires that the container be made aware of the
>> dependance and invoke some mechanism to inject an instance which
>> satisfies it.
> 
> Making aware a container of dependencies means mostly xml. This is just
> like a formal documentation of the dependencies. You should probably do
> that even when you using a service locator.
> I don't consider it as problematic that the format differs in different
> frameworks. They are quite similar and the process is not error prone. 
> 
> Invoking some mechanism means just calling setters. Likely inside some
> kind of factory. I don't see any magic there. :-) The whole procedure is
> probably just as easy as dealing with JNDI.
> IMO even when using JNDI the Bean should be configured through setters
> by calling a corresponding method or using a factory. 
> (Funny enough: This could even be done by using a generic factory and
> xml ;-)
> This way the consumer had full control and could decide whether to use
> DI or JNDI. 
> 
> 
> Also lookup up services as needed is more flexible I think it is more
> save to check dependencies at initialization. With DI you can do that
> even without creating any instances.
> 
>> In what way is injection preferable to lookup?
> 
> e.g.
>  -  who is affected when I change service A?
>  -  using a wrapper when Mailet X needs a special behavior of service B
>  -  different implementions/instances of Service C for Mailet Y and Z.
>  -  defined, full control of lifecycle: who is instantiated when?
>  -  possibility of adding support for different service locators.
>  -  Testing: being able to make use of Mocks
>  -  If you just want to use very few Mailets in a small tool you could
> wire up deps yourself. 
> 
> Another point is that a Mailet should concentrate on it's own business.
> Looking up and checking dependencies is IMO out of scope.
> If you do that in every single component it is not very DRY.
> 
> Conclusion:
> 
> I would not like to see service locator pattern as the default for
> looking up services in James. 
> 
> If it is really wanted/needed it could be a compromise to publish James
> services supplementary by JNDI and extend Mailet implementations with
> the ability of using JNDI for looking up dependencies.
> (I'm convinced this could be done in a clean, separate way without
> blowing up existing code)
> Following the trends we should keep OSGi in mind which offers another
> service locator mechanism.
> 
> Joachim



Re: injection and/or JNDI WAS Re: On Global vs Local jndi naming

Posted by Joachim Draeger <jd...@gmx.de>.
Am Samstag, den 11.11.2006, 09:14 +0000 schrieb Danny Angus:
> On 11/11/06, Serge Knystautas <sk...@gmail.com> wrote:
> 
> > Yeah, I'm biased, but I like think this is part of the advantages of
> > just dependency injection.
> 
> I'm still waiting for someone to give a sensible DI example that would
> show how we deal with the fact that there can be an unlimited number
> of unknown dependancies.

IMO exactly "unlimited number of *unknown* dependencies" is a strong
argument for DI. 
In a big application it is important to know the dependencies exactly.

> Service location allows the consumer of the services to look them up
> as needed, DI requires that the container be made aware of the
> dependance and invoke some mechanism to inject an instance which
> satisfies it.

Making aware a container of dependencies means mostly xml. This is just
like a formal documentation of the dependencies. You should probably do
that even when you using a service locator.
I don't consider it as problematic that the format differs in different
frameworks. They are quite similar and the process is not error prone. 

Invoking some mechanism means just calling setters. Likely inside some
kind of factory. I don't see any magic there. :-) The whole procedure is
probably just as easy as dealing with JNDI.
IMO even when using JNDI the Bean should be configured through setters
by calling a corresponding method or using a factory. 
(Funny enough: This could even be done by using a generic factory and
xml ;-)
This way the consumer had full control and could decide whether to use
DI or JNDI. 


Also lookup up services as needed is more flexible I think it is more
save to check dependencies at initialization. With DI you can do that
even without creating any instances.

> In what way is injection preferable to lookup?

e.g.
 -  who is affected when I change service A?
 -  using a wrapper when Mailet X needs a special behavior of service B
 -  different implementions/instances of Service C for Mailet Y and Z.
 -  defined, full control of lifecycle: who is instantiated when?
 -  possibility of adding support for different service locators.
 -  Testing: being able to make use of Mocks
 -  If you just want to use very few Mailets in a small tool you could
wire up deps yourself. 

Another point is that a Mailet should concentrate on it's own business.
Looking up and checking dependencies is IMO out of scope.
If you do that in every single component it is not very DRY.

Conclusion:

I would not like to see service locator pattern as the default for
looking up services in James. 

If it is really wanted/needed it could be a compromise to publish James
services supplementary by JNDI and extend Mailet implementations with
the ability of using JNDI for looking up dependencies.
(I'm convinced this could be done in a clean, separate way without
blowing up existing code)
Following the trends we should keep OSGi in mind which offers another
service locator mechanism.

Joachim









Re: injection and/or JNDI WAS Re: On Global vs Local jndi naming

Posted by "Andrew C. Oliver" <ac...@apache.org>.
> I'm still waiting for someone to give a sensible DI example that would
> show how we deal with the fact that there can be an unlimited number
> of unknown dependancies. 

mailet.xml
<mailets>
<mailet>
   <name>MyMailet</name>
   <class>org.foo.MyMailetImpl</class>
   <interface>org.foo.MyMailet</interface>
   <constructors>
     <constructor/>
     <constructor>
       <arguments>
         <argument>java.lang.String</argument>
       </arguments>
     </constructor>
   </constructors>
   <attributes>
      <attribute>
         <name>foo</name>
         <type>java.lang.String</type>
         <getter>getFoo</getter>
         <setter>setFoo</setter>
      </attribtue>
      <attribute>  
         <name>MyOtherMailet</name>
         <type>org.foo.MyOtherMailet</type>
         <setter>getMyOtherMailet</setter>
         <depends>true</depends>
      </attribute>
      <attribute>  
         <name>YetAnotherMailet</name>
         <type>org.foo.YetAnotherMailet</type>
         <setter>setYetAnotherMailet</setter>
         <jndi>true</jndi>
         <depends>true</depends>
      </attribute>
   </attributes>
</mailet>
</mailets>

OR 

@org.apache.mailet.Mailet(name="MyMailet"
                          class="org.foo.MyMailet)
public class MyMailetImpl implements MyMailet {
  ... public members snipped ...
  @org.apache.mailet.Constructor
  public MyMailetImpl() {}   

  @org.apache.mailet.Constructor
  public MyMailetImpl(String bar) {
     this.bar = bar;
  }

  @org.apache.mailet.Attribute
  public void setFoo(String foo) {
      this.foo = foo;
  }

  public String getFoo() {
      return this.foo;
  }

  @org.apache.mailet.Attribute(depends=true)
  public void setMyOtherMailet(MyOtherMailet mailet) {
     this.mom = mailet;
  }

  @org.apache.mailet.Attribute(depends=true jndi=true)
  public void setYetAnotherMailet(YetAnotherMailet yam) {
      this.yam = yam;
  }

  public void start() {
  }

  public void stop() {
  }
}


myserver-specific-config.xml (unspecified but example)

<mailet-instance>
  <mailet>
     <name>MyMailet</name>
     <instance-name>MyMailet1</instance-name>
     <constructor>
        <arguments>
          <argument type="java.lang.String">Hi man</argument>
        </arguments>
     </constructor>
     <attributes>
        <attribute name="foo">Hello</attribute>
        <attribute name="MyOtherMailet">MyOtherMailet1</attribute>
        <attribute name="YetAnotherMailet">java://yam</attribute>
     </attributes>
  </mailet>
</mailet-instance>

CONTRACTS:
Constructors are called in any order.  
Each mailet has a method called start.
Each mailet has a method called stop.
Attributes are "set" after construction but before "start".
Interfaces are proxies (ala java.lang.reflect.Proxy) and thus can be 
passed before the service is started
Start is then called once dependencies are satisfied (below).
Mailets with no <depends>true</depends> are started first.
Mailets whose dependencies are satisfied are started next (loop).
Mutual and circular dependencies are not allowed (error).
JNDI dependencies are satisfied when the jndi lookup exists and the 
service has been started.
stops are called in reverse order that starts were called.

Notes:
attribute annotations can be either on the implementation or the 
interface.  
constructor annotations must be on the implementation (duh)
annotations and/or XML are equivalent
annotations should not be used for configuration (vendor specific 
example in xml above)

This is more or less the same idea used for JBoss XMBeans, Geronimo 
GBeans, and EJB3.


Re: injection and/or JNDI WAS Re: On Global vs Local jndi naming

Posted by "Andrew C. Oliver" <an...@superlinksoftware.com>.
Danny Angus wrote:
> On 11/11/06, Serge Knystautas <sk...@gmail.com> wrote:
>
>> Yeah, I'm biased, but I like think this is part of the advantages of
>> just dependency injection.
>
> I'm still waiting for someone to give a sensible DI example that would
> show how we deal with the fact that there can be an unlimited number
> of unknown dependancies.
>
I posted one but for some reason it didn't make it to the list.  I will 
post it again
when I get motivation on Monday.

> Service location allows the consumer of the services to look them up
> as needed, DI requires that the container be made aware of the
> dependance and invoke some mechanism to inject an instance which
> satisfies it.
>
> In what way is injection preferable to lookup?
Lookup doesn't necessarily help with dependence at all.  Meaning you 
just get NPEs all
over the place because the other service isnt' start.  Dependence, 
injection and lookup are
all orthogonal. 
>
> d.



Re: injection and/or JNDI WAS Re: On Global vs Local jndi naming

Posted by Danny Angus <da...@gmail.com>.
On 11/11/06, Serge Knystautas <sk...@gmail.com> wrote:

> Yeah, I'm biased, but I like think this is part of the advantages of
> just dependency injection.

I'm still waiting for someone to give a sensible DI example that would
show how we deal with the fact that there can be an unlimited number
of unknown dependancies.

Service location allows the consumer of the services to look them up
as needed, DI requires that the container be made aware of the
dependance and invoke some mechanism to inject an instance which
satisfies it.

In what way is injection preferable to lookup?

d.

Re: injection and/or JNDI WAS Re: On Global vs Local jndi naming

Posted by Serge Knystautas <sk...@gmail.com>.
On 11/11/06, Danny Angus <da...@gmail.com> wrote:
> On 11/11/06, Serge Knystautas <sk...@gmail.com> wrote:
>
> > Yeah, I'm biased, but I like think this is part of the advantages of
> > just dependency injection.
>
> I'm still waiting for someone to give a sensible DI example that would
> show how we deal with the fact that there can be an unlimited number
> of unknown dependancies.
>
> Service location allows the consumer of the services to look them up
> as needed, DI requires that the container be made aware of the
> dependance and invoke some mechanism to inject an instance which
> satisfies it.
>
> In what way is injection preferable to lookup?

I think we're considering different scenarios since in my ears, your
points support my view.  When I hear unlimited number of unknown
dependencies, that rules out service lookup since it's impossible to
come up with an unlimited number of unknown names for the lookups.
It's all explicit and clear.  It makes a huge ugly XML, but it's much
more rigorous and scales better IMHO.

I haven't used attributes to define DI, but my first reaction is to
not like it since to me it seems that I would have to recompile my
Java classes to change the dependency relationship in some cases.
Actually, studying your example, it seems like it's just removing some
verbosity that I haven't had to deal with with Spring since it excels
at sensible defaults.

-- 
Serge Knystautas
Lokitech >> software . strategy . design >> http://www.lokitech.com
p. 301.656.5501
e. sergek@lokitech.com