Wicket
  1. Wicket
  2. WICKET-1312

Generic inter-component event mechanism

    Details

    • Type: New Feature New Feature
    • Status: Resolved
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 1.3.0-final
    • Fix Version/s: 1.5-M2.1
    • Component/s: wicket-extensions
    • Labels:
      None

      Description

      The attached patch provides a generic mechanism for transmitting inter-component events within a page. This has grown primarily from the need to repaint all relevant ajax components after an event, but can be used also in non-ajax environments such as after normal form submits.

      The basic idea is to fire an IVisitor on the page of the component sending an event, giving as an argument an event-specific listener interface that must be implemented by the components willing to receive the events. They can then do whatever they need such as add themselves to the AjaxRequestTarget that can be supplied in the event.

      Sometimes the basic Wicket mechanisms such as sharing a model are not enough; particularly repainting all relevant components in Ajax events gets tedious if the components are far away from each other in a complex DOM tree.

      The benefits of this approach are

      • loose coupling between the sending and receiving end
      • however, because of strong static typing it's easy enough to find with an IDE from where the events are broadcasted and where they are received
      • good testability (EventBroadcaster can be mocked on the sending end, and event handlers tested directly on the receiving end, possibly with mock events)
      • no need the keep references to Component instances or their paths (which could have been problematic on repeaters)

      (This is not a real observer or listener pattern implementation because the components cannot register and unregister themselves dynamically, but "registering" is handled statically on a class basis by implementing the relevant event receiver interface.)

      1. event-handler-with-testcase.zip
        5 kB
        Peter Ertl
      2. Generic_EventBroadcaster_glued_in_Component.patch
        34 kB
        Timo Rantalaiho
      3. Generic_EventBroadcaster.patch
        30 kB
        Timo Rantalaiho

        Issue Links

          Activity

          Transition Time In Source Status Execution Times Last Executer Last Execution Date
          Open Open Resolved Resolved
          932d 3h 43m 1 Igor Vaynberg 18/Aug/10 21:46
          Hide
          Igor Vaynberg added a comment -

          @Sven

          Re #1 if you have a reference to the sink then you dont need an event system do you?

          Re #2 whats wrong with simple:

          void onEvent(event) {
          object payload=event.getpayload();
          if (payload instanceof SomeEventICareAbout)

          {....process event....}
          else if (payload instanceof SomeOtherEventICareAbout) {....process event....}

          }

          usually there will be just one type of event you care about so the code is pretty simple.

          Show
          Igor Vaynberg added a comment - @Sven Re #1 if you have a reference to the sink then you dont need an event system do you? Re #2 whats wrong with simple: void onEvent(event) { object payload=event.getpayload(); if (payload instanceof SomeEventICareAbout) {....process event....} else if (payload instanceof SomeOtherEventICareAbout) {....process event....} } usually there will be just one type of event you care about so the code is pretty simple.
          Hide
          Martin Grigorov added a comment -

          Thanks for the feedback Sven!

          About #1 I agree that it is better to not keep references to the 'sink' object. As a user of the previous patch in this ticket currently I migrate my app to use "getPage()" as a sink. This is how the patch worked so far. But the new implementation provides a way to make it much more flexible - use 'this' as sink and Broadcast.BUBBLE, then stop the propagation at a given point and send a new event, ... etc.

          My current solution for #2 is related to #1 - use getPage() as sink and send the event to all components. My custom Payload class has a list of whitelist classes and if list is not empty and the current component class (the one that receives onEvent()) is assignable by any of the classes in the white list then the rest of the onEvent body is executed. This is similar to the original patch, just the logic to match the visited component is moved in my Payload class.

          Maybe there are better ways to do that but for now I'm trying to make my application compiling against 1.5 and then running with 1.5 and then I'll probably optimize.

          My current observation is that the generic type of the IEvent is not quite usable. We have to think a bit more at it.

          Show
          Martin Grigorov added a comment - Thanks for the feedback Sven! About #1 I agree that it is better to not keep references to the 'sink' object. As a user of the previous patch in this ticket currently I migrate my app to use "getPage()" as a sink. This is how the patch worked so far. But the new implementation provides a way to make it much more flexible - use 'this' as sink and Broadcast.BUBBLE, then stop the propagation at a given point and send a new event, ... etc. My current solution for #2 is related to #1 - use getPage() as sink and send the event to all components. My custom Payload class has a list of whitelist classes and if list is not empty and the current component class (the one that receives onEvent()) is assignable by any of the classes in the white list then the rest of the onEvent body is executed. This is similar to the original patch, just the logic to match the visited component is moved in my Payload class. Maybe there are better ways to do that but for now I'm trying to make my application compiling against 1.5 and then running with 1.5 and then I'll probably optimize. My current observation is that the generic type of the IEvent is not quite usable. We have to think a bit more at it.
          Hide
          Sven Ludwig added a comment - - edited

          The Interfaces look promising. I have two points for consideration.

          The first point is on the sending side. The sink along with the Broadcast enum value are arguments of the method send, i.e. the sender (a Component, or a Behavior, or some delegate code being responsible for the sending etc.) of an event needs to know into what scope the event is to be broadcasted, and how. Of course, there is for example the combination getPage() and BREADTH, which would be like a truly decoupled solution to broadcast an Event, because the sender knows no one Component in particular, it only knows that it sends the event to any interested receiver within the current Page. But it may get dogy when the sender needs to resolve or even know a particular Component that should be the sink. But I do like the flexibility here.

          The second point is on the receiving side. How does a receiver decide in onEvent whether to do something or not? The implementation of the onEvent method might be able to define the type of event payload that it can process simply within the method signature - if so, onEvent would never be called with a mismatching type of payload. However, if this is not possible, or not supported by the core, or as soon as there are two types of event payloads to be processed in different ways by one onEvent implementation... then the onEvent implementation would have to distinguish between the payloads of received events. How would it do that? The payload may be of a general kind with an enumeration representing its functional meaning... but who wants an enumeration with all functionally possible event meanings... so it would probably be a specific payload type... and this type would have to be checked instanceof-fashion within onEvent. This approach is quite flexible. But in cases where there are only a few interested components among many event-processing components, potentially all of the components would do instanceof-checks of the payload type, which basically might take some processing power away.
          As a performance-optimizing solution for such cases, an additional approach could be offered in which the interested receivers would be registered as event-listeners for events with a specific payload type. Of course there would have to be a registry mechanism with a sensible scoping. The core broadcasting mechanism would then, during the broadcasting of an event, only call onEvent on the registered listeners within the relevant scope. This alternative may be implemented under a dedicated Broadcast enum value LISTENERS_ONLY.

          Show
          Sven Ludwig added a comment - - edited The Interfaces look promising. I have two points for consideration. The first point is on the sending side. The sink along with the Broadcast enum value are arguments of the method send, i.e. the sender (a Component, or a Behavior, or some delegate code being responsible for the sending etc.) of an event needs to know into what scope the event is to be broadcasted, and how. Of course, there is for example the combination getPage() and BREADTH, which would be like a truly decoupled solution to broadcast an Event, because the sender knows no one Component in particular, it only knows that it sends the event to any interested receiver within the current Page. But it may get dogy when the sender needs to resolve or even know a particular Component that should be the sink. But I do like the flexibility here. The second point is on the receiving side. How does a receiver decide in onEvent whether to do something or not? The implementation of the onEvent method might be able to define the type of event payload that it can process simply within the method signature - if so, onEvent would never be called with a mismatching type of payload. However, if this is not possible, or not supported by the core, or as soon as there are two types of event payloads to be processed in different ways by one onEvent implementation... then the onEvent implementation would have to distinguish between the payloads of received events. How would it do that? The payload may be of a general kind with an enumeration representing its functional meaning... but who wants an enumeration with all functionally possible event meanings... so it would probably be a specific payload type... and this type would have to be checked instanceof-fashion within onEvent. This approach is quite flexible. But in cases where there are only a few interested components among many event-processing components, potentially all of the components would do instanceof-checks of the payload type, which basically might take some processing power away. As a performance-optimizing solution for such cases, an additional approach could be offered in which the interested receivers would be registered as event-listeners for events with a specific payload type. Of course there would have to be a registry mechanism with a sensible scoping. The core broadcasting mechanism would then, during the broadcasting of an event, only call onEvent on the registered listeners within the relevant scope. This alternative may be implemented under a dedicated Broadcast enum value LISTENERS_ONLY.
          Igor Vaynberg made changes -
          Fix Version/s 1.5-M2.1 [ 12315331 ]
          Fix Version/s 1.5-M2 [ 12315237 ]
          Hide
          Hudson added a comment -

          Integrated in Apache Wicket 1.5.x #247 (See https://hudson.apache.org/hudson/job/Apache%20Wicket%201.5.x/247/)
          initial inter-component event system implementation
          Issue: WICKET-1312

          Show
          Hudson added a comment - Integrated in Apache Wicket 1.5.x #247 (See https://hudson.apache.org/hudson/job/Apache%20Wicket%201.5.x/247/ ) initial inter-component event system implementation Issue: WICKET-1312
          Igor Vaynberg made changes -
          Status Open [ 1 ] Resolved [ 5 ]
          Resolution Fixed [ 1 ]
          Hide
          Igor Vaynberg added a comment -

          see org.apache.wicket.event package in core and DecoupledAjaxUpdatePage in examples

          Show
          Igor Vaynberg added a comment - see org.apache.wicket.event package in core and DecoupledAjaxUpdatePage in examples
          Igor Vaynberg made changes -
          Assignee Igor Vaynberg [ ivaynberg ]
          Igor Vaynberg made changes -
          Fix Version/s 1.5-M2 [ 12315237 ]
          Fix Version/s 1.5-M1 [ 12313078 ]
          Hide
          Antony Stubbs added a comment -

          We are putting in similar functionality, we should potentially try to combine the two event systems, or at least make them clearly different. (This is Portlet Eventing btw)

          Show
          Antony Stubbs added a comment - We are putting in similar functionality, we should potentially try to combine the two event systems, or at least make them clearly different. (This is Portlet Eventing btw)
          Antony Stubbs made changes -
          Link This issue is part of WICKET-1620 [ WICKET-1620 ]
          Hide
          Martin Grigorov added a comment -

          Hi,

          What do you think about making broadcast method this way:
          broadcast(Event, Class...)

          (now it is broadcast(Class, Event))

          This way it will be possible to send one event to more than one recepients in one pass.

          Of course this will require the same mofication of Component#visitChildren(Class, Visitor) too.

          Show
          Martin Grigorov added a comment - Hi, What do you think about making broadcast method this way: broadcast(Event, Class...) (now it is broadcast(Class, Event)) This way it will be possible to send one event to more than one recepients in one pass. Of course this will require the same mofication of Component#visitChildren(Class, Visitor) too.
          Hide
          lenka laurincikova added a comment - - edited

          Hi Stefan,
          thank you, you are true I am using 1.3. I would expect it is compatible. Or with 1.4 I can use some alternative?
          I am trying to compile classes from event-handler-with-testcase.zip

          regards

          Thank you .. hope I will manage to fix it and use it. because I really need it.

          Show
          lenka laurincikova added a comment - - edited Hi Stefan, thank you, you are true I am using 1.3. I would expect it is compatible. Or with 1.4 I can use some alternative? I am trying to compile classes from event-handler-with-testcase.zip regards Thank you .. hope I will manage to fix it and use it. because I really need it.
          Hide
          Stefan Fussenegger added a comment - - edited

          Not sure which example you talk about, but it seems you are using the wrong Wicket version. I think the example is for Wicket 1.3 and you are using 1.4 (or the other way)

          Edit:
          Okay, now it's clearer. You are using Wicket 1.3 but the example is using 1.4

          Edit#2:
          Okay, now it's even clearer (and sorry for giving bad hints). The example was built against an older developement version of Wicket 1.4 where Page was generic (which it isn't in current RC1 and won't be). Therefore, the example is currently broken. But feel free to fix it (removing the generic type should be sufficient)

          Show
          Stefan Fussenegger added a comment - - edited Not sure which example you talk about, but it seems you are using the wrong Wicket version. I think the example is for Wicket 1.3 and you are using 1.4 (or the other way) Edit: Okay, now it's clearer. You are using Wicket 1.3 but the example is using 1.4 Edit#2: Okay, now it's even clearer (and sorry for giving bad hints). The example was built against an older developement version of Wicket 1.4 where Page was generic (which it isn't in current RC1 and won't be). Therefore, the example is currently broken. But feel free to fix it (removing the generic type should be sufficient)
          Hide
          lenka laurincikova added a comment - - edited

          Hi,

          I have a little problem with compiling of the example. I compile it with java 1.5, so I do not understand why the problem appears.

          however.. in EventHandler.java

          private final Page<?> page; // type org.apache.wicket.Page does not take parameters

          can you please give me a hint?

          thank you in advance

          Show
          lenka laurincikova added a comment - - edited Hi, I have a little problem with compiling of the example. I compile it with java 1.5, so I do not understand why the problem appears. however.. in EventHandler.java private final Page<?> page; // type org.apache.wicket.Page does not take parameters can you please give me a hint? thank you in advance
          Hide
          Uladzimir Liashkevich added a comment -

          I have implemented yet another solution of event mechanism based on Stefan's implementation:
          http://subject-ivity.blogspot.com/2008/11/wicket-ajax-event-updates.html

          Main differences:
          1) Methods annotated with @AjaxEvent are considered as event handlers (with typed parameter).
          2) Component and AjaxRequestTarget instance are passed to "fire" method rather than an event object constructor to allow longer life-time of event.
          3) Unit-testing is supported.

          Examples:

          @AjaxEvent
          protected void onMyEvent(MyEvent event) {
          }

          new MyEvent(parameter).fire(component, ajaxRequestTarget);

          Show
          Uladzimir Liashkevich added a comment - I have implemented yet another solution of event mechanism based on Stefan's implementation: http://subject-ivity.blogspot.com/2008/11/wicket-ajax-event-updates.html Main differences: 1) Methods annotated with @AjaxEvent are considered as event handlers (with typed parameter). 2) Component and AjaxRequestTarget instance are passed to "fire" method rather than an event object constructor to allow longer life-time of event. 3) Unit-testing is supported. Examples: @AjaxEvent protected void onMyEvent(MyEvent event) { } new MyEvent(parameter).fire(component, ajaxRequestTarget);
          Hide
          Stefan Fussenegger added a comment -

          Hi Timo, thanks for your comments.

          1) You're right. But I feel that differentiating between events should be up to the framework users not the framework itself. For instance: you propose an IntegerChangeEvent, I use such things as NewCommentEvents. These are two completely different layers of abstractions that heavily depend on what you try to do with those events in your application. I only want to add components if another component receives an ajax call and maybe add the new comment to the list of comments first. I'm not sure what you use those IntegerChangeEvents for but I am sure you have very valid reasons for them However, both ways of using events may be cut down to one common thing: the event broadcasting mechanism! I feel that this is enough to be included in the framework together with some common events. (Just the way the events are used in the java beans spec: java.util.EventObject as root for all events and common events like PropertyChangeEvent that are often used)

          2) I didn't spend much though on testing yet. But isn't it possible to assume (i.e. test) behavior of the sending end using a specialized receiver? This way, you would just test wheter you received the events you expected and everything should be fine.

          I would really appreciate a final solution that is similar to the usage of events by the java beans spec. There you have one "root event" (java.util.EventObject), some commonly used events (e.g. PropertyChangeEvent) and a naming convention used for introspection. On first look I really, really, really didn't like your use of reflection in you EventBroadcaster. I'd also vote for using a much simpler approach as outlined by Martin above. On second look, I might like an approach that is base on java bean spec's naming convention: to handle a FooEvent one would have to implement the FooEventListener interface with a method 'void fooEvent(FooEvent e)'. I'm currently not sure though whether what I'm saying is completely correct, but it's at least close enough

          Furthermore, I think that we could take the usage of events another step further (Just some raw ideas here, but maybe worth looking at): Maybe we (and some core devs) could brainstorm on another thing: Who is responsible for firing events? This could not only be the user but also the framework itself. This way, one could implement something like the VetoableChangeListeners where you can constrain (or validate) model values by dropping in another component (an event is fired for every model change). I could even imagine, that an event is fired automatically when one component of a page receives an ajax call.

          Show
          Stefan Fussenegger added a comment - Hi Timo, thanks for your comments. 1) You're right. But I feel that differentiating between events should be up to the framework users not the framework itself. For instance: you propose an IntegerChangeEvent, I use such things as NewCommentEvents. These are two completely different layers of abstractions that heavily depend on what you try to do with those events in your application. I only want to add components if another component receives an ajax call and maybe add the new comment to the list of comments first. I'm not sure what you use those IntegerChangeEvents for but I am sure you have very valid reasons for them However, both ways of using events may be cut down to one common thing: the event broadcasting mechanism! I feel that this is enough to be included in the framework together with some common events. (Just the way the events are used in the java beans spec: java.util.EventObject as root for all events and common events like PropertyChangeEvent that are often used) 2) I didn't spend much though on testing yet. But isn't it possible to assume (i.e. test) behavior of the sending end using a specialized receiver? This way, you would just test wheter you received the events you expected and everything should be fine. I would really appreciate a final solution that is similar to the usage of events by the java beans spec. There you have one "root event" (java.util.EventObject), some commonly used events (e.g. PropertyChangeEvent) and a naming convention used for introspection. On first look I really, really, really didn't like your use of reflection in you EventBroadcaster. I'd also vote for using a much simpler approach as outlined by Martin above. On second look, I might like an approach that is base on java bean spec's naming convention: to handle a FooEvent one would have to implement the FooEventListener interface with a method 'void fooEvent(FooEvent e)'. I'm currently not sure though whether what I'm saying is completely correct, but it's at least close enough Furthermore, I think that we could take the usage of events another step further (Just some raw ideas here, but maybe worth looking at): Maybe we (and some core devs) could brainstorm on another thing: Who is responsible for firing events? This could not only be the user but also the framework itself. This way, one could implement something like the VetoableChangeListeners where you can constrain (or validate) model values by dropping in another component (an event is fired for every model change). I could even imagine, that an event is fired automatically when one component of a page receives an ajax call.
          Hide
          Timo Rantalaiho added a comment -

          Hi Martin,

          That's a fair enough question, which already came up on the
          mailing list so I'll just quote myself

          "I wanted to make the code using the framework as clear
          and simple as possible, perhaps with the cost of added
          complexity inside the framework, and separate onEvent()
          methods for different event types feels clearer and more
          elegant to me than the instanceof checks. That way, you
          can see right away from the signature of the component
          class which events it handles. "

          http://www.nabble.com/Generic-event-mechanism-(was%3A-loosely-coupled-panels%3A-react-to-model-object-change)-tt15516909.html#a16072330

          It's too bad that because of erasure, reflection is needed
          to be able to have multiple onEvent() methods for
          different types.

          Show
          Timo Rantalaiho added a comment - Hi Martin, That's a fair enough question, which already came up on the mailing list so I'll just quote myself "I wanted to make the code using the framework as clear and simple as possible, perhaps with the cost of added complexity inside the framework, and separate onEvent() methods for different event types feels clearer and more elegant to me than the instanceof checks. That way, you can see right away from the signature of the component class which events it handles. " http://www.nabble.com/Generic-event-mechanism-(was%3A-loosely-coupled-panels%3A-react-to-model-object-change)-tt15516909.html#a16072330 It's too bad that because of erasure, reflection is needed to be able to have multiple onEvent() methods for different types.
          Hide
          Martin Grigorov added a comment -

          Hi Timo,

          I have a question.
          Why do you decided to use reflection for resolving the onEvent(...) method ?

          Currently the user have to implement onEvent(<T extends Event>) method for every event type.
          For example:
          MyComponent.java:
          ...
          public void onEvent(EventType1 ev1)

          {...}
          public void onEvent(EventType2 ev2) {...}

          What do you think about o.a.w.Component#onEvent(Event) and let the user dispatch the processing of the event.
          Example:
          MyComponent2.java:
          ...
          <code>
          public void onEvent(Event ev) {
          if (ev instanceof EventType1)

          { processType1((EventType1) ev); }

          else if (ev instanceof EventType2)

          { processType2((EventType2) ev); }

          }
          </code>

          Show
          Martin Grigorov added a comment - Hi Timo, I have a question. Why do you decided to use reflection for resolving the onEvent(...) method ? Currently the user have to implement onEvent(<T extends Event>) method for every event type. For example: MyComponent.java: ... public void onEvent(EventType1 ev1) {...} public void onEvent(EventType2 ev2) {...} What do you think about o.a.w.Component#onEvent(Event) and let the user dispatch the processing of the event. Example: MyComponent2.java: ... <code> public void onEvent(Event ev) { if (ev instanceof EventType1) { processType1((EventType1) ev); } else if (ev instanceof EventType2) { processType2((EventType2) ev); } } </code>
          Hide
          Timo Rantalaiho added a comment -

          Nice work, Stefan! It's reassuring to know that you arrived to essentially the same solution.

          Obviously, after a quick look I prefer our original solution but consider me biased. A couple of points that I can come up with based on our more than six months of heavy "broadcaster" usage are

          1) Differentiating between not only different kinds of events but also their listeners by different Java types is very good to have for manageability when you have a lot of events and receivers.

          2) Do you unit test your events (sending / receiving end) and if you do, how? Testing the receiving end seems easy enough, especially as AjaxRequestTarget.addComponent() is not final anymore and can be mocked. But the sending end seems more difficult to me as the Page dependency looks like hard to mock out. I might be missing out something though.

          Keep up the good work!

          Show
          Timo Rantalaiho added a comment - Nice work, Stefan! It's reassuring to know that you arrived to essentially the same solution. Obviously, after a quick look I prefer our original solution but consider me biased. A couple of points that I can come up with based on our more than six months of heavy "broadcaster" usage are 1) Differentiating between not only different kinds of events but also their listeners by different Java types is very good to have for manageability when you have a lot of events and receivers. 2) Do you unit test your events (sending / receiving end) and if you do, how? Testing the receiving end seems easy enough, especially as AjaxRequestTarget.addComponent() is not final anymore and can be mocked. But the sending end seems more difficult to me as the Page dependency looks like hard to mock out. I might be missing out something though. Keep up the good work!
          Hide
          Stefan Fussenegger added a comment -

          I implemented the same idea. Please have a look at my blog (http://talk-on-tech.blogspot.com/2008/09/wicket-loose-coupling-of-componens-for.html). Fortunately, somebody pointed me to this issue.

          I'd say that my approach is somewhat simpler than the current proposal (only one class and one interface). It's less focused on model updates, just passes the source Component and AjaxRequestTarget as event that is passed using an IVisitor to all Components. Yes, very similar, but still a another approach to the problem. We could maybe combine our ideas.

          Best regards, Stefan

          Show
          Stefan Fussenegger added a comment - I implemented the same idea. Please have a look at my blog ( http://talk-on-tech.blogspot.com/2008/09/wicket-loose-coupling-of-componens-for.html ). Fortunately, somebody pointed me to this issue. I'd say that my approach is somewhat simpler than the current proposal (only one class and one interface). It's less focused on model updates, just passes the source Component and AjaxRequestTarget as event that is passed using an IVisitor to all Components. Yes, very similar, but still a another approach to the problem. We could maybe combine our ideas. Best regards, Stefan
          Hide
          Timo Rantalaiho added a comment -

          Peter, thanks for the interesting idea, but surfing in the stack trace is really too much magic at least for my taste! Also checking the method from which the event got fired from (if I got that right) might complicate unit testing.

          Show
          Timo Rantalaiho added a comment - Peter, thanks for the interesting idea, but surfing in the stack trace is really too much magic at least for my taste! Also checking the method from which the event got fired from (if I got that right) might complicate unit testing.
          Timo Rantalaiho made changes -
          Fix Version/s 1.4-M3 [ 12312912 ]
          Fix Version/s 1.5-M1 [ 12313078 ]
          Hide
          Timo Rantalaiho added a comment -

          Nope, 1.5 is the current plan, if 1.4 goes according to the current plan

          Show
          Timo Rantalaiho added a comment - Nope, 1.5 is the current plan, if 1.4 goes according to the current plan
          Hide
          James Carman added a comment -

          Are we going to introduce this stuff in 1.4? I thought 1.4 was all about generification?

          Show
          James Carman added a comment - Are we going to introduce this stuff in 1.4? I thought 1.4 was all about generification?
          Frank Bille Jensen made changes -
          Fix Version/s 1.4-M2 [ 12312911 ]
          Fix Version/s 1.4-M3 [ 12312912 ]
          Peter Ertl made changes -
          Attachment event-handler-with-testcase.zip [ 12382102 ]
          Hide
          Peter Ertl added a comment -

          I really like the idea of having a broadcast mechanism in wicket pages (especially when updating complex ajax related stuff). However, I developed a different style of event handler mechanism. It uses some reflection, still to an acceptable degree I believe, but maybe you still like it.

          If you consider it valuable enough you could include it in org.apache.wicket.util.

          I uploaded that thing including some really stupid and useless example lol

          hope you like it!

          Show
          Peter Ertl added a comment - I really like the idea of having a broadcast mechanism in wicket pages (especially when updating complex ajax related stuff). However, I developed a different style of event handler mechanism. It uses some reflection, still to an acceptable degree I believe, but maybe you still like it. If you consider it valuable enough you could include it in org.apache.wicket.util. I uploaded that thing including some really stupid and useless example lol hope you like it!
          Frank Bille Jensen made changes -
          Fix Version/s 1.4-M1 [ 12312523 ]
          Fix Version/s 1.4-M2 [ 12312911 ]
          Timo Rantalaiho made changes -
          Hide
          Timo Rantalaiho added a comment -

          Better version where

          • the EventBroadcaster instance is being held by Application
          • custom EventBroadcaster can be supplied by overriding protected EventBroadcaster Application.newEventBroadcaster()
          • EventBroadcaster in use can be change by Application.get().setEventBroadcaster(anotherBroadcaster) to e.g. supply mock broadcaster in tests
          Show
          Timo Rantalaiho added a comment - Better version where the EventBroadcaster instance is being held by Application custom EventBroadcaster can be supplied by overriding protected EventBroadcaster Application.newEventBroadcaster() EventBroadcaster in use can be change by Application.get().setEventBroadcaster(anotherBroadcaster) to e.g. supply mock broadcaster in tests
          Timo Rantalaiho made changes -
          Attachment Generic_EventBroadcaster_glued_in_Component.patch [ 12375780 ]
          Hide
          Matthijs Wensveen added a comment -

          This would indeed be great to have in a 1.3.x release!

          Show
          Matthijs Wensveen added a comment - This would indeed be great to have in a 1.3.x release!
          Hide
          Edward Yakop added a comment -

          This is a great patch.

          This would enable a more elegant way to handle AjaxRequestTarget#addComponent.
          If possible, please make this feature available for the next wicket 1.3.2 release.

          Show
          Edward Yakop added a comment - This is a great patch. This would enable a more elegant way to handle AjaxRequestTarget#addComponent. If possible, please make this feature available for the next wicket 1.3.2 release.
          Timo Rantalaiho made changes -
          Attachment Generic_EventBroadcaster_glued_in_Component.patch [ 12375780 ]
          Hide
          Timo Rantalaiho added a comment -

          This patch (Generic_EventBroadcaster_glued_in_Component.patch) adds the method public void broadcast(Class receiverType, Event event) directly to Component, along the lines suggested by Pekka Enberg (thanks!). Thus the event package is also moved from wicket-extensions to main wicket module.

          EventBroadcaster is now also made a non-enforced / pluggable singleton. There must be an easy way to intercept and inspect the event broadcasting in unit tests. This solution provides it in a very straight forward, if not eloquent, way.

          Against revision 628453 (Sun Feb 17 2008).

          Show
          Timo Rantalaiho added a comment - This patch (Generic_EventBroadcaster_glued_in_Component.patch) adds the method public void broadcast(Class receiverType, Event event) directly to Component, along the lines suggested by Pekka Enberg (thanks!). Thus the event package is also moved from wicket-extensions to main wicket module. EventBroadcaster is now also made a non-enforced / pluggable singleton. There must be an easy way to intercept and inspect the event broadcasting in unit tests. This solution provides it in a very straight forward, if not eloquent, way. Against revision 628453 (Sun Feb 17 2008).
          Timo Rantalaiho made changes -
          Attachment Generic_EventBroadcaster.patch [ 12374271 ]
          Timo Rantalaiho made changes -
          Attachment Generic_EventBroadcaster.patch [ 12375765 ]
          Hide
          Timo Rantalaiho added a comment -

          Freshers version that also handles the Page itself if it implements the required receiver interface

          Show
          Timo Rantalaiho added a comment - Freshers version that also handles the Page itself if it implements the required receiver interface
          Hide
          Timo Rantalaiho added a comment -

          Thanks for the improvement, Matt! That should be easy enough to add, easiest way probably by making the event handler method to return something like the CONTINUE_TRAVERSAL / STOP TRAVERSAL of IVisitor.

          In our software, we have used very specialised event types, and then the children would typically not directly receive the event at all in the scenario you describe. The children can anyway receive other types of events.

          Show
          Timo Rantalaiho added a comment - Thanks for the improvement, Matt! That should be easy enough to add, easiest way probably by making the event handler method to return something like the CONTINUE_TRAVERSAL / STOP TRAVERSAL of IVisitor. In our software, we have used very specialised event types, and then the children would typically not directly receive the event at all in the scenario you describe. The children can anyway receive other types of events.
          Hide
          Matt Clark added a comment -

          Timo - Great patch. We have done something similar in our app (http://www.nabble.com/Updating-distant-%28unrelated%29-components-via-Ajax-when-a-shared-model-changes-to13165777.html#a13165777), although I like your approach better.

          The one suggestion I would make is that you allow the event receivers to signal that traversal should not go deeper. This became important in our use case because you would have a parent add itself to the target, and then the child would add itself. When the parent re-rendered the child was removed from the page hierarchy, and by the time it got to render the child it was no longer part of the page. If the parent knows that it is going to completely re-compose its descendant hierarchy, then it can signal to the event broadcaster to stop traversala t that point. I hope that was a clear enough description.

          Show
          Matt Clark added a comment - Timo - Great patch. We have done something similar in our app ( http://www.nabble.com/Updating-distant-%28unrelated%29-components-via-Ajax-when-a-shared-model-changes-to13165777.html#a13165777 ), although I like your approach better. The one suggestion I would make is that you allow the event receivers to signal that traversal should not go deeper. This became important in our use case because you would have a parent add itself to the target, and then the child would add itself. When the parent re-rendered the child was removed from the page hierarchy, and by the time it got to render the child it was no longer part of the page. If the parent knows that it is going to completely re-compose its descendant hierarchy, then it can signal to the event broadcaster to stop traversala t that point. I hope that was a clear enough description.
          Igor Vaynberg made changes -
          Fix Version/s 1.4-M1 [ 12312523 ]
          Timo Rantalaiho made changes -
          Field Original Value New Value
          Attachment Generic_EventBroadcaster.patch [ 12374271 ]
          Hide
          Timo Rantalaiho added a comment -

          Against revision 616446 (Tue Jan 29th 2008)

          Show
          Timo Rantalaiho added a comment - Against revision 616446 (Tue Jan 29th 2008)
          Timo Rantalaiho created issue -

            People

            • Assignee:
              Igor Vaynberg
              Reporter:
              Timo Rantalaiho
            • Votes:
              15 Vote for this issue
              Watchers:
              16 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Development