6 Replies Latest reply on Aug 13, 2007 8:44 AM by alesj

    Adding applyMetaData method to KernelControllerContext

    alesj

      I've added

       /**
       * Do apply meta data.
       *
       * @throws Throwable for any error
       */
       void applyMetaData() throws Throwable;
      

      to hide the details of applying annotations.

      I've reused the existing MetaDataVisitor impls that reside in AbstractKernelControllerContext + added a flag if context was already processed for annotations.

       public void applyMetaData() throws Throwable
       {
       if (areAnnotationsProcessed == false)
       {
       // handle custom annotations
       MetaDataVisitor annotationsVisitor = new AnnotationMetaDataVisitor(metaData);
       BeanAnnotationAdapterFactory.getBeanAnnotationAdapter().applyAnnotations(annotationsVisitor);
       areAnnotationsProcessed = true;
       }
       }
      


      Is this method valid?

        • 1. Re: Adding applyMetaData method to KernelControllerContext

          You need to take a step back and explain it from first princples.

          e.g. You've reused the MetaDataVisitors to do what?
          They look at the MetaData object not the real object graph how does this relate
          to annotations are you talking about the annotations in the xml?

          Why would the annotations be already processed?

          Short of finding the time (I don't at the moment) to do a code read on all these changes
          (not just the latest stuff), I can't really comment.

          I can say from that code that was broken,
          I don't like the idea of hardwiring those annotation handlers

          What was it something like?

          Adapter[] adapters
          {
          ImplementationDetail1Adapter.INSTANCE
          ImplementationDetail2Adapter.INSTANCE
          };
          


          How does one add ImplementationDetail3Adapter or use
          AlternateImplementationDetail1Adapter.INSTANCE.

          • 2. Re: Adding applyMetaData method to KernelControllerContext
            alesj

             

            "adrian@jboss.org" wrote:

            e.g. You've reused the MetaDataVisitors to do what?
            They look at the MetaData object not the real object graph how does this relate to annotations are you talking about the annotations in the xml?

            After you add new MetaData, it needs to be 'visited', in order to plugin all those dependencies, callbacks, installs, ...
            So the easiest way for me to do that was to use the existing MetaDataVisitor concept, and just twist it a bit to suite my need - not starting from BeanMetaData, but on newly added MetaDataVisitorNode + pushing BMD at the bottom of the stack before executing it.

            "adrian@jboss.org" wrote:

            Why would the annotations be already processed?

            When we do a re-install on the controller context, do we need a new look at the annotations?

            "adrian@jboss.org" wrote:

            I can say from that code that was broken,
            I don't like the idea of hardwiring those annotation handlers

            This can easily be fixed, just temp impl detail.
            Basically you have two kinds on annotations handlers - plugins and adapters.
            Plugins are those who know how to handle class, constructor, method (property), field annotations.
            Adapters (Annotation2ValueMetaDataAdapter) are those who know how to produce ValueMetaData from annotation.
            Since property plugins == adapters, there is just one need for actual impl.

            "adrian@jboss.org" wrote:

            How does one add ImplementationDetail3Adapter or use
            AlternateImplementationDetail1Adapter.INSTANCE.

            There is a BeanAnnotationAdapter (uf, yup, bad choice of name) factory.
            Some simple extension impl can be easily added.
            public class BeanAnnotationAdapterFactory
            {
             private static final BeanAnnotationAdapter adapter = new BasicBeanAnnotationAdapter();
            
             public static BeanAnnotationAdapter getBeanAnnotationAdapter()
             {
             return adapter;
             }
            }
            
            


            You can extend BasicBeanAnnotationAdapter and use its addPlugin method to add your new annotation plugins.

             protected void addAnnotationPlugin(AnnotationPlugin plugin)
             {
             Class<? extends Annotation> annotation = plugin.getAnnotation();
             if (annotation.getAnnotation(Target.class) == null)
             log.warn("Annotation " + annotation + " missing @Target annotation!");
             if (annotation.getAnnotation(Retention.class) == null)
             log.warn("Annotation " + annotation + " missing @Retention annotation!");
            
             Set supported = plugin.getSupportedTypes();
             if (supported.contains(ElementType.TYPE))
             {
             classAnnotationPlugins.add(plugin);
             }
             if (supported.contains(ElementType.CONSTRUCTOR))
             {
             constructorAnnotationPlugins.add(plugin);
             }
             if (supported.contains(ElementType.METHOD))
             {
             if (plugin instanceof PropertyAware)
             propertyAnnotationPlugins.add(plugin);
             else
             methodAnnotationPlugins.add(plugin);
             }
             if (supported.contains(ElementType.FIELD))
             {
             fieldAnnotationPlugins.add(plugin);
             }
             }
            


            • 3. Re: Adding applyMetaData method to KernelControllerContext

               

              "alesj" wrote:
              "adrian@jboss.org" wrote:

              e.g. You've reused the MetaDataVisitors to do what?
              They look at the MetaData object not the real object graph how does this relate to annotations are you talking about the annotations in the xml?

              After you add new MetaData, it needs to be 'visited', in order to plugin all those dependencies, callbacks, installs, ...
              So the easiest way for me to do that was to use the existing MetaDataVisitor concept, and just twist it a bit to suite my need - not starting from BeanMetaData, but on newly added MetaDataVisitorNode + pushing BMD at the bottom of the stack before executing it.


              Ok. But I'm not sure it needs to be this complicated?


              "adrian@jboss.org" wrote:

              Why would the annotations be already processed?

              When we do a re-install on the controller context, do we need a new look at the annotations?


              Of course, the class could change.


              "adrian@jboss.org" wrote:

              How does one add ImplementationDetail3Adapter or use
              AlternateImplementationDetail1Adapter.INSTANCE.

              There is a BeanAnnotationAdapter (uf, yup, bad choice of name) factory.
              Some simple extension impl can be easily added.
              public class BeanAnnotationAdapterFactory
              {
               private static final BeanAnnotationAdapter adapter = new BasicBeanAnnotationAdapter();
              
               public static BeanAnnotationAdapter getBeanAnnotationAdapter()
               {
               return adapter;
               }
              }
              
              


              You can extend BasicBeanAnnotationAdapter and use its addPlugin method to add your new annotation plugins.

               protected void addAnnotationPlugin(AnnotationPlugin plugin)
               {
               Class<? extends Annotation> annotation = plugin.getAnnotation();
               if (annotation.getAnnotation(Target.class) == null)
               log.warn("Annotation " + annotation + " missing @Target annotation!");
               if (annotation.getAnnotation(Retention.class) == null)
               log.warn("Annotation " + annotation + " missing @Retention annotation!");
              
               Set supported = plugin.getSupportedTypes();
               if (supported.contains(ElementType.TYPE))
               {
               classAnnotationPlugins.add(plugin);
               }
               if (supported.contains(ElementType.CONSTRUCTOR))
               {
               constructorAnnotationPlugins.add(plugin);
               }
               if (supported.contains(ElementType.METHOD))
               {
               if (plugin instanceof PropertyAware)
               propertyAnnotationPlugins.add(plugin);
               else
               methodAnnotationPlugins.add(plugin);
               }
               if (supported.contains(ElementType.FIELD))
               {
               fieldAnnotationPlugins.add(plugin);
               }
               }
              


              Ok. So the code that didn't compile was just out-of-the-box factory settings
              for bootstrapping?

              • 4. Re: Adding applyMetaData method to KernelControllerContext
                alesj

                 

                "adrian@jboss.org" wrote:
                "alesj" wrote:

                After you add new MetaData, it needs to be 'visited', in order to plugin all those dependencies, callbacks, installs, ...
                So the easiest way for me to do that was to use the existing MetaDataVisitor concept, and just twist it a bit to suite my need - not starting from BeanMetaData, but on newly added MetaDataVisitorNode + pushing BMD at the bottom of the stack before executing it.

                Ok. But I'm not sure it needs to be this complicated?

                Complicated?
                This is what looked natural to me, to use existing visitor concept.
                Since we are already in Describe state, executing both of them - initial and describe. No need for changing existing MetaData impl.
                What would you do?

                "adrian@jboss.org" wrote:


                When we do a re-install on the controller context, do we need a new look at the annotations?


                Of course, the class could change.

                Yup.
                Can you give a scenario how this would work and that the underlying controller context wouldn't be removed during that process?
                Probably if we remove the underlying Classloader, context gets unistalled - into PreInstall state - and then re-installed with new Classloader. Will that do? :-)

                "adrian@jboss.org" wrote:

                Ok. So the code that didn't compile was just out-of-the-box factory settings
                for bootstrapping?

                The JavaBeanAnnotationPlugin?
                I think the compiling problem was simply because I had some classes locally which my IDEA/SVN didn't 'noticed', so they weren't commited.
                Or which problem do you have in mind?

                • 5. Re: Adding applyMetaData method to KernelControllerContext

                   

                  "alesj" wrote:
                  "adrian@jboss.org" wrote:
                  "alesj" wrote:

                  After you add new MetaData, it needs to be 'visited', in order to plugin all those dependencies, callbacks, installs, ...
                  So the easiest way for me to do that was to use the existing MetaDataVisitor concept, and just twist it a bit to suite my need - not starting from BeanMetaData, but on newly added MetaDataVisitorNode + pushing BMD at the bottom of the stack before executing it.

                  Ok. But I'm not sure it needs to be this complicated?

                  Complicated?
                  This is what looked natural to me, to use existing visitor concept.
                  Since we are already in Describe state, executing both of them - initial and describe. No need for changing existing MetaData impl.
                  What would you do?


                  I don't know, but I'd try to find someway to avoid the isAlreadyDone()
                  that is bound to lead to confusion (and most likely errors).

                  The fundamental problem is that there are three points when we know that metadata
                  could be introduced and that is really complete.

                  1) Initial install - we know the xml (really BeanMetaData)
                  2) PreInstall - for a simple bean - we know the class (and we know it exists)
                  3) Instantiate - for a bean from a factory - it is only here we know the class
                  from object.getClass()

                  I'd find someway to make the retrieval lazy such that
                  steps 1 and 2 only look at the metadata they absolutely need to
                  and step 3 does the all rest (most of it).

                  e.g. You can't specify a classloader using an annotation
                  @ClassLoader(name="Whatever")
                  public class MyClass {}
                  

                  because it couldn't load the class until the classloader exists
                  so it could never read the annotation.

                  That is an example of the MetaData that needs to be visited in step (1)
                  and the dependency constructed.

                  Others like property injection can be left to step 3 when we know
                  we have access to the full picture, i.e. we don't use the annotation
                  from the class if the xml/metadata has one.

                  This is also related to something I discussed with Carlo about ejb annotations.
                  The annotations in the xml are "instance scope" annotations,
                  while the annotations on the class are "Class scope" annotations.

                  Any "instance scope" annotation makes the "class scope" invisible.

                  • 6. Re: Adding applyMetaData method to KernelControllerContext
                    alesj

                     

                    "adrian@jboss.org" wrote:

                    This is also related to something I discussed with Carlo about ejb annotations.
                    The annotations in the xml are "instance scope" annotations,
                    while the annotations on the class are "Class scope" annotations.

                    Any "instance scope" annotation makes the "class scope" invisible.


                    I though of this - following your discussion with Carlo :-) - but there are some issues that IMO still need exact knowledge of overlapping instances.
                    Specially when dealing with full sets/lists of metadata - e.g. bean propertys, annotations, installs/uninstalls, callbacks, supplies, demands, ...
                    But I guess implementing equals/hashCode on all these metada would do the trick.

                    And the bean metadata ControllerContext would deal with it would actually be a scoped chain of bean metadata.