I started to prototype the idea of using blueprint config to
initialize beans and attempted to convert our blueprint samples.  Not
entirely done yet but I am not sure I like what i have -

public class BaseBlueprintConfig {

    @Inject(ref="blueprintBundleContext")
    BundleContext blueprintBundleContext;

    @Inject(ref="blueprintContainer")
    BlueprintContainer blueprintContainer;

    @Inject(ref="blueprintBundle")
    Bundle blueprintBundle;

    @Inject(ref="converter")
    Converter converter;

}

@Blueprint(defaultActivation="eager", defaultTimeout=300,
defaultAvailability="optional")
public class BlueprintConfig extends BaseBlueprintConfig {

    Bar bar;

    @Bean(id="bar")
    public Bar bar() {
        if (bar == null) {
            bar = new Bar();
            bar.setValue("Hello FooBar");
            bar.setContext(blueprintBundleContext);
            List l = new ArrayList();
            l.add("a list element");
            l.add(5);
            bar.setList(l);
        }

        return bar;
    }


    @Bean
    public Foo foo() {
        Foo foo = new Foo();
        foo.setA(5);
        //foo.setB(${key.b});
        foo.setBar(bar());
        // not sure how to do this one...
        foo.setCurrency(new Currency(null, 0));
        foo.setDate(new Date("2009.04.17"));

        return foo;
    }

    @Bean
    public Account accountOne() {
        Account account = new Account(1);
        return account;
    }

    @Bean
    public Account accountTwo() {
        Account account = StaticAccountFactory.createAccount(2);
        return account;
    }

    @Bean
    public NewAccount accountThree() {
        NewAccount account = getAccountFactory().createAccount(3);
        return account;
    }

    @Bean
    public AccountFactory getAccountFactory() {
        AccountFactory af = new AccountFactory("account factory");
        return af;
    }
 }

I have to admit that there are a few things I didn't like about the
blueprint configuration file:

1. I didn't like the fact that it detach many of the initialization
from the original java files.  Some was very easy to annotate in the
original bean class but now I don't even know what to do, for example
the inject of the blueprintBundleContext I still have to fell back to
the original way of doing things and I don't even know how to do
foo.setCurrency which was obvious to me before.
2. I am concerned about converting these blueprint configuration to
the corresponding blueprint XML.  I think this is necessary to have
the ability of blueprint XML override the annotation.
3. I remember one of Guillaume's concern was code reusability.  Given
blueprint XML has higher priority than annotation, people can only
specify values that are stable in annotation and the rest in blueprint
definition XML, or modify what is being annotated or create blueprint
XML definition to override annotation without changing the java files.
4. For complicated scenario, may just be better to support only the
blueprint XML definition without annotation, for example initialize a
list.

Lin

On Tue, May 18, 2010 at 3:32 AM, Guillaume Nodet <[email protected]> wrote:
> That would be better imho.
> I still think that adding annotations containing values (or reference to
> names of other beans) on a class is a bad idea.  The reason is that it makes
> this class not reusable at all, which imho is one of the main feature of
> blueprint.
> Doing that would led our users down this path and when  further down,
> they'll see that they can't really reuse their beans without modifying
> them...
>
> Annotations on the classes are fine when they just say something about the
> bean: if they need to be injected with a value, if a method is the
> initialization / destroy method, etc ...
>
> Another point is that we should try to minimize the amount of information in
> order to make things easier to refactory, not harder.   Currently, all the
> ids of beans for example are centrlized in the xml.  Spreading them around
> will just make things harder to refactor.    The @Bean annotation should be
> mostly optional, as it does not bring anything.  The use of @PreDestroy and
> @PostConstruct on the method will also make it easier to change the method
> name, without having the change the init-method attribute on the bean
> annotation.
>
> I don't think the goal should be to stay too close to the xml
> configuration.  While dealing with Java, we could also thing about some kind
> of DSL to build the configuration.
>
> In addition, we need to remain blueprint compliant and make sure we have
> something in the blueprint xml to indicate we want some extension parser.
>
> On Fri, May 14, 2010 at 19:48, Lin Sun <[email protected]> wrote:
>
>>
>> I wonder if we could use what we have now for simple, common cases,
>> while use a hybrid approach like below:
>>
>> 1) we allow users to annotate the class to define its behavior like
>> @Bean, @Service, @ReferenceListener like what we have right now.
>> 2) Optionally, we allow users to create a common configuration java
>> file to describe how they want to create instances with the values.
>>
>> For example:
>>
>> @Bean
>> public class BeanClass {
>>  ...
>> }
>>
>
> Such annotations should not be mandatory I think.  A bean is just an
> instance of a class.  There's no load time weaving or anything going on at
> this point, so annotating it with a default annotation should be optional
> (if needed at all)
>
>
>>
>> @Bean(factoryRef="accountFactory",
>>     factoryMethod="createAccount")
>> public class NewAccount {
>>  ...
>> }
>>
>
> I really don't like this one either.  If needed, this annotation should be
> on the createAccount method of the factory.
>
>
>>
>> // this class also gets to specify the blueprint global configuration
>> like defaultActivation, defaultTimeout, etc
>> @Blueprint(defaultActivation="eager", defaultTimeout=300,
>> defaultAvailability="optional")
>> public class BlueprintConfig {
>>
>>     @Bean(id="myBean1")
>>     public BeanClass beanClass1(){
>>          @Inject @Bean(id="accountOne", ar...@arg(value="1")
>>          NewAccount account;
>>          ....
>>     }
>>
>>     @Bean(id="myBean2")
>>     public BeanClass beanClass1(){
>>          @Inject @Bean(id="accountOne", ar...@arg(value="2")
>>          NewAccount account;
>>          ....
>>     }
>> }
>>
>> WDYT?
>>
>>
> The id of the bean could be inferred from the method name.
> What about the following configuration:
>
> @Blueprint
> public class MyConfig {
>
>  @Bean public BeanClass myBean1() {
>      return new BeanClass(accountFactory.createAccount(1));
>   }
>
>  @Bean public BeanClass myBean2() {
>      return new BeanClass(accountFactory().createAccount(2));
>   }
>
>  @Bean public AccountFactory accountFactory() {
>      return new AccountFactory();
>   }
> }
>
> I suppose in order to respect scopes, we'd have to modify this class to
> intercept calls, so that the accountFactory() method would cache the value
> of the create account factory.
>
> I also think, that in order to support "custom namespace", we'd have to
> define annotations to put on other annotations, so that we can ask the
> namespace handler to help building the metadata.   We also need to be able
> to inject values from outside to support config admin and property
> placeholders.
>
> --
> Cheers,
> Guillaume Nodet
> ------------------------
> Blog: http://gnodet.blogspot.com/
> ------------------------
> Open Source SOA
> http://fusesource.com
>

Reply via email to