1 2 Previous Next 25 Replies Latest reply on Dec 28, 2009 9:31 PM by johaneltes Go to original post
      • 15. Re: Bean property configuration
        gavin.king

        Alternative still have some hard code. And do i have all preconcerted Alternative?

        Well, not really, not if you use producer methods/fields, like I show above.



        BWT Alternative is not clear than xml

        I actually think it's more clear to have everything expressed in Java code, instead of split out into XML. I think you'll get used to @Alternative. It looks a little strange at first, because it's not what you're used to. But once you figure out that it's possible to do all the things you do today with XML, it will get natural.

        • 16. Re: Bean property configuration
          alin.heyoulin.qq.com

          Well, not really, not if you use producer methods/fields, like I show above.

          I mean producer methods/fields could be any value. For example to config datasource url or username... .  It could't geive all the  producer methods/fields .



          Thanks your reply!

          • 17. Re: Bean property configuration
            alin.heyoulin.qq.com

            And an other question. Why load all managed bean to container? In seam3 can i just load my special bean by config file?

            • 18. Re: Bean property configuration


              Thought I share were I ended up with my JmsTemplate experiment. The case is to find a CDI-ish approach for configuration of multiple beans of the same class, so that these bean configurations can be injected into various injection points across the application. 
              
              The scenario at hand is about JmsTemplates. The application needs a set of JmsTemplate - one per destination - to be pre-configured. I would like to do the configuration using as little procedural Java code as possible.
              
              First, the injection point (sample):
              
                   private @Inject @Named("error") JmsTemplate template;
              
              The semantics of the injection point is: Inject the pre-configured JmsTemplate instance named "error". The application will then use the template to send error messages.
              
              The pre-configured JMS templates are defined in Java, not XML. A annotation has been created to support configuration of the properties of the templates. A configuration is represented by a producer method, The complete set of JMS Template configurations are represented by a CDI bean hosting all the producer methods. The following template configuration class defines two named JmsTemplate configurations: "log" and "error":
              
              public class JmsTemplateProducers {
                   
                   @Produces @Resource(name="java:app/jms/NoXA_CF") ConnectionFactory cf;
              
                   @Produces @Named("error")
                   public JmsTemplate getErrorQueueTemplate(
                             @JmsTemplateConfig(defaultDestinationName = "errorQueue", timeout = 3600) JmsTemplate template) {
                        template.setConnectionFactory(cf);
                        return template;
                   }
              
                   @Produces @Named("log")
                   public JmsTemplate getLogQueueTemplate(
                             @JmsTemplateConfig(defaultDestinationName = "logQueue", timeout = 100) JmsTemplate template) {
                        template.setConnectionFactory(cf);
                        return template;
                   }
              }
              
              The difference to just assigning all values the usual way isn't paramount:
              
                   @Produces @Named("log")
                   public JmsTemplate getLogQueueTemplate() {
                        JmsTemplate template = new JmsTemplate();
                        template.setConnectionFactory(cf);
                        template.setDefaultDestinationName("logQueue");
                        template.setTimeout(100);
                        return template;
                   }
              
              The value of the annotation approach is that it does not require the producers to be created, when I'm not concerned about reusing a configuration:
              
              private @Inject @JmsTemplateConfig(defaultDestination = "logQueue", timeout = 100) JmsTemplate template;
              
              For the annotation merging to work, there need to be an annotation type and a supporting injection point producer. These two classes are generic utilities:
              
              @Qualifier
              @Target( { METHOD, FIELD, PARAMETER, TYPE })
              @Retention(RUNTIME)
              public @interface JmsTemplateConfig {
                   @Nonbinding
                   String defaultDestinationName() default "";
              
                   @Nonbinding
                   int timeout() default 0;
              }
              
              public class JmsTemplateConfigurationProducer {
              
                      @Produces @JmsTemplateConfig 
                      public JmsTemplate produceJmsTemplate(InjectionPoint injectionPoint)
                      {
                              if (injectionPoint.getAnnotated().isAnnotationPresent(JmsTemplateConfig.class)) {
                                   JmsTemplateConfig t = injectionPoint.getAnnotated().getAnnotation(JmsTemplateConfig.class);
                                   JmsTemplate tmp = new JmsTemplate();
                                   tmp.setDefaultDestinationName(t.defaultDestinationName());
                                  tmp.setReceiveTimeout(t.timeout());
                                  return tmp;
                              }
                              else {
                                 return new JmsTemplate();
                              }
                      }
              }



              Thanks to all who guided me through this journey. It definitely way to increased my understanding of CDI.

              • 19. Re: Bean property configuration
                meetoblivion

                just a note, Johan


                in this code:




                @Produces @JmsTemplateConfig 
                        public JmsTemplate produceJmsTemplate(InjectionPoint injectionPoint)
                        {
                                if (injectionPoint.getAnnotated().isAnnotationPresent(JmsTemplateConfig.class)) {
                                     JmsTemplateConfig t = injectionPoint.getAnnotated().getAnnotation(JmsTemplateConfig.class);
                                     JmsTemplate tmp = new JmsTemplate();
                                     tmp.setDefaultDestinationName(t.defaultDestinationName());
                                    tmp.setReceiveTimeout(t.timeout());
                                    return tmp;
                                }
                                else {
                                   return new JmsTemplate();
                                }
                        }
                



                @Produces @JmsTemplateConfig makes the isAnnotationPresent part of your code unnecessary, as this will only ever be called to @Inject @JmsTemplateConfig JmsTemplate,

                • 20. Re: Bean property configuration
                  gavin.king

                  Thought I share were I ended up with my JmsTemplate experiment.

                  A couple of notes:



                  1. I agree that @ErrorQueue, @LogQueue is much better than @Named("error"), @Named("log"). I don't think you are ever going to have so many queues in your app that defining an annotation for each one is a significant burden.

                  2. Why not suck the connection factory JNDI name into @JmsTemplateConfig, and have produceJmsTemplate() look it up from JNDI instead of using injection? That would significantly simplify the code.

                  3. When we introduce abstract producer methods, the code for getErrorQueueTemplate() and getLogQueueTemplate() will get waaay simpler!



                  With all these changes, including abstract producer methods, the code would look like:


                  @Produces @ErrorQueue abstract JmsTemplate getErrorQueueTemplate(@JmsTemplateConfig(defaultDestinationName="errorQueue", timeout=3600, name="java:app/jms/NoXA_CF") JmsTemplate template);



                  Which I think is a significant simplification.

                  • 21. Re: Bean property configuration
                    gavin.king

                    Gavin King wrote on Dec 28, 2009 19:21:


                    With all these changes, including abstract producer methods, the code would look like:

                    @Produces @ErrorQueue abstract JmsTemplate getErrorQueueTemplate(@JmsTemplateConfig(defaultDestinationName="errorQueue", timeout=3600, name="java:app/jms/NoXA_CF") JmsTemplate template);



                    Which I think is a significant simplification.



                    Hrm. Who would prefer to be able to write:


                    @Produces @ErrorQueue  
                    @GenericResource @JmsTemplateConfig(defaultDestinationName="errorQueue", timeout=3600, name="java:app/jms/NoXA_CF") 
                    JmsTemplate template;



                    Perhaps abstract @Produces methods are the wrong way to go, and @Produces @GenericResource fields are more readable construct....

                    • 22. Re: Bean property configuration
                      gavin.king

                      Perhaps abstract @Produces methods are the wrong way to go, and @Produces @GenericResource fields are more readable construct....

                      I guess it's not the right way to go, since it opens up a whole can of worms of resolving generic resources. Better to just not go there, I guess. The abstract producer method solves the problem (along with several other problems).

                      • 23. Re: Bean property configuration
                        gavin.king

                        Gavin King wrote on Dec 28, 2009 19:35:


                        Perhaps abstract @Produces methods are the wrong way to go, and @Produces @GenericResource fields are more readable construct....

                        I guess it's not the right way to go, since it opens up a whole can of worms of resolving generic resources. Better to just not go there, I guess. The abstract producer method solves the problem (along with several other problems).


                        Actually, here's an interesting possibility: give portable extensions the possibility to inject into (i.e. define the value of) @Producer fields at the right time, by registering a callback on the particular Producer object. This generalizes a capability that already exists implicitly in CDI and is used by the container for stuff like @Resource, @PersistenceContext, @EJB and friends. We would just be opening up that capability to portable extensions.


                        Then the code would look like:


                        @Produces @ErrorQueue  
                        @JmsTemplateConfig(defaultDestinationName="errorQueue", timeout=3600, name="java:app/jms/NoXA_CF") 
                        JmsTemplate template;



                        And the portable extension would register some callback object when it encounters a @Produces field annotated @JmsTemplateConfig. Yeah, I think that would be a really nice capability! I'll add it to the wishlist.

                        • 24. Re: Bean property configuration
                          gavin.king

                          Even better, this feature would allow us to eliminate the whole special bean category Resources from the spec, and suck the whole of 3.5 into 3.4, in a new subsection for Producer field initializers. Now that's really nice! All we would need to do is introduce a new interface in the SPI package:


                          public interface Initializer<X> {
                              public X getInitialValue(AnnotatedField<?> field);
                          }



                          Along with a ProcessProducerField event type extending ProcessProducer with a setInitializer() method.

                          • 25. Re: Bean property configuration
                            @Produces @ErrorQueue  
                            @JmsTemplateConfig(defaultDestinationName="errorQueue", timeout=3600, name="java:app/jms/NoXA_CF") 
                            JmsTemplate template;



                            ...is really nice. It is an important achievement to get rid of the producer method. I the abstract method is axactly that: a bit (too) abstract.


                            I'm note sure I like the idea of introducing an annotation type for each queue. I see the point of type safe injection, but it is important to reduce level of abstractions and the bloat of intruducing new queues. The reason is that I have a different experience regarding the number of queues that may be present. Having an annotation type per domain/app with a supporting enum of queue names may be the ideal intersection of type safety and footprint.


                            Regarding the @Resource: baking the lookup into the injection point producer method makes sense in this simple case. In a real-world app it will sometimes be a reasource but most likely an alternative, one of which being an out-of-container configuration based on e.g. MQQueueConnectionFactory with several properties.


                            1 2 Previous Next