PicoContainer
  1. PicoContainer
  2. PICO-142

All components are not created on start()

    Details

    • Type: Bug Bug
    • Status: Closed Closed
    • Priority: Major Major
    • Resolution: Won't Fix
    • Affects Version/s: 1.0-beta-5
    • Fix Version/s: 1.0-RC-1
    • Component/s: None
    • Labels:
      None
    • Number of attachments :
      0

      Description

      It is an extremely common pattern in Pico applications to register listeners in the constructor. It is therefor crucial that start() instantiates all components in the container. This pattern is even used in the demo we did at JavaPolis.

      The following code should outline the pattern:

      public interface SocketConnector
      {
      void addSocketListener(SocketListener listener);
      }

      public interface SocketListener extends java.util.EventListener
      {
      void socketRequest(Socket socket);
      }

      public class SocketServer implements SocketConnector, Lifecycle
      {
      public void start()

      { // start listening to socket }

      // ...
      }

      public class HttpServer implements SocketListener
      {
      public HttpServer(SocketConnector connector)

      { connector.addSocketListener(this); }

      public void socketRequest(Socket socket)

      { // implement http }

      }

      MutablePicoContainer pico = new DefaultPicoContainer();
      pico.registerComponentImplementation(SocketServer.class);
      pico.registerComponentImplementation(HttpServer.class);
      pico.start();

      If not both the SocketServer and the HttpServer is instantiated in start() the server will simply not function. The server will listen to requests on the socket but noone will process them. A catastrophy!

        Issue Links

          Activity

          Jon Tirsen made changes -
          Field Original Value New Value
          Fix Version/s 1.0-beta-5 [ 10145 ]
          Hide
          Aslak Hellesøy added a comment -

          Even if this is an "extremely common" pattern (which I doubt), it isn't necessarily a good pattern.

          Making the classes that register themselves as a listener Startable solves this problem. (addListener(this) in start, removeListener(this) in stop()).

          See http://lists.codehaus.org/pipermail/picocontainer-dev/2004-February/002738.html

          Show
          Aslak Hellesøy added a comment - Even if this is an "extremely common" pattern (which I doubt), it isn't necessarily a good pattern. Making the classes that register themselves as a listener Startable solves this problem. (addListener(this) in start, removeListener(this) in stop()). See http://lists.codehaus.org/pipermail/picocontainer-dev/2004-February/002738.html
          Hide
          Thomas Heller added a comment -

          To fix your issue in the way start() is handled now:

          pico.getComponentInstances();
          pico.start();

          If your "fix" this issue you need to wipe lazy instantiation from your feature list. I use transient components (shame on me) inside the container which get instantiated when start is called and forgotten afterwards which is a totally unnecessary.

          However, I really think its a matter of style and maybe adding listeners in a ctor is just something sub-optimal?

          PS: I wrote about this 5 hours ago, whats up with the mailing list server?

          Show
          Thomas Heller added a comment - To fix your issue in the way start() is handled now: pico.getComponentInstances(); pico.start(); If your "fix" this issue you need to wipe lazy instantiation from your feature list. I use transient components (shame on me) inside the container which get instantiated when start is called and forgotten afterwards which is a totally unnecessary. However, I really think its a matter of style and maybe adding listeners in a ctor is just something sub-optimal? PS: I wrote about this 5 hours ago, whats up with the mailing list server?
          Hide
          Jon Tirsen added a comment -

          "Not a very good pattern". It was me and you that came up with the pattern so if you have a better suggestion I would really like to hear about it. As I see it there's not better way of doing it.

          Doing pico.getComponentInstances() and then doing pico.start() is counterintuitive. In my opinion calling "start" is what should instantiate all the components, especially since Pico-components uses the constructor for a lot of things.

          Besides, having complicated logic in the container that filters out only the Startables seems unnecessary. I think we should go for the simplest thing that can possibly work.

          Is it really such a big problem to instantiate all the components? The current garbage collector (post JDK 1.4) is absurdly good at cleaning away short-lived objects. In fact it is so good at doing this that having conditional logic that avoids creating short-lived objects actually in the end makes things slower! (due to the overhead of the extra conditional logic)

          If it's just an optimization I think we should remove it. Optimizations like this just bloat the code and introduce bugs (and in the end actually hurt performance). Especially since I rely on this behaviour in the way I use PicoContainer. If it's something that is required I really do want to hear about why someone can't live without it.

          Show
          Jon Tirsen added a comment - "Not a very good pattern". It was me and you that came up with the pattern so if you have a better suggestion I would really like to hear about it. As I see it there's not better way of doing it. Doing pico.getComponentInstances() and then doing pico.start() is counterintuitive. In my opinion calling "start" is what should instantiate all the components, especially since Pico-components uses the constructor for a lot of things. Besides, having complicated logic in the container that filters out only the Startables seems unnecessary. I think we should go for the simplest thing that can possibly work. Is it really such a big problem to instantiate all the components? The current garbage collector (post JDK 1.4) is absurdly good at cleaning away short-lived objects. In fact it is so good at doing this that having conditional logic that avoids creating short-lived objects actually in the end makes things slower ! (due to the overhead of the extra conditional logic) If it's just an optimization I think we should remove it. Optimizations like this just bloat the code and introduce bugs (and in the end actually hurt performance). Especially since I rely on this behaviour in the way I use PicoContainer. If it's something that is required I really do want to hear about why someone can't live without it.
          Hide
          Aslak Hellesøy added a comment -

          <Jon>
          It was me and you that came up with the pattern so if you have a better suggestion I would really like to hear about it.
          </Jon>

          Sounds like you missed my comment on the list and the link above. I sketch out what I believe is a better solution here:
          http://lists.codehaus.org/pipermail/picocontainer-dev/2004-February/002738.html

          The original TulipTrader code is here:
          http://cvs.codehaus.org/viewcvs.cgi/sample/src/java/org/picocontainer/sample/tulip/TulipTrader.java?rev=1.1&root=picocontainer&view=auto

          Show
          Aslak Hellesøy added a comment - <Jon> It was me and you that came up with the pattern so if you have a better suggestion I would really like to hear about it. </Jon> Sounds like you missed my comment on the list and the link above. I sketch out what I believe is a better solution here: http://lists.codehaus.org/pipermail/picocontainer-dev/2004-February/002738.html The original TulipTrader code is here: http://cvs.codehaus.org/viewcvs.cgi/sample/src/java/org/picocontainer/sample/tulip/TulipTrader.java?rev=1.1&root=picocontainer&view=auto
          Hide
          Jon Tirsen added a comment -

          <Aslak from mailing list>
          Don't you think the following implementation is cleaner? (It cleans up
          after itself).

          [... snipped code where addListener is done in start() and removeListener in stop() ...]

          </Aslak from mailing list>

          Indeed! I did miss that email! I think I like it actually... I have to think about it, but I think it actually solves our problem. That is the proper pattern, we should document it in the documentation.

          Still though, if the only reason for not instantiating all components in start() is because we don't want to waste instances I think it's a bad reason (and as of 1.4 it actually decreases performance!). If there's better reasons for doing it I'd really like to hear about them.

          Show
          Jon Tirsen added a comment - <Aslak from mailing list> Don't you think the following implementation is cleaner? (It cleans up after itself). [... snipped code where addListener is done in start() and removeListener in stop() ...] </Aslak from mailing list> Indeed! I did miss that email! I think I like it actually... I have to think about it, but I think it actually solves our problem. That is the proper pattern, we should document it in the documentation. Still though, if the only reason for not instantiating all components in start() is because we don't want to waste instances I think it's a bad reason (and as of 1.4 it actually decreases performance!). If there's better reasons for doing it I'd really like to hear about them.
          Hide
          Rafal Krzewski added a comment -

          The components instantiated by container.start() for no reason will not be short lived, if they are attached using DefaultComponentAdapter, or any adapter stack including CachingComponentAdapter.

          They'll just sit around as long as the container object is used, even if they won't be accessed ever again (unless stop() is called that is)

          Please don't kill the lazy instantiation concept, just because the gains are neglible in small applications...

          Show
          Rafal Krzewski added a comment - The components instantiated by container.start() for no reason will not be short lived, if they are attached using DefaultComponentAdapter, or any adapter stack including CachingComponentAdapter. They'll just sit around as long as the container object is used, even if they won't be accessed ever again (unless stop() is called that is) Please don't kill the lazy instantiation concept, just because the gains are neglible in small applications...
          Hide
          Jon Tirsen added a comment -

          <Rafal>
          Please don't kill the lazy instantiation concept, just because the
          gains are neglible in small applications...
          </Rafal>

          Why not? Do you have a very large number of components where this would actually make a difference? Counting that a Java object takes up about 10 bytes of space it would literally take thousands of components to make a difference.

          I'm just curious. I think I buy Aslaks argument about a better way of doing what I'm trying to do.

          Show
          Jon Tirsen added a comment - <Rafal> Please don't kill the lazy instantiation concept, just because the gains are neglible in small applications... </Rafal> Why not? Do you have a very large number of components where this would actually make a difference? Counting that a Java object takes up about 10 bytes of space it would literally take thousands of components to make a difference. I'm just curious. I think I buy Aslaks argument about a better way of doing what I'm trying to do.
          Hide
          Jon Tirsen added a comment -

          Okay, I think I like this solution. There's only one problem to it: You need to depend on a Pico-specific interface to make a common usage scenario (listening to events from dependencies) work. Any opinions on that?

          Show
          Jon Tirsen added a comment - Okay, I think I like this solution. There's only one problem to it: You need to depend on a Pico-specific interface to make a common usage scenario (listening to events from dependencies) work. Any opinions on that?
          Hide
          Jörg Schaible added a comment -

          Well, following the pattern, you'll have to use Startable, but you
          may very easily revert the situation by deriving your own
          DefaultContainer:

          class MyDefaultContainer extents DefaultContainer {
          // ... snipped ctors
          public start()

          { getComponentInstances(); super.start(); }

          }

          This implementation hides the additional step in your code. So you
          create an enhanced functionality with a simple enhancement.

          OTOH it would be much more difficult to get an own DefaultContainer
          that does not instanciates anything if the underlaying
          implementation do so. Both was demonstrated in a mail from Thomas.

          Regards,
          Jörg

          Show
          Jörg Schaible added a comment - Well, following the pattern, you'll have to use Startable, but you may very easily revert the situation by deriving your own DefaultContainer: class MyDefaultContainer extents DefaultContainer { // ... snipped ctors public start() { getComponentInstances(); super.start(); } } This implementation hides the additional step in your code. So you create an enhanced functionality with a simple enhancement. OTOH it would be much more difficult to get an own DefaultContainer that does not instanciates anything if the underlaying implementation do so. Both was demonstrated in a mail from Thomas. Regards, Jörg
          Aslak Hellesøy made changes -
          Fix Version/s 1.0-beta-5 [ 10145 ]
          Fix Version/s 1.0-RC-1 [ 10461 ]
          Affects Version/s 1.0-beta-5 [ 10145 ]
          Hide
          Aslak Hellesøy added a comment -

          In order to keep the lazy instantiation feature intact, this issue is now closed.

          Show
          Aslak Hellesøy added a comment - In order to keep the lazy instantiation feature intact, this issue is now closed.
          Aslak Hellesøy made changes -
          Status Open [ 1 ] Closed [ 6 ]
          Resolution Won't Fix [ 2 ]
          Assignee Aslak Hellesoy [ rinkrank ]
          Jörg Schaible made changes -
          Link This issue is related to PICO-120 [ PICO-120 ]

            People

            • Assignee:
              Aslak Hellesøy
              Reporter:
              Jon Tirsen
            • Votes:
              0 Vote for this issue
              Watchers:
              0 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: