[xwiki-devs] New Observation component: Usage scenarios
Hi, How do you feel about the next usage scenarios for the observation component? A. Simple observing of changes This is the most common usage of the old notification mechanism. It allows a listener to see when something gets changed. It receives as the source the changed document, from which it can get the original document (there's a doc.getOriginalDocument() method for this). For the moment, the data argument is the context, as it is still a vital object for most of the code, and it has to be passed around all the time. The event will hold the type of change, like adding a new document, deleting, or just saving a new version. In the future I'd like to increase the granularity, to make this "change" a set of basic changes, to be able to say that (object added, attachment removed, content changed) is what happened to the document (see http://jira.xwiki.org/jira/browse/XE-213 too). With this event, a listener can then update some data indexer, like the Lucene plugin does, or send the new documents/attachments to a repository, or send a mail with the new code, or ping on IRC. B. Simple observing of actions This is also implemented in the old notification mechanism. It allows a listener to monitor actions. It receives as the source the affected document, and as the additional data the same context, as it is needed. The event holds the action name, and I'd like to add the full URL, too, as other important information might be in there. I don't know if sending the complete request object is a good idea, but I think we should be able to obtain it somehow. With this event, a listener can update some statistics, refresh some caches or cleanup some indexes, send an attachment to another repository (like SVN), or, based on the URL, it can be used to take some action, like if the action was "createspace" and the "notify=admins" parameter was given in the request, then the observer can send the notifications, without polluting the application code with the checks and mail sending calls. C. Precondition/Postcondition enforcing The previous two use cases allow a simple ping that something has already happened. (Actually, the listeners can also change the passed document, as the actual object is sent.) But I'd like to be able to write a listener that can say "this is not allowed, please stop this action", or "these changes are not OK, don't save this document". So, a precondition can be that "/save/" cannot be performed between 6PM and 7AM, which would be a needed feature in some companies, or that "/view/" cannot be performed on the "SectionA" space from the IP addresses like 192.168.2.*, which belongs to the SectionB users (these are action events). And a postcondition can be that the XWiki.XWikiPreferences can only be updated by changing XWikiGlobalRights objects, other types of changes can only be performed by a superadmin only, or that adding some content that looks like spam is not allowed (these are document events). So, on top of the previous use cases, I'd like to add a "phase" to the events, which indicates if the event is sent before or after the change (or we can just add new events), and a new type of exception thrown by the listeners, which is not ignored. Right now, if a listener throws an exception, it is ignored. This exception, when received by the code that sends the notification, should stop the normal processing and display "action not allowed" + ex.getMessage to the user. D. Rendering hooks While working on the SkinExtensions and trying to write a better #toc macro, I was faced with the problem that there's no way a plugin can change the rendered content at the end. Yes, it can alter it line by line, and in theory there is an endRenderingHook sent with the content, but that is actually buggy, as an empty string is sent instead of the content, and the result is discarded. Still, even if fixed, this is sent only for *rendered* content, not *parsed* content. My initial idea was to change the PluginInterface by adding two new methods that will be called before and after the content was generated, but that is a bad idea, since the PluginInterface is already too big and has too many types of methods. And since the new rendering component is not yet available, I thought that we can also use events for this. So, instead of writing new methods in the PluginInterface, we can add other type of events, which gets sent in the parsing/rendering process. That way, we don't need to have a plugin that implements all these methods, and adding a new feature will require just sending a new type of event, instead of changing an interface (which is dangerous). The source would be an object holding the string, which can be modified by the listeners. Other information could be the content document, if there is one, the rendering/parsing context, anything else? E. Other generic events Like FlushCacheEvent, StartupEvent, ShutdownEvent, VirtualInitEvent, VirtualShutdownEvent (sent when a wiki is deleted by the WikiManagerEvent), Application[Added/Enabled/Disabled/Removed]Event (sent by the ApplicationManager), Space[Added/Removed]Event (sent by the SpaceManagerPlugin), etc. Comments, please? -- Sergiu Dumitriu http://purl.org/net/sergiu/
Sorry about proposing my ideas here but they are linked to the observation component. In my current studies, I have some needs but I can't say I know the architecture in details yet. I need a component allowing to add some behaviours in the lifecycle of group of documents without modifying or adding too much code... For example, in a space, I would like all documents to pass through a kind of filter modifying the content according to some rules when some events happen or to be intercepted according to some custom security rules etc... I have seen the notification mechanism which is not quite satisfying and then the future observation component which should replace the notifications and which seems more interesting to me. To summarize, I would need something allowing: - to add intercepting and filtering features in the document lifecycle - to create event listeners on known events - to manage these behaviours with some simple rules' mechanism - to add some custom behaviours on custom pointcuts like in AOP... I like this idea... AOP as a way to build document or space's templates or behaviors... An aspect oriented wiki if you want:) without needing to code and compile too much... What do you think about that? Is it already possible? Could the observation component be a good beginning for that? regards Pascal On Sat, Mar 15, 2008 at 8:11 AM, Sergiu Dumitriu <[email protected]> wrote:
Hi,
How do you feel about the next usage scenarios for the observation component?
A. Simple observing of changes This is the most common usage of the old notification mechanism. It allows a listener to see when something gets changed. It receives as the source the changed document, from which it can get the original document (there's a doc.getOriginalDocument() method for this). For the moment, the data argument is the context, as it is still a vital object for most of the code, and it has to be passed around all the time.
The event will hold the type of change, like adding a new document, deleting, or just saving a new version. In the future I'd like to increase the granularity, to make this "change" a set of basic changes, to be able to say that (object added, attachment removed, content changed) is what happened to the document (see http://jira.xwiki.org/jira/browse/XE-213 too).
With this event, a listener can then update some data indexer, like the Lucene plugin does, or send the new documents/attachments to a repository, or send a mail with the new code, or ping on IRC.
B. Simple observing of actions This is also implemented in the old notification mechanism. It allows a listener to monitor actions. It receives as the source the affected document, and as the additional data the same context, as it is needed.
The event holds the action name, and I'd like to add the full URL, too, as other important information might be in there. I don't know if sending the complete request object is a good idea, but I think we should be able to obtain it somehow.
With this event, a listener can update some statistics, refresh some caches or cleanup some indexes, send an attachment to another repository (like SVN), or, based on the URL, it can be used to take some action, like if the action was "createspace" and the "notify=admins" parameter was given in the request, then the observer can send the notifications, without polluting the application code with the checks and mail sending calls.
C. Precondition/Postcondition enforcing The previous two use cases allow a simple ping that something has already happened. (Actually, the listeners can also change the passed document, as the actual object is sent.) But I'd like to be able to write a listener that can say "this is not allowed, please stop this action", or "these changes are not OK, don't save this document". So, a precondition can be that "/save/" cannot be performed between 6PM and 7AM, which would be a needed feature in some companies, or that "/view/" cannot be performed on the "SectionA" space from the IP addresses like 192.168.2.*, which belongs to the SectionB users (these are action events). And a postcondition can be that the XWiki.XWikiPreferences can only be updated by changing XWikiGlobalRights objects, other types of changes can only be performed by a superadmin only, or that adding some content that looks like spam is not allowed (these are document events).
So, on top of the previous use cases, I'd like to add a "phase" to the events, which indicates if the event is sent before or after the change (or we can just add new events), and a new type of exception thrown by the listeners, which is not ignored. Right now, if a listener throws an exception, it is ignored. This exception, when received by the code that sends the notification, should stop the normal processing and display "action not allowed" + ex.getMessage to the user.
D. Rendering hooks While working on the SkinExtensions and trying to write a better #toc macro, I was faced with the problem that there's no way a plugin can change the rendered content at the end. Yes, it can alter it line by line, and in theory there is an endRenderingHook sent with the content, but that is actually buggy, as an empty string is sent instead of the content, and the result is discarded. Still, even if fixed, this is sent only for *rendered* content, not *parsed* content. My initial idea was to change the PluginInterface by adding two new methods that will be called before and after the content was generated, but that is a bad idea, since the PluginInterface is already too big and has too many types of methods. And since the new rendering component is not yet available, I thought that we can also use events for this.
So, instead of writing new methods in the PluginInterface, we can add other type of events, which gets sent in the parsing/rendering process. That way, we don't need to have a plugin that implements all these methods, and adding a new feature will require just sending a new type of event, instead of changing an interface (which is dangerous).
The source would be an object holding the string, which can be modified by the listeners. Other information could be the content document, if there is one, the rendering/parsing context, anything else?
E. Other generic events Like FlushCacheEvent, StartupEvent, ShutdownEvent, VirtualInitEvent, VirtualShutdownEvent (sent when a wiki is deleted by the WikiManagerEvent), Application[Added/Enabled/Disabled/Removed]Event (sent by the ApplicationManager), Space[Added/Removed]Event (sent by the SpaceManagerPlugin), etc.
Comments, please? -- Sergiu Dumitriu http://purl.org/net/sergiu/ _______________________________________________ devs mailing list [email protected] http://lists.xwiki.org/mailman/listinfo/devs
Hi Sergiu, On Mar 15, 2008, at 8:11 AM, Sergiu Dumitriu wrote:
Hi,
How do you feel about the next usage scenarios for the observation component?
A. Simple observing of changes
[snip]
B. Simple observing of actions
[snip]
C. Precondition/Postcondition enforcing The previous two use cases allow a simple ping that something has already happened. (Actually, the listeners can also change the passed document, as the actual object is sent.) But I'd like to be able to write a listener that can say "this is not allowed, please stop this action", or "these changes are not OK, don't save this document". So, a precondition can be that "/save/" cannot be performed between 6PM and 7AM, which would be a needed feature in some companies, or that "/ view/" cannot be performed on the "SectionA" space from the IP addresses like 192.168.2.*, which belongs to the SectionB users (these are action events). And a postcondition can be that the XWiki.XWikiPreferences can only be updated by changing XWikiGlobalRights objects, other types of changes can only be performed by a superadmin only, or that adding some content that looks like spam is not allowed (these are document events).
So, on top of the previous use cases, I'd like to add a "phase" to the events, which indicates if the event is sent before or after the change (or we can just add new events), and a new type of exception thrown by the listeners, which is not ignored. Right now, if a listener throws an exception, it is ignored. This exception, when received by the code that sends the notification, should stop the normal processing and display "action not allowed" + ex.getMessage to the user.
My first reaction is that I'm not really fan of this approach. The way I had planned to implement this in the V2.0 architecture is by either: 1) replacing existing component with a different implementation. This is when the current behavior need to be modified/replaced by another one. 2) depending on the component, introduce new component. For example the Action Manager in the new action component allows defining new Actions that can be inserted before or after existing actions (or even replace existing actions but that's 1)). To summarize, I would agree with your idea except that with components there's another way of doing it and I don't think we should have too many ways. If you think about how you'd implement your idea you'll end up creating a state machine component to which actions are hooked to. This is what the Action Manager component is meant to do, although for the moment I have resisted introducing a FSM since I wanted to see the exact need first and with 1) and 2) I thought we could already do quite a lot (not sure what we cannot do to be honest).
D. Rendering hooks While working on the SkinExtensions and trying to write a better #toc macro, I was faced with the problem that there's no way a plugin can change the rendered content at the end. Yes, it can alter it line by line, and in theory there is an endRenderingHook sent with the content, but that is actually buggy, as an empty string is sent instead of the content, and the result is discarded. Still, even if fixed, this is sent only for *rendered* content, not *parsed* content. My initial idea was to change the PluginInterface by adding two new methods that will be called before and after the content was generated, but that is a bad idea, since the PluginInterface is already too big and has too many types of methods. And since the new rendering component is not yet available, I thought that we can also use events for this.
So, instead of writing new methods in the PluginInterface, we can add other type of events, which gets sent in the parsing/rendering process. That way, we don't need to have a plugin that implements all these methods, and adding a new feature will require just sending a new type of event, instead of changing an interface (which is dangerous).
The source would be an object holding the string, which can be modified by the listeners. Other information could be the content document, if there is one, the rendering/parsing context, anything else?
Again my first reaction is that I'm no fan... :) The reason is that I have this implemented in the new rendering component. First any piece of code can get the parsed content of a text having any kind of syntax (Element Blocks or DOM). Second, it's possible to write any Macro that will manipulate this DOM and make any modification to it. This is how the Toc Macro is going to be rewritten actually. However you're right in that right now all I have planned for are Macros and these are triggered by the macro syntax in the text to parse/rendering. So it's a good idea to add a small FSM in the rendering component since we already need an order in the macro execution but also to add the ability to register macros to be executed regardless of whether they appear in the parsed text or not.
E. Other generic events Like FlushCacheEvent, StartupEvent, ShutdownEvent, VirtualInitEvent, VirtualShutdownEvent (sent when a wiki is deleted by the WikiManagerEvent), Application[Added/Enabled/Disabled/Removed]Event (sent by the ApplicationManager), Space[Added/Removed]Event (sent by the SpaceManagerPlugin), etc.
+1 to those. Thanks -Vincent
Vincent Massol wrote:
Hi Sergiu,
On Mar 15, 2008, at 8:11 AM, Sergiu Dumitriu wrote:
Hi,
How do you feel about the next usage scenarios for the observation component?
A. Simple observing of changes
[snip]
B. Simple observing of actions
[snip]
C. Precondition/Postcondition enforcing The previous two use cases allow a simple ping that something has already happened. (Actually, the listeners can also change the passed document, as the actual object is sent.) But I'd like to be able to write a listener that can say "this is not allowed, please stop this action", or "these changes are not OK, don't save this document". So, a precondition can be that "/save/" cannot be performed between 6PM and 7AM, which would be a needed feature in some companies, or that "/ view/" cannot be performed on the "SectionA" space from the IP addresses like 192.168.2.*, which belongs to the SectionB users (these are action events). And a postcondition can be that the XWiki.XWikiPreferences can only be updated by changing XWikiGlobalRights objects, other types of changes can only be performed by a superadmin only, or that adding some content that looks like spam is not allowed (these are document events).
So, on top of the previous use cases, I'd like to add a "phase" to the events, which indicates if the event is sent before or after the change (or we can just add new events), and a new type of exception thrown by the listeners, which is not ignored. Right now, if a listener throws an exception, it is ignored. This exception, when received by the code that sends the notification, should stop the normal processing and display "action not allowed" + ex.getMessage to the user.
My first reaction is that I'm not really fan of this approach. The way I had planned to implement this in the V2.0 architecture is by either:
1) replacing existing component with a different implementation. This is when the current behavior need to be modified/replaced by another one. 2) depending on the component, introduce new component. For example the Action Manager in the new action component allows defining new Actions that can be inserted before or after existing actions (or even replace existing actions but that's 1)).
To summarize, I would agree with your idea except that with components there's another way of doing it and I don't think we should have too many ways. If you think about how you'd implement your idea you'll end up creating a state machine component to which actions are hooked to. This is what the Action Manager component is meant to do, although for the moment I have resisted introducing a FSM since I wanted to see the exact need first and with 1) and 2) I thought we could already do quite a lot (not sure what we cannot do to be honest).
This allows introducing/changing ONE new functionality, by completely replacing a whole component, but it isn't flexible enough IMHO. Using events also allows: - chaining several completely different "behaviors" - writing one listener for all the actions, instead of replacing several Actions just to introduce a check - defining a behavior as a Groovy script placed inside a document, so adding a new -- let's say -- security feature will not require writing a component, packaged as a jar, but just installing a wiki application, controllable from the wiki, like the IRC bot. I don't see a need for a FSM, as the place where these events should be sent are already clear, and the old notification already sends pre- and post-notifications, just that all the errors are ignored.
D. Rendering hooks While working on the SkinExtensions and trying to write a better #toc macro, I was faced with the problem that there's no way a plugin can change the rendered content at the end. Yes, it can alter it line by line, and in theory there is an endRenderingHook sent with the content, but that is actually buggy, as an empty string is sent instead of the content, and the result is discarded. Still, even if fixed, this is sent only for *rendered* content, not *parsed* content. My initial idea was to change the PluginInterface by adding two new methods that will be called before and after the content was generated, but that is a bad idea, since the PluginInterface is already too big and has too many types of methods. And since the new rendering component is not yet available, I thought that we can also use events for this.
So, instead of writing new methods in the PluginInterface, we can add other type of events, which gets sent in the parsing/rendering process. That way, we don't need to have a plugin that implements all these methods, and adding a new feature will require just sending a new type of event, instead of changing an interface (which is dangerous).
The source would be an object holding the string, which can be modified by the listeners. Other information could be the content document, if there is one, the rendering/parsing context, anything else?
Again my first reaction is that I'm no fan... :) The reason is that I have this implemented in the new rendering component. First any piece of code can get the parsed content of a text having any kind of syntax (Element Blocks or DOM). Second, it's possible to write any Macro that will manipulate this DOM and make any modification to it. This is how the Toc Macro is going to be rewritten actually.
However you're right in that right now all I have planned for are Macros and these are triggered by the macro syntax in the text to parse/rendering. So it's a good idea to add a small FSM in the rendering component since we already need an order in the macro execution but also to add the ability to register macros to be executed regardless of whether they appear in the parsed text or not.
At first I thought that the new rendering part would be enough, but then I realized that in order for some code to be executed, it must exist in the source, as a macro or something. Then I thought that we can make several tree walkers that are executed, instead of one that transforms the tree into XHTML, or PDF, or RSS, or a different wiki markup, or whatever, but I'm not sure this is a good idea, either. I don't like the events approach for this (especially the fact that the event is used for passing data around), but for the moment it seemed a simpler approach while waiting for the rendering engine.
E. Other generic events Like FlushCacheEvent, StartupEvent, ShutdownEvent, VirtualInitEvent, VirtualShutdownEvent (sent when a wiki is deleted by the WikiManagerEvent), Application[Added/Enabled/Disabled/Removed]Event (sent by the ApplicationManager), Space[Added/Removed]Event (sent by the SpaceManagerPlugin), etc.
+1 to those.
Thanks -Vincent
_______________________________________________ devs mailing list [email protected] http://lists.xwiki.org/mailman/listinfo/devs
-- Sergiu Dumitriu http://purl.org/net/sergiu/
On Mar 17, 2008, at 6:38 PM, Sergiu Dumitriu wrote: [snip]
C. Precondition/Postcondition enforcing The previous two use cases allow a simple ping that something has already happened. (Actually, the listeners can also change the passed document, as the actual object is sent.) But I'd like to be able to write a listener that can say "this is not allowed, please stop this action", or "these changes are not OK, don't save this document". So, a precondition can be that "/save/" cannot be performed between 6PM and 7AM, which would be a needed feature in some companies, or that "/ view/" cannot be performed on the "SectionA" space from the IP addresses like 192.168.2.*, which belongs to the SectionB users (these are action events). And a postcondition can be that the XWiki.XWikiPreferences can only be updated by changing XWikiGlobalRights objects, other types of changes can only be performed by a superadmin only, or that adding some content that looks like spam is not allowed (these are document events).
So, on top of the previous use cases, I'd like to add a "phase" to the events, which indicates if the event is sent before or after the change (or we can just add new events), and a new type of exception thrown by the listeners, which is not ignored. Right now, if a listener throws an exception, it is ignored. This exception, when received by the code that sends the notification, should stop the normal processing and display "action not allowed" + ex.getMessage to the user.
My first reaction is that I'm not really fan of this approach. The way I had planned to implement this in the V2.0 architecture is by either:
1) replacing existing component with a different implementation. This is when the current behavior need to be modified/replaced by another one. 2) depending on the component, introduce new component. For example the Action Manager in the new action component allows defining new Actions that can be inserted before or after existing actions (or even replace existing actions but that's 1)).
To summarize, I would agree with your idea except that with components there's another way of doing it and I don't think we should have too many ways. If you think about how you'd implement your idea you'll end up creating a state machine component to which actions are hooked to. This is what the Action Manager component is meant to do, although for the moment I have resisted introducing a FSM since I wanted to see the exact need first and with 1) and 2) I thought we could already do quite a lot (not sure what we cannot do to be honest).
This allows introducing/changing ONE new functionality, by completely replacing a whole component, but it isn't flexible enough IMHO.
No, it also allows adding actions before/after existing actions.
Using events also allows: - chaining several completely different "behaviors"
This is supported in the Action component architecture since you can introduce Actions and tell where you're introducing them in the chain of actions.
- writing one listener for all the actions, instead of replacing several Actions just to introduce a check
I don't see why we would need to replace several actions to introduce a check. You'd simply create an Action on the same mapping and make it execute before the "main" actions for that mapping.
- defining a behavior as a Groovy script placed inside a document, so adding a new -- let's say -- security feature will not require writing a component, packaged as a jar, but just installing a wiki application, controllable from the wiki, like the IRC bot.
This is supported too. You just need to write a Groovy class that implements Action and register it against the component manager. The same apply for everything. Said differently it'll be possible to modify any behavior from groovy if we want.
I don't see a need for a FSM, as the place where these events should be sent are already clear, and the old notification already sends pre- and post-notifications, just that all the errors are ignored.
D. Rendering hooks While working on the SkinExtensions and trying to write a better #toc macro, I was faced with the problem that there's no way a plugin can change the rendered content at the end. Yes, it can alter it line by line, and in theory there is an endRenderingHook sent with the content, but that is actually buggy, as an empty string is sent instead of the content, and the result is discarded. Still, even if fixed, this is sent only for *rendered* content, not *parsed* content. My initial idea was to change the PluginInterface by adding two new methods that will be called before and after the content was generated, but that is a bad idea, since the PluginInterface is already too big and has too many types of methods. And since the new rendering component is not yet available, I thought that we can also use events for this.
So, instead of writing new methods in the PluginInterface, we can add other type of events, which gets sent in the parsing/rendering process. That way, we don't need to have a plugin that implements all these methods, and adding a new feature will require just sending a new type of event, instead of changing an interface (which is dangerous).
The source would be an object holding the string, which can be modified by the listeners. Other information could be the content document, if there is one, the rendering/parsing context, anything else?
Again my first reaction is that I'm no fan... :) The reason is that I have this implemented in the new rendering component. First any piece of code can get the parsed content of a text having any kind of syntax (Element Blocks or DOM). Second, it's possible to write any Macro that will manipulate this DOM and make any modification to it. This is how the Toc Macro is going to be rewritten actually.
However you're right in that right now all I have planned for are Macros and these are triggered by the macro syntax in the text to parse/rendering. So it's a good idea to add a small FSM in the rendering component since we already need an order in the macro execution but also to add the ability to register macros to be executed regardless of whether they appear in the parsed text or not.
At first I thought that the new rendering part would be enough, but then I realized that in order for some code to be executed, it must exist in the source, as a macro or something.
Then I thought that we can make several tree walkers that are executed, instead of one that transforms the tree into XHTML, or PDF, or RSS, or a different wiki markup, or whatever, but I'm not sure this is a good idea, either.
I don't like the events approach for this (especially the fact that the event is used for passing data around), but for the moment it seemed a simpler approach while waiting for the rendering engine.
I'm not sure why we need to spend time on this while waiting for the rendering engine. As you know I'm actively working on it. Is there something urgent? :) In general I'm not too much in favor of tweaking the observation mechanism to introduce the ability to replace/pre-execute/post-execute code. Not sure why this is just a gut feeling for now. I think we need to discuss it on a use case by use case basis. I don't see the need for Actions and Rendering since these use case are already supported IMO. Thanks -Vincent
E. Other generic events Like FlushCacheEvent, StartupEvent, ShutdownEvent, VirtualInitEvent, VirtualShutdownEvent (sent when a wiki is deleted by the WikiManagerEvent), Application[Added/Enabled/Disabled/Removed]Event (sent by the ApplicationManager), Space[Added/Removed]Event (sent by the SpaceManagerPlugin), etc.
+1 to those.
Thanks -Vincent
Vincent Massol wrote:
On Mar 17, 2008, at 6:38 PM, Sergiu Dumitriu wrote:
[snip]
C. Precondition/Postcondition enforcing The previous two use cases allow a simple ping that something has already happened. (Actually, the listeners can also change the passed document, as the actual object is sent.) But I'd like to be able to write a listener that can say "this is not allowed, please stop this action", or "these changes are not OK, don't save this document". So, a precondition can be that "/save/" cannot be performed between 6PM and 7AM, which would be a needed feature in some companies, or that "/ view/" cannot be performed on the "SectionA" space from the IP addresses like 192.168.2.*, which belongs to the SectionB users (these are action events). And a postcondition can be that the XWiki.XWikiPreferences can only be updated by changing XWikiGlobalRights objects, other types of changes can only be performed by a superadmin only, or that adding some content that looks like spam is not allowed (these are document events).
So, on top of the previous use cases, I'd like to add a "phase" to the events, which indicates if the event is sent before or after the change (or we can just add new events), and a new type of exception thrown by the listeners, which is not ignored. Right now, if a listener throws an exception, it is ignored. This exception, when received by the code that sends the notification, should stop the normal processing and display "action not allowed" + ex.getMessage to the user. My first reaction is that I'm not really fan of this approach. The way I had planned to implement this in the V2.0 architecture is by either:
1) replacing existing component with a different implementation. This is when the current behavior need to be modified/replaced by another one. 2) depending on the component, introduce new component. For example the Action Manager in the new action component allows defining new Actions that can be inserted before or after existing actions (or even replace existing actions but that's 1)).
To summarize, I would agree with your idea except that with components there's another way of doing it and I don't think we should have too many ways. If you think about how you'd implement your idea you'll end up creating a state machine component to which actions are hooked to. This is what the Action Manager component is meant to do, although for the moment I have resisted introducing a FSM since I wanted to see the exact need first and with 1) and 2) I thought we could already do quite a lot (not sure what we cannot do to be honest). This allows introducing/changing ONE new functionality, by completely replacing a whole component, but it isn't flexible enough IMHO.
No, it also allows adding actions before/after existing actions.
Using events also allows: - chaining several completely different "behaviors"
This is supported in the Action component architecture since you can introduce Actions and tell where you're introducing them in the chain of actions.
My mistake, I thought we were speaking of Struts Actions, but that's not the case, right? We should talk a bit about Actions and the Action Manager...
- writing one listener for all the actions, instead of replacing several Actions just to introduce a check
I don't see why we would need to replace several actions to introduce a check. You'd simply create an Action on the same mapping and make it execute before the "main" actions for that mapping.
- defining a behavior as a Groovy script placed inside a document, so adding a new -- let's say -- security feature will not require writing a component, packaged as a jar, but just installing a wiki application, controllable from the wiki, like the IRC bot.
This is supported too. You just need to write a Groovy class that implements Action and register it against the component manager. The same apply for everything. Said differently it'll be possible to modify any behavior from groovy if we want.
I don't see a need for a FSM, as the place where these events should be sent are already clear, and the old notification already sends pre- and post-notifications, just that all the errors are ignored.
D. Rendering hooks While working on the SkinExtensions and trying to write a better #toc macro, I was faced with the problem that there's no way a plugin can change the rendered content at the end. Yes, it can alter it line by line, and in theory there is an endRenderingHook sent with the content, but that is actually buggy, as an empty string is sent instead of the content, and the result is discarded. Still, even if fixed, this is sent only for *rendered* content, not *parsed* content. My initial idea was to change the PluginInterface by adding two new methods that will be called before and after the content was generated, but that is a bad idea, since the PluginInterface is already too big and has too many types of methods. And since the new rendering component is not yet available, I thought that we can also use events for this.
So, instead of writing new methods in the PluginInterface, we can add other type of events, which gets sent in the parsing/rendering process. That way, we don't need to have a plugin that implements all these methods, and adding a new feature will require just sending a new type of event, instead of changing an interface (which is dangerous).
The source would be an object holding the string, which can be modified by the listeners. Other information could be the content document, if there is one, the rendering/parsing context, anything else? Again my first reaction is that I'm no fan... :) The reason is that I have this implemented in the new rendering component. First any piece of code can get the parsed content of a text having any kind of syntax (Element Blocks or DOM). Second, it's possible to write any Macro that will manipulate this DOM and make any modification to it. This is how the Toc Macro is going to be rewritten actually.
However you're right in that right now all I have planned for are Macros and these are triggered by the macro syntax in the text to parse/rendering. So it's a good idea to add a small FSM in the rendering component since we already need an order in the macro execution but also to add the ability to register macros to be executed regardless of whether they appear in the parsed text or not. At first I thought that the new rendering part would be enough, but then I realized that in order for some code to be executed, it must exist in the source, as a macro or something.
Then I thought that we can make several tree walkers that are executed, instead of one that transforms the tree into XHTML, or PDF, or RSS, or a different wiki markup, or whatever, but I'm not sure this is a good idea, either.
I don't like the events approach for this (especially the fact that the event is used for passing data around), but for the moment it seemed a simpler approach while waiting for the rendering engine.
I'm not sure why we need to spend time on this while waiting for the rendering engine. As you know I'm actively working on it.
Is there something urgent? :)
In general I'm not too much in favor of tweaking the observation mechanism to introduce the ability to replace/pre-execute/post-execute code. Not sure why this is just a gut feeling for now. I think we need to discuss it on a use case by use case basis. I don't see the need for Actions and Rendering since these use case are already supported IMO.
-- Sergiu Dumitriu http://purl.org/net/sergiu/
participants (3)
-
Pascal Voitot -
Sergiu Dumitriu -
Vincent Massol