Announcement Announcement Module
Collapse
No announcement yet.
Dynamic nested properties Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Dynamic nested properties

    Hello all,

    I guess I can explain my problem best by a small code-exmaple:

    <beans>
    <bean id="DeviceManager" class="...">
    <property name="devices">
    <list>
    <ref id="device_1" />
    <ref id="device_2" />
    ....
    <ref id="device_n" />
    </list>
    </property>
    </bean>

    <bean id="device_1" class="MyDevice">
    ... etc....
    </bean>

    <bean id="device_n" class="MyDevice">
    ... etc....
    </bean>
    </beans>

    My problem: My devicemanager has a list of devices. The DeviceManager receives some information, passes this on to the devices and waits for result (callback)

    Now, the example above probably works, but the device definitions are pretty dynamic. Each installation of the application has a different device list.

    I could each time modify the beans.xml file (which will become pretty big) or look for another solution.

    In the avalon framework, you could instantiate a device (from within the devicemanager) and pass on a configuration using the ConfigurationUtils.
    What is the best way in Spring?

    A database might be an option, but we are working with existing code (port from avalon to Spring) and using a database requires a rewrite. Besides this, there is also a lifecycle issue .

    Another solution is to give a configuration file to the devicemanager which uses a factory (in combination with the config file) to instantiate a list of devices, but this seems odd.....

    Any suggestions welcome

    Regards,
    Barry

  • #2
    If all the devices implement an IDevice interface, you can make DeviceManager look for devices using factory.getBeansOfType(IDevice.class). DeviceManager needs, of course, to implement BeanFactoryAware. This Implies that all devices will be manager by the same manager.
    HTH

    Comment


    • #3
      Originally posted by irbouho
      DeviceManager needs, of course, to implement BeanFactoryAware
      Alternatively the assignment of devices to the manager could be done manually.
      1. Get the device manager from the context (which you might probably do anyway)
      2. Get all Devices (getBeansOfType)
      3. Assign the devices to the manager.

      This way the device manager will not be coupled to spring and you have full control over the assignment. You could probably also use multiple device managewr this way.

      Additionally I'd like to suggest an improvement concerning your file size issue:
      You might create one configuration file per device, containing only the device bean (alternatively you can also have a group of devices per file). You can then change the initialization of your bean factory to load your main configuration file (containing the device manager) and all device configuration files. This way your configuration might be more fine grained and easier to maintain. The usage will be unchanged since the bean definitions from all files will be merged within the factory.
      If the files containing the device beans adhere to a distinct naming pattern, the loading might be automatized, so you can add/remove devices without changing anything (beside refreshing the context/ restarting the application).

      Regards,
      Andreas

      Comment


      • #4
        Thanks Omar and Andreas,

        Originally posted by Andreas Senft
        Alternatively the assignment of devices to the manager could be done manually.
        1. Get the device manager from the context (which you might probably do anyway)
        2. Get all Devices (getBeansOfType)
        3. Assign the devices to the manager.
        This sounds like the way to go! I'll start right away ;-)
        I definitely do not want any spring interfaces in my code (we have had this with avalon....)

        Originally posted by Andreas Senft
        If the files containing the device beans adhere to a distinct naming pattern, the loading might be automatized, so you can add/remove devices without changing anything (beside refreshing the context/ restarting the application).
        Ok: a newbie question: how exactly would I automate. Are you referring to runtime addition of devices? That would be a features that is not requested but with which we could really please the customer (I guess)

        Thanks again,
        Barry

        Comment


        • #5
          Originally posted by barrel
          Ok: a newbie question: how exactly would I automate. Are you referring to runtime addition of devices?
          I just thought of a simple means to change the configuration, so to just add/change configuration files and restart without registering the files explicitly or something like that.
          If it is no problem to dynamically replace your device manager (or the devices registered to it) while running your application, I guess it will not be hard to accomplish that with the proposed approach. When using prototype beans for the devices it should be easier. With singleton beans you have to take care about held references when you try to reconfigure your device.manager.

          As for the automatism:
          The reading in of the configuration files is usually done with XmlBeanDefinitionReader#loadBeanDefinitions, which you can invoke several times. So you can look up files matching a specific pattern in a predefined search path and loop over them to load the contained definitions (with the above mentioned method).
          So you are not required to change this code ever again, when you add (or remove) some configuration files (as long as the lookup pattern does not change).

          Hope that helps,
          Andreas

          Comment


          • #6
            Thanks for your comments.

            One last question/thought:

            something like this is not possibel:

            <bean id="DisplayManager" etc>
            <property>
            <list>
            <value>be.nauta.displays.MyDisplayInterface</value>
            </list>
            etc

            Forcing the list to be populated with all instances of MyDisplayInterface?

            Comment


            • #7
              It cannot be done out of the box. However, you might provide your own FactoryBean implementation to achieve this.

              An implementation should be aware of its bean factory, look-up the specified beans and return them. I am just not sure about the initialization order in this case. The factory bean has to be initialized after the other beans in order to be effective. I remember some initialization order issues being discussed in the past. However, I cannot provide a profound statement on this issue. If it cannot be deduced from the reference documentation (I haven't searched it on this issue) maybe Jürgen or someone else from the Spring Team could provide help on that topic.

              Performing the lookup lazily might prove useless if the factory bean is referenced from another bean (which seems to be the case here, where it would be referenced by the device manager).

              Regards,
              Andreas

              Comment


              • #8
                Sorry to bother again, but I am a bit confused about the lifecycle.

                Normally, the init-method is only called after all the properties are set.
                I now use 'getBeansOfType(...)' to retrieve a Map of Devices.
                I pass these to the DeviceManager, using the following code:

                DeviceManagerInterface deviceManager =
                (DeviceManagerInterface) context.getBean ("deviceManager");
                Map devices =
                context.getBeansOfType(Class.forName("be.switchsof t.ids.devicemanager.base.Device"));
                deviceManager.setDevices (devices);

                Pretty straight-forward except for the part that the devicemanager is now already initialized before it gets the devices... Something that is not wanted, since during the initialization phase the device manager starts collecting some data that needs to be sent to the devices..... Now... if I could simple give the devices to the manager during paramterization phase.... :wink:

                Any suggestions?

                Thanks
                Barry

                Comment


                • #9
                  Well... have been trying to use a BeanPostProcessor but before this postprocessor is initialised, some of the beans already have received their initialisation.

                  Code:
                  ConfigurableApplicationContext context = new ClassPathXmlApplicationContext ("beans.xml");
                  IdsBeanPostProcessor idsBeanPostProcessor = new IdsBeanPostProcessor (context);
                  ConfigurableListableBeanFactory factory = context.getBeanFactory();
                  factory.addBeanPostProcessor(idsBeanPostProcessor) ;

                  And only afterwards I ask for the first beans from the context.... Guess the configurableApplicationContext does a lot of stuff.... Probably RTFM but not very intuitive....

                  Comment


                  • #10
                    Originally posted by barrel
                    Well... have been trying to use a BeanPostProcessor but before this postprocessor is initialised, some of the beans already have received their initialisation.
                    I guess you mean that part of the device-beans are initialized and then you enter post-processing of the device-manager. It is possible to specify dependencies within the configuration file (using the attribute "depends-on"). However, this implies to register dependencies for all device beans with the device-manager (which is not wanted). So I fear I cannot come up with a solution for this scenario.

                    Maybe the programmatic approach should indeed prove to be simpler to realize.

                    Regards,
                    Andreas

                    Comment


                    • #11
                      Yep, basically it means that I have to 'implement' the lifecycle management myself.
                      First instantiate (partially programmatic) all beans since I definitely do not want a depends-on a dynamic list and afterwards initialize....

                      Thanks for the help,
                      Barry

                      Comment


                      • #12
                        Originally posted by irbouho
                        If all the devices implement an IDevice interface, you can make DeviceManager look for devices using factory.getBeansOfType(IDevice.class). DeviceManager needs, of course, to implement BeanFactoryAware. This Implies that all devices will be manager by the same manager.
                        HTH
                        Isn't this simpler to do?

                        Comment


                        • #13
                          Originally posted by irbouho
                          Originally posted by irbouho
                          If all the devices implement an IDevice interface, you can make DeviceManager look for devices using factory.getBeansOfType(IDevice.class). DeviceManager needs, of course, to implement BeanFactoryAware. This Implies that all devices will be manager by the same manager.
                          HTH
                          Isn't this simpler to do?
                          Well.... yes and no. Simpler because it does what I want to do, but not simpler since I would make my code dependant of Spring.

                          We are currently changing from Avalon to Spring, but I want to be able to switch just as quickly to Pico (for instance) if Spring doesn't do what I want to do.....

                          On the other hand... it is worth giving a try :wink:

                          Comment


                          • #14
                            One thing I just thought of:

                            If you can live with having your device beans in another configuration file (or several other configuration file) than the device-manager bean you could do the following:

                            Initialize your device-manager with a BeanPostProcessor which looks up the other configuration files and loads the contained device-beans. For this you could use the approach I mentioned some postings above. This way you do not have to take care about the order in which beans will be initialized within one context file. The lookup path/ file pattern might be configured with properties of your BeanPostProcessor.

                            Regards,
                            Andreas

                            Comment

                            Working...
                            X