Announcement Announcement Module
Collapse
No announcement yet.
Bean definition turned up side down Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Bean definition turned up side down

    Hi Spring folks,

    I am currently thinking about the Spring RPC framework and considering diffrent design decisions to provide some value to the project. Along some general design questions I noticed what the guys are suffering from - the missing of contributions.

    You know, I am thinking about the revese way. I am thinking about active and dynamically pulling.

    Talking Spring, you actually define a bean and set the bean's properties (means dependencies) then afterPropertiesSet is called and we are all happy having a bean. This is greate if you wire the domain layer together and this what I miss most when declaring my plugins in Eclipse.

    In the Eclipse world all you do is pulling, in the Spring world all you do is pushing. Pulling contributions is dynamic and pushing beans is rather static.

    It seams that in terms of extensions (especially when talking about UI objects) pulling works great. On the other hand pushing works superior when it comes to hardwireing the domain layer. That's why Spring feels so good when we wire up a web-application. You control it, it all get's pushed.

    But comming right from the Eclipse world and finding Spring RPC emerging beyond its initial state it had 5 months ago, I am starting to think of a framework combining both, pushing and pulling. And thinking even more about it, I start to think, that this would be fabulous.

    Here is what would be needed:

    First beside the general bean-tag, the contribution-tag has to be introduced. Contributing an extension may look like this:

    Code:
    <contribution extension-point="my.application.views" class="MyView">
         <property name="myProperty"><value>HardwiredStuff</value></property>
    
    </contribution>
    So how is it used:

    A contribution has to apply to a certain type to be compatible. These requirements are formulated by the stakeholder of the extension-point. So if you contribute an application view object, the class describing the certain contribution must be of type ApplicationView.

    What additional features does need Spring to support contributions?

    First of all, your application needs to know all contributions applying to the extension point.

    Code:
    ContributionDefinition &#91;&#93; contributions=ApplicationContext.getContributions&#40;myExtensionPoint&#41;;
    Next we need a way to check the contribution for applying a certain interface (being compatible with the requirements the stakeholder of the extension point imposes).

    Code:
    for&#40;ContributionDefinition contribution &#58; contributions&#41; &#123;
        if&#40;contribution.isCompatible&#40;Class requiredType&#41;&#41; &#123;
              RequiredType instance=
                  &#40;RequiredType&#41;ApplicationContext.instanciateContribution&#40;contribution&#41;;
              instance.setAdditionalDependencyImposedByRequiredType&#40;dependency&#41;;
              ApplicationContext.finishInstanciationOfContribution&#40;contribution,instance&#41;;
              rememberContributionInstance&#40;instance&#41;;
        &#125;
    &#125;
    This looks ugly because a stakeholder (or the component instanciating a contribution) has to kick in the initialization process to set dynamic dependencies declared by the contract of the extension point.

    So this is the far best method I can currently think of:

    Code:
        applicationContext.instanciateContributions&#40;String extensionPoint, MyExtensionPointPolicy myExtensionPointPolicy&#41;;
    MyContributionPolicy implements ContributionPolicy (or whatever it may be named) which may look like this:

    Code:
     
    ContributionPolicy &#123;
         boolean isCompatibleContribution&#40;ContributionDefinition&#41;;
         void injectAdditionalDependencies&#40;Object instance&#41;;
    &#125;
    Thats all.


    Since a contribution can be hardwired, too (setting dependencies within the application-context definition using the property-tag), this solution would be able to solve some problems I always have while describing a contribution within the Eclipse framework.

    For example the names of an extension point (string) may be dynamic. The implementation of the contribution should not know the actual name of the extension point used within the description. Currently the Eclipse folks use static constants to store an extension point's name inside the implementation. But having hardwiring at hand, I can tell the application/plugin which extension point name (or better an instance of an object) it should use to refer to the extension point. This would drive the framework away from the sniffy String names an extension point issue. (So the framework don't have to deal with strings once all application objects are instanciated).

    That brings me to an aditional idea:

    Code:
    ExtensionPoint &#123;
        void isCompatible&#40;ContributionDefinition&#41;;
    &#125;

    So to summarize:

    We can have all good from both worlds by simply adding the method ApplicationContext.instanciateContributions(...), adding a simple type called ExtensionPointPolicy and extending the dtd by a second type (single liner since the rest would equal the bean-tag). Also a special handling of the contribution-tag (extracting a contribution definition and remember it).

    Thats all which is needed. This feature should be easy to test and I guess contributions can leverage the web-application community as well. Think of not adding hibernate xml files but contributing hibernate mappings within diffrent contextes, contributing security advisors or contributing a certain skin. All seams possible.

    So hardwire the domain layer but contribute views, additional features, applications, plugins and extensions. And that can be done by using Spring.

    Could life be easier?


    Cheers,

    Martin (Kersten)

    PS: I have been dreaming about this for the last 5 months. I guess I outlined a nice implementation for this feature within this post. And hopefully I have shown, that it would fit within Spring world quite great. PSS: Actions,Menus can be also contributed :-).

  • #2
    You give the following example:
    Code:
    <contribution extension-point="my.application.views" class="MyView"> 
         <property name="myProperty"><value>HardwiredStuff</value></property> 
    
    </contribution>
    If I follow this correctly, the extension-point is some sort of known section of an existing bean, that you are injecting this dependency into. So, at some later point, everything relevant to the extension point 'my.application.views' will be pulled together and made available at that point.

    So you are pulling a number of beans of a known type and setting them as dependencies on another bean. What will those dependencies be? Will this bean be expecting a map, a list, a single bean? I take it it will be up to the bean that recieves these dependencies to do whatever it wants with them.

    On the face of this, I would say, why not use a beanfactorypostprocessor to wire up all beans of a specific type to beans that need them.

    Except, looking at your example, the contribution defines, by name, the extension point to which it applies.

    So why not the following:

    A new bean (lets call it Contribution), which you could set up as follows:

    Code:
    <bean class="Contribution"> 
         <property name="extensionPoint">
              <value>my.application.views</value>
         </property> 
         <property name="contribution">
              <bean class="MyView"/>
         </property>
    </contribution>
    In the above example, the extension point is a String, and the contribution property is the contribution you wish to expose.

    Then you could have a bean post processor that picks up all objects of class Contribution, aggregates them by their named extension point and sets them in the beans defined with that extension point. You could even verify that the class of the contribution was valid for the extension point in question.

    Code:
    <bean class="ContributionPostProcessor"> 
         <property name="extensionPoints">
              <value>
                my.application.views=myApplication.views&#40;ApplicationView&#41;
              </value>
         </property> 
    </contribution>
    In the above example, the extension point definition is as follows:
    {extensionPointName}={extensionPointBean}.{setterM ethodForDependencies}({validClasses})

    So what's missing, what are you trying to do that cannot be acheived with existing spring infrastructure?

    Comment


    • #3
      It's a quite diffrent concept.

      For example imagen you have a GUI application. You made up the domain model and the presentation layer is just rudimentary.

      The GUI Platform provides special extension points to register additional views. The orginal application does not know a zip about the extensions. Also the Platform does not know who is contributing explicitly what. The only thing the GUI Platform states as a stakeholder: "If you want to contribute a view, just behave!"

      So its like extending something without the one being extended nowing about that it is extended. But this extension is on demand. You don't instanciate every view on startup. The views are instanciated when the user needs it. Open a view twice within diffrent windows result in two instances of the same particular view contribution.

      Think of setting up the context for your application. Only the domain layer is set up and an intermodul interface. Now you use this context of the application and add a contribution to form a command line application. In the other scenario you are adding the application to the gui framework and contribute the views/wizards/editors.

      In both cases you didn't changed the context definition of the application nor does the application knows who is finally using it. All it knows, someone is interacting with it. It doesn't care who and for what.

      In your example you use a wired on startup approach. You can not control who is using the contributed feature and how. That is up to the stakeholder of the extension points. But think about a scenario where the extension point stakeholder checks who is contributing and only select one for the task (contributing several parsers but only one is needed).

      So you seperate the main application / extension point stakeholder from the extensions. The application does not depend on the extensions and only imposes some basic rudimentary rules by the extension point policy.

      Also your way uses strings to identify the extension point. I am thinking about extension points which are described by a name but while runtime nor the application or the contribution knows the name of the extension point.

      Comment


      • #4
        Also your way uses strings to identify the extension point. I am thinking about extension points which are described by a name but while runtime nor the application or the contribution knows the name of the extension point.
        The way I proposed (finding collaborators by type) doesn't need to use string identified extension points - I just added that feature because your example seemed to have them. And in fact, looking at your example definition of a contribution they do seem to know the name of the extension point:

        Code:
        <contribution extension-point="my.application.views" class="MyView"> 
             <property name="myProperty"><value>HardwiredStuff</value></property> 
        </contribution>
        So something needs to know which collaborator goes where - what does that in your example? You seem to have a ContributionPolicy that vets Contributions before they are wired up to the extension points. This is not incompatible with what I proposed - the postprocessor could use exactly this mechanism to ensure extension points get the right collaborators.

        However, you say you don't like the idea of a static, wiring time only, post-processing approach. How about this:

        On your bean that is providing an extension point, supply the following method:

        Code:
        abstract ContributionDefinitions&#91;&#93; getContributions&#40;&#41;
        Provide a ContributionFactoryBean class that retrieves all beans of type Contribution and returns them. It can use the aforementioned ContributionPolicy to filter the Contributions that are returned. Declare it non-singleton so that it picks up new Contributions at runtime. Use getter injection to implement the abstract method in your bean that provides an extension point. The XML for all this would be:

        Code:
        <bean id="myExtensionPointBean" class="...">
          <lookup-method name="getContributions" bean="contributionFactory"/>
        </bean>
        
        <bean id="contributionFactory" class="ContributionFactory" singleton="false">
          <property name="contibutionPolicy">
            <bean class="ContributionPolicy"/>
          </property>
        </bean>
        
        <bean class="Contribution">
          <property name="myProperty"><value>Hardwired Stuff</value></property>
        </bean>
        In your example you use a wired on startup approach. You can not control who is using the contributed feature and how. That is up to the stakeholder of the extension points. But think about a scenario where the extension point stakeholder checks who is contributing and only select one for the task (contributing several parsers but only one is needed).
        In my example, the extended bean doesn't care how it gets its Contributions, the Contributions don't care where they end up - its all controlled by the ContributionPolicy of the ContributionFactoryBean. The stakeholder is then free to choose which of its contributions it uses, if any.

        Any thoughts?

        Comment


        • #5
          I am under the impression that this feature can be added elegantly without any modifications to the Spring core or the configuration file DTD.

          The suggestions by dhewitt are close to my thoughts. I think if this can be added without touching the core then so much the better.

          Rob

          Comment


          • #6
            I will give it a try how it feels. Maybe the overhead isn't that problematic than I thought initially. But I think it is such a core concept that it should be supported right out of the box but maybe a special extension point factory would make things more declarative than.

            I will give it a shot.

            Comment


            • #7
              One thing that I have a problem with is, how is the extension point referred to?

              Comment


              • #8
                I will give it a try how it feels. Maybe the overhead isn't that problematic than I thought initially. But I think it is such a core concept that it should be supported right out of the box but maybe a special extension point factory would make things more declarative than.
                Its not that I disagree that it should be a core concept. But if you can do it simply wihout modifying the core then I think that's a logical first step. So many core concepts are implemented as generic beans that you add, rather than extensions to the core and changes to the DTD (aop for starters). Originally constructor arguments could only be passed by creating a factory bean - but now its a first-class construct. If this were implemented as some plain beans that would work with *any* version of spring, the barrier to adoption is very low, and there is nothing to stop a tighter integration in future.

                One problem I do see with the approach I've outlined is that it is not possible (AFAIK) to walk the application context heirarchy starting at the root. Heirarchical application contexts only refer to their parents, not their children, so you won't be able to find beans of a specific type that are declared in child application contexts - they will all have to be merged into the root. There are ways round this, but its a bit of a stumbling block.

                One thing that I have a problem with is, how is the extension point referred to?
                I'm not entirely sure what you mean - could you elaborate a little?

                -Dave

                Comment


                • #9
                  The Problem is the explosion of extension types. The target is to make the language you use to wire everything up, so declarative as possible.

                  Imagen you have a gui action:

                  action {
                  abstract run();
                  }

                  Now you are implementing an action you want to contribute:

                  myaction extends action {
                  run {
                  doSerious stuff;
                  }
                  }

                  Now all you want to do is contributing this action to a toolbar and a menu item.

                  so you would do something like:

                  <bean class="myaction"/>

                  This is nice. But you need to specify a name and a type for this action:

                  <bean class="ActionContribution">
                  <property name="name">Name</property>
                  <property name="action"><bean class="myAction"/></property>
                  </bean>

                  But now you need to specify wether you are contributing to a toolbar or a menu.

                  <bean class="ToolbarActionContribution"> ...</bean>
                  <bean class="MenuActionContribution">...</bean>

                  Ok that seams all ok except that this means a lot of typing, maybe
                  supporting a collection of actions to contribute would be solve this, anyway.

                  The problem starts when you are going to contribute to two distinct bean contribution of the same class.

                  Imagen contributing two views of the same view implementation. Now you want contribute to the first view but not to the second. Currently you have no way to go.

                  The only thing would be that using a ToolbarActionContribution you are adding something like a name referring to the view. But I guess this is not a very smart solution.

                  Another thing is about that the everyone you contribute to knows what the extension point actually is.

                  I wanted to take the knowledge about the name of the extension point away from the implementation. Therefore I wanted to set the extension point when declaring the bean.

                  <bean id="application" class="MyApplication>
                  <property name="viewExtensionPoint">
                  <bean class="ExtensionPoint">
                  <property name="toolbarExtensionPoint">org....MyApplication. toolbar</property>
                  </bean>
                  </property>
                  </bean>

                  So all MyApplication knows is having an extension point. The extension point would also be the only one, being able to instanciate any contribution. Therefore without a extension point the application would be out in the woods, left alone.

                  But I guess the strict dtd would also prevent this from being practicable.

                  Another problem is the type hierarchy. Imagen you have an MenuAction type and threat everything that has this type as a contribution to a menu. But saidly someone is implementing a context menu within his view. He uses a ContextMenuAction being subtype of MenuAction, since this is logically for him. But doing so everything he contributes to his view, get also contributed to the orginally intended menu since it is compatible.

                  I guess this can only be done by providing non-extandable XXXContribution implementations for each extension point. Well I guess this has to be checked out.

                  If you have any additional idea to one of those problems, I would like to hear.


                  Cheers,

                  Martin (Kersten)

                  Comment

                  Working...
                  X