PicoContainer
  1. PicoContainer
  2. PICO-22

Add the ability for components to be re-initialized with their dependencies after creation

    Details

    • Type: Improvement Improvement
    • Status: Closed Closed
    • Priority: Major Major
    • Resolution: Won't Fix
    • Affects Version/s: 1.0-beta-1
    • Fix Version/s: None
    • Component/s: PicoContainer (Java)
    • Labels:
      None
    • Number of attachments :
      0

      Description

      If components have been serialized or are sent via RMI, they need to be able to be re-wired to their dependencies.

        Issue Links

          Activity

          Hide
          Aslak Hellesøy added a comment -

          I don't quite understand this RFE. Wouldn't Java's native serialisation mechanism take care of this? -Unless the dependencies are transient?

          Could you provide a test case (preferrably in compilable code, but pseudocode will also do) that illustrates the desired behaviour?

          The responsabilities of the container versus the component are a bit blurry to me too.

          Show
          Aslak Hellesøy added a comment - I don't quite understand this RFE. Wouldn't Java's native serialisation mechanism take care of this? -Unless the dependencies are transient? Could you provide a test case (preferrably in compilable code, but pseudocode will also do) that illustrates the desired behaviour? The responsabilities of the container versus the component are a bit blurry to me too.
          Hide
          Brett Knights added a comment -

          This is some discussion from the WebWork2 mailing list that has a bearing on this issue. I don't know if the approach described is ideologically compatible with picocontainer but it does seem to me to be a lightweight approach.

          Everyone seems to want to write "pure" business objects that have no
          dependencies on their framework. This is a good thing. This often translates
          to people wanting to write objects that don't know they will be used in a
          framework. This seems impossible if you actually want your objects to work
          with the features of the framework.

          For instance it is likely that any reference you have to something supplied
          by the framework should be marked transient. Your code has to declare that -
          it can't be managed by the framework.

          To integrate this with a framework you'd need a decorator object that
          handles the initialization in a framework dependent way and overrides
          (perhaps) readObject to refresh the framework supplied values.

          A simple way to do this is with xDoclet (another dependency !)

          e.g.
          package com.mycompany.business;
          /** Implements some business rules

          • @ioc.framework.configurationMethod setDataSource(DataSource)
            public class BusinessObject implements Serializable { private transient DataSource frameworkDataSource; ... public void nonIOCMethod(); }

          Running xDoclet on this source file would produce something like:

          package org.frameworkorg.com.mycompany.business;
          public class BusinessObjectWrapper extends
          com.mycompany.business.BusinessObject
          {
          BusinessObject obj;
          public BusinessObjectFrameworkWrapper

          { obj = new BusinessObject(); // calling the ioc methods here removes the need to extend readObject() obj.setDataSource(framework.getDataSource()); }

          //
          public void nonIOCMethod()

          { obj.nonIOCMethod(); }

          }

          The framework could check to see if an XXXFrameworkWrapper class is
          available and, if it is, it would instantiate, configure and return that.
          Using xDoclet to generate the necessary classes means that the class should
          be able to be adapated to run under any IoC framework - "only" the code
          generation boilerplate would need to be changed.

          For scoped objects the framework would generate an XXXFrameworkWrapper and
          store that in the requested scope. One of the issues being discussed on this
          point is the need to re-set the object into the session in a distributed
          situation. This should be trivial to accomplish:

          e.g.
          public void nonIOCMethod()

          { obj.nonIOCMethod(); if(framework.getSession().containsValue(this)) framework.getSession().put(framework.getSessionKey(this), this); //watch performance on key lookup. }

          The framework specific decorator doesn't, of course, need to go into another package when it's being generated by xDoclet. When you don't have access to the original source you should be able to generate a suitable decorator by other means. e.g. make a config file that specifies the class and nominates the configuration methods.

          These examples are trivial. Any XXXFrameworkWrapper only extends its base class. It may be desirable to apply the same configuration to a subclass of BusinessObject. If this is the case then the code generator could (as one strategy) use java.lang.reflect.Proxy to return an object of the desired type while still overriding the correct methods in a framework specific way.

          > Based on what you've described, I don't agree with you.
          > Personally, I
          > think of frameworks such as xwork/webwork can be thought of a
          > sophisticated
          > adapter. They adapt my business logic to the web, swing,
          > jms, what have
          > you. When I'm working on presentation or other layer
          > integration issues,
          > I'm dealing directly with the framework. However, when I'm
          > working on
          > business logic, I want the framework to get out of my way.

          Sure I totally agree that the environment should be gotten out of the way as
          much as possible. But exactly how transparent the environment can be is the
          subject of my post.

          >
          > Can you provide a more detailed example of framework features
          > you want to
          > get access to directly from your business logic?
          >
          > M

          In the discussion so far there are two examples of things I need to do to in my business code that are mandated by the environment. Neither of these is in any way related to the business rules implemented by my model classes:
          1. Somehow mark the methods I want called (configured) when the object is instantiated. Currently this requires creating an artificial constructor.
          2. Allow the object to work in a servlet environment that manages reloading by serializaton/deserialization. I suspect clustering solutions may also use serialization for distributing objects.

          Even if you offload item 1. to yet another configuration file (files?) you still need to address item 2. in some fashion.
          The current xwork direction (picocontainer) breaks Serialization which I think is a bad thing. It requires an artificial constructor (also a bad thing IMO). Objects may have to re-set themselves into a session (another environment aware behaviour) in order to be shared in a cluster.

          With this proposal you just create your beans knowing they may be distributed (serialized) and that certain things will be supplied by the invoking environment. The things you want to be supplied by the environment get specified twice (once in the code with the transient keyword and once with an xDoclet tag) but in a very non-verbose way. xDoclet could potentially be set up to produce wrapper classes for just about any IoC framework without changing the tags.

          Show
          Brett Knights added a comment - This is some discussion from the WebWork2 mailing list that has a bearing on this issue. I don't know if the approach described is ideologically compatible with picocontainer but it does seem to me to be a lightweight approach. Everyone seems to want to write "pure" business objects that have no dependencies on their framework. This is a good thing. This often translates to people wanting to write objects that don't know they will be used in a framework. This seems impossible if you actually want your objects to work with the features of the framework. For instance it is likely that any reference you have to something supplied by the framework should be marked transient. Your code has to declare that - it can't be managed by the framework. To integrate this with a framework you'd need a decorator object that handles the initialization in a framework dependent way and overrides (perhaps) readObject to refresh the framework supplied values. A simple way to do this is with xDoclet (another dependency !) e.g. package com.mycompany.business; /** Implements some business rules @ioc.framework.configurationMethod setDataSource(DataSource) public class BusinessObject implements Serializable { private transient DataSource frameworkDataSource; ... public void nonIOCMethod(); } Running xDoclet on this source file would produce something like: package org.frameworkorg.com.mycompany.business; public class BusinessObjectWrapper extends com.mycompany.business.BusinessObject { BusinessObject obj; public BusinessObjectFrameworkWrapper { obj = new BusinessObject(); // calling the ioc methods here removes the need to extend readObject() obj.setDataSource(framework.getDataSource()); } // public void nonIOCMethod() { obj.nonIOCMethod(); } } The framework could check to see if an XXXFrameworkWrapper class is available and, if it is, it would instantiate, configure and return that. Using xDoclet to generate the necessary classes means that the class should be able to be adapated to run under any IoC framework - "only" the code generation boilerplate would need to be changed. For scoped objects the framework would generate an XXXFrameworkWrapper and store that in the requested scope. One of the issues being discussed on this point is the need to re-set the object into the session in a distributed situation. This should be trivial to accomplish: e.g. public void nonIOCMethod() { obj.nonIOCMethod(); if(framework.getSession().containsValue(this)) framework.getSession().put(framework.getSessionKey(this), this); //watch performance on key lookup. } The framework specific decorator doesn't, of course, need to go into another package when it's being generated by xDoclet. When you don't have access to the original source you should be able to generate a suitable decorator by other means. e.g. make a config file that specifies the class and nominates the configuration methods. These examples are trivial. Any XXXFrameworkWrapper only extends its base class. It may be desirable to apply the same configuration to a subclass of BusinessObject. If this is the case then the code generator could (as one strategy) use java.lang.reflect.Proxy to return an object of the desired type while still overriding the correct methods in a framework specific way. > Based on what you've described, I don't agree with you. > Personally, I > think of frameworks such as xwork/webwork can be thought of a > sophisticated > adapter. They adapt my business logic to the web, swing, > jms, what have > you. When I'm working on presentation or other layer > integration issues, > I'm dealing directly with the framework. However, when I'm > working on > business logic, I want the framework to get out of my way. Sure I totally agree that the environment should be gotten out of the way as much as possible. But exactly how transparent the environment can be is the subject of my post. > > Can you provide a more detailed example of framework features > you want to > get access to directly from your business logic? > > M In the discussion so far there are two examples of things I need to do to in my business code that are mandated by the environment. Neither of these is in any way related to the business rules implemented by my model classes: 1. Somehow mark the methods I want called (configured) when the object is instantiated. Currently this requires creating an artificial constructor. 2. Allow the object to work in a servlet environment that manages reloading by serializaton/deserialization. I suspect clustering solutions may also use serialization for distributing objects. Even if you offload item 1. to yet another configuration file (files?) you still need to address item 2. in some fashion. The current xwork direction (picocontainer) breaks Serialization which I think is a bad thing. It requires an artificial constructor (also a bad thing IMO). Objects may have to re-set themselves into a session (another environment aware behaviour) in order to be shared in a cluster. With this proposal you just create your beans knowing they may be distributed (serialized) and that certain things will be supplied by the invoking environment. The things you want to be supplied by the environment get specified twice (once in the code with the transient keyword and once with an xDoclet tag) but in a very non-verbose way. xDoclet could potentially be set up to produce wrapper classes for just about any IoC framework without changing the tags.
          Hide
          Jason Carreira added a comment -

          I'm no serialization expert, but what happens to references to objects in the Application scope when your Session is passivated and re-activated? Some service references will need to be transient, for instance connections to JNDI services, etc. These things need to be able to be re-established. Also, what if you're sending a command object (a WebWork action, for instance) across RMI to be run on the server? I'd probably set up the Action without it's services on the client side, and just populate it with the parameters it will need to run. On the server side, I'd like to wire it up to the services it requires before running it.

          For session serialization, if your Object needed to, it could implement HttpSessionActivationListener to be notified of Session lifecycle events and be able to call its own init() method which would ask Pico to re-initialize the component dependencies.

          For RMI, the server would be in control of setting up the component before executing it.

          Show
          Jason Carreira added a comment - I'm no serialization expert, but what happens to references to objects in the Application scope when your Session is passivated and re-activated? Some service references will need to be transient, for instance connections to JNDI services, etc. These things need to be able to be re-established. Also, what if you're sending a command object (a WebWork action, for instance) across RMI to be run on the server? I'd probably set up the Action without it's services on the client side, and just populate it with the parameters it will need to run. On the server side, I'd like to wire it up to the services it requires before running it. For session serialization, if your Object needed to, it could implement HttpSessionActivationListener to be notified of Session lifecycle events and be able to call its own init() method which would ask Pico to re-initialize the component dependencies. For RMI, the server would be in control of setting up the component before executing it.
          Hide
          Jason Carreira added a comment -

          ...oh, that was my way of saying "no, I can't provide source code..." I'm talking theories and haven't looked at the Pico code yet.

          Show
          Jason Carreira added a comment - ...oh, that was my way of saying "no, I can't provide source code..." I'm talking theories and haven't looked at the Pico code yet.
          Hide
          Jon Tirsen added a comment -

          Traditionally we have recommended reinstantiation of all components in the container in cases such as this. Could you state an example where this is not sufficient?

          Show
          Jon Tirsen added a comment - Traditionally we have recommended reinstantiation of all components in the container in cases such as this. Could you state an example where this is not sufficient?
          Hide
          Jason Carreira added a comment -

          I have already given an example of where this is needed... If I populate a WebWork Action and serialize it across the wire (RMI or to a special Servlet Dispatcher that expects a serialized Action), then I need to re-wire the component dependencies before I execute it.

          Show
          Jason Carreira added a comment - I have already given an example of where this is needed... If I populate a WebWork Action and serialize it across the wire (RMI or to a special Servlet Dispatcher that expects a serialized Action), then I need to re-wire the component dependencies before I execute it.
          Hide
          Jon Tirsen added a comment -

          I understand. The only way to support rewiring dependencies is by reinstantiating the components.

          Show
          Jon Tirsen added a comment - I understand. The only way to support rewiring dependencies is by reinstantiating the components.
          Hide
          Aslak Hellesøy added a comment -

          This is a more concrete specification of PICO-22

          Show
          Aslak Hellesøy added a comment - This is a more concrete specification of PICO-22
          Aslak Hellesøy made changes -
          Field Original Value New Value
          Link This issue is depended upon by PICO-24 [ PICO-24 ]
          Hide
          Paul Hammant added a comment -

          I have implemented basic serializability to DefaultPicoContainer.

          I'd like to propose that we solve the non-serializable issue by asking component mfrs to honor serialization. As all containers become serilaible ... the developer coding the serialization of the container should (depending on which container they are using) end/stop lifecycle of comps hosted by the container, serialize the container with components in situ. One deserilaization, they whould (depending on impl), deserialize, then 'start' the container.

          Thus I am suggesting there is no active removal of unserializable components.

          Thus I propose that we continue marking components of Pico and Nano as Serilaible and closed this issue.

          Show
          Paul Hammant added a comment - I have implemented basic serializability to DefaultPicoContainer. I'd like to propose that we solve the non-serializable issue by asking component mfrs to honor serialization. As all containers become serilaible ... the developer coding the serialization of the container should (depending on which container they are using) end/stop lifecycle of comps hosted by the container, serialize the container with components in situ. One deserilaization, they whould (depending on impl), deserialize, then 'start' the container. Thus I am suggesting there is no active removal of unserializable components. Thus I propose that we continue marking components of Pico and Nano as Serilaible and closed this issue.
          Hide
          Aslak Hellesøy added a comment -

          No comments after Paul's suggestion to close this, so closed it is.

          Show
          Aslak Hellesøy added a comment - No comments after Paul's suggestion to close this, so closed it is.
          Aslak Hellesøy made changes -
          Status Unassigned [ 1 ] Closed [ 6 ]
          Resolution Won't Fix [ 2 ]

            People

            • Assignee:
              Unassigned
              Reporter:
              Jason Carreira
            • Votes:
              0 Vote for this issue
              Watchers:
              0 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: