Ticket #261 (closed Enhancement: fixed)
Redesign server-side hook mechanism
Reported by: | jri | Owned by: | jri |
---|---|---|---|
Priority: | Major | Milestone: | Release 4.1 |
Component: | DeepaMehta Standard Distribution | Version: | 4.0.11 |
Keywords: | Cc: | ||
Complexity: | 8 | Area: | Application Framework / API |
Module: | deepamehta-core |
Description
Plugins should register listener objects at the core instead of overriding dedicated methods. The core would call the registered listeners explicitly instead of iterating over all plugins installed. This should be the more efficient approach.
Note: #173 covers the same issue for the client-side.
Change History
comment:2 Changed 13 years ago by dgf
please have a look at the OSGi Event Admin Service Specification (page 295) as possible implementation of a dynamic dispatch service
comment:3 Changed 13 years ago by jri
Thanks for that impulse!
I will definitely consider using the Event Admin service.
Generally it seems a good idea as it would allow non-DM bundles to interfere with the DM installation.
However, I'm wondering if DM's hook concept fully fits the OSGi event concept. DM hooks are triggered at a high-rate, e.g. fetching a Person's full composite structure triggers the POST_FETCH_TOPIC hook about 20 times. OSGi events on the other hand are probably meant to be rather "high-level" events not fired this rapidly. I'm wondering about the overhead of OSGi events in contrast to native listener-method calls. Probably some profiling would help.
What do you think?
BTW: the DM core already makes use of Event Admin service to fire PLUGIN_READY events to handle plugin dependencies.
comment:4 Changed 13 years ago by dgf
i studied the source a little bit http://svn.apache.org/viewvc/felix/trunk/eventadmin/impl/ and in my opinion, we should give it a try
in preparation we can implement a test szenario and messure the event communication time, a blackbox test over REST should be enough
comment:5 Changed 13 years ago by jri
After discussing it dgf and jri decided the following:
The listener-observer pattern will be realized via native Java classes. Each one of the current hook methods will be replaced by a corresponding listener class. The OSGi Event Admin service will not be involved.
This was decided because of the "low-level" nature of the DM core events. An external application (not using the DM framework) would not be interested in these low-level events. A DM application (coded to the DM framework) on the other hand would use the very listener approach to participate in the DM control flow (and has no need for the OSGi Event Admin service).
The OSGi Event Admin service would be of interest when it comes to loose coupling of DM- and non-DM applications that run in the same OSGi container. Supporting this future scenario would involve the design of higher-level DM events.
comment:6 Changed 12 years ago by Jörg Richter
Core: redesign server-side hook mechanism (#261).
Plugins implement listener interfaces instead of overriding hook methods.
IMPORTANT: developers must adapt their plugins.
The required changes are quite minor. For each used hook a dedicated listener interface must be imported and implemented. The existing hook method can still act as the listener implementation. Only the method name changes slightly (the "Hook" wording is obsolete). The registration of the listeners is performed automatically by the framework by reflecting the implemented interfaces.
See the postCreateHook() of the Workspaces plugin as an example:
Old code:
public class WorkspacesPlugin extends Plugin implements WorkspacesService { @Override public void postCreateHook(Topic topic, ClientState clientState, Directives directives) { ... } }
New code:
import de.deepamehta.core.service.listeners.PostCreateTopicListener; public class WorkspacesPlugin extends Plugin implements WorkspacesService, PostCreateTopicListener { @Override public void postCreateTopic(Topic topic, ClientState clientState, Directives directives) { ... } }
The core service API has 2 new methods:
List<Object> fireEvent(CoreEvent event, Object... params); void addListener(CoreEvent event, Listener listener);
These are usually not to be called by the plugin developer.
For the moment only the postCreateHook() is transformed.
The other hooks will follow.
See ticket 261.
comment:7 Changed 12 years ago by Jörg Richter
Core: transform 7 more hooks to listeners (#261).
Old Hook Method New Listener Method Listener Interface ---------------------------------------------------------------------------------- preCreateHook -> preCreateTopic PreCreateTopicListener preUpdateHook -> preUpdateTopic PreUpdateTopicListener postUpdateHook -> postUpdateTopic PostUpdateTopicListener preDeleteAssociationHook -> preDeleteAssociation PreDeleteAssociationListener postDeleteAssociationHook -> postDeleteAssociation PostDeleteAssociationListener preSendTopicHook -> preSendTopic PreSendTopicListener preSendTopicTypeHook -> preSendTopicType PreSendTopicTypeListener ----------------------------------------------------------------------------------
2 hooks from DM3 are removed:
providePropertiesHook(Topic topic) providePropertiesHook(Association assoc)
7 more hooks are pending.
See ticket 261.
comment:8 Changed 12 years ago by dgf
Please add a short class documentation to each listener, so the package javadoc can be linked in the documentation.
Appending Listener to the interfaces is just a matter of taste, but it looks odd for me in a separated listners package.
comment:9 Changed 12 years ago by Jörg Richter
Core: internal events (#261).
A plugin can send an event to itself.
This is needed for the events (hook formerly) that are bound to a particular plugin (instead of fired globally):
- postInstallPluginHook
- modifyTopicTypeHook
- serviceArrived
- serviceGone
Transformed 1 more hook into a listener:
Old Hook Method New Listener Method Listener Interface ---------------------------------------------------------------------------------- postInstallPluginHook -> postInstallPlugin PostInstallPluginListener ----------------------------------------------------------------------------------
Package renamed to ...service.listener (instead ...service.listeners)
6 more hooks are pending.
See ticket 261.
comment:10 Changed 12 years ago by Jörg Richter
Core: all hooks transformed into listeners (#261).
Transformed 5 hooks:
Old Hook Method New Listener Method Listener Interface ---------------------------------------------------------------------------------- postRetypeAssociationHook -> postRetypeAssociation PostRetypeAssociationListener allPluginsReadyHook -> allPluginsReady AllPluginsReadyListener modifyTopicTypeHook -> introduceTopicType IntroduceTopicTypeListener serviceArrived -> serviceArrived ServiceArrivedListener serviceGone -> serviceGone ServiceGoneListener ----------------------------------------------------------------------------------
Removed 1 hook:
executeCommandHook()
Plugin hot deployment doesn't work yet.
Removed 1 core service call:
executeCommand()
The "Commands" concept is obsolete and will be dropped.
Note: the Commands related code is not yet dropped as it still provides a working file uplaod implementation. See:
- de.deepamehta.plugins.webservice.WebservicePlugin#executeCommand?()
- de.deepamehta.plugins.webservice.provider.CommandParamsProvider?
- de.deepamehta.core.util.UploadedFile?
See ticket 261.
comment:11 Changed 12 years ago by Jörg Richter
Core: fix closing service trackers (#261).
We close the service trackers in reverse creation order.
Consider this case: when a consumed plugin service goes away the core service is still needed to deliver the SERVICE_GONE event.
Plugin redeployment still doesn't work properly.
See ticket 261.
comment:12 Changed 12 years ago by Jörg Richter
Core: unregister event listeners (#261).
When a plugin is stopped it unregisters its event listeners.
Plugin hot redeployment works.
Technically the listeners are fully functional.
The old hook concept and code is now obsolete.
Removal of unused code and code cleanup is pending.
See ticket 261.
comment:13 Changed 12 years ago by Jörg Richter
Core: remove unused code and cleanup (#261).
See ticket 261.
comment:14 Changed 12 years ago by jri
There are still exceptions when the platform shuts down.
I'll fix them very soon.
comment:15 Changed 12 years ago by Jörg Richter
Core: fix plugin and service tracking (#261).
Plugin redeployment and container shutdown works properly.
Two groups of services are distinguished: a) the 3 "core services" (dms, web publishing, and event admin), and b) the "plugin services" as provided by plugins.
Once the dms is removed from a plugin the trackers of the consumed plugin services are closed. This is necessary because the dms is still needed to deliver the respective SERVICE_GONE events. Once the dms arrives the trackers are opened.
Simplification of plugin dependency tracking: plugin concept of being "ready" is now equivalent with being "registered" (at the core). No separate semantic anymore. No double bookkeeping.
See ticket 261.
comment:16 Changed 12 years ago by Jörg Richter
Core: rename some events (#261).
3 core events are renamed:
SERVICE_ARRIVED -> PLUGIN_SERVICE_ARRIVED
SERVICE_GONE -> PLUGIN_SERVICE_GONE
ALL_PLUGINS_READY -> ALL_PLUGINS_ACTIVE
The listener interfaces and and handler methods are renamed accordingly.
1 internal OSGi event is renamed:
PLUGIN_READY -> PLUGIN_ACTIVATED
See ticket 261.
comment:17 Changed 12 years ago by Jörg Richter
Core: redesign server-side hook mechanism (#261).
Plugins implement listener interfaces instead of overriding hook methods.
IMPORTANT: developers must adapt their plugins.
The required changes are quite minor. For each used hook a dedicated listener interface must be imported and implemented. The existing hook method can still act as the listener implementation. Only the method name changes slightly (the "Hook" wording is obsolete). The registration of the listeners is performed automatically by the framework by reflecting the implemented interfaces.
See the postCreateHook() of the Workspaces plugin as an example:
Old code:
public class WorkspacesPlugin? extends Plugin implements WorkspacesService? {
@Override
public void postCreateHook(Topic topic, ClientState? clientState, Directives directives) {
...
}
}
New code:
import de.deepamehta.core.service.listeners.PostCreateTopicListener?;
public class WorkspacesPlugin? extends Plugin implements WorkspacesService?, PostCreateTopicListener? {
@Override
public void postCreateTopic(Topic topic, ClientState? clientState, Directives directives) {
...
}
}
The core service API has 2 new methods:
List<Object> fireEvent(CoreEvent? event, Object... params);
void addListener(CoreEvent? event, Listener listener);
These are usually not to be called by the plugin developer.
For the moment only the postCreateHook() is transformed.
The other hooks will follow.
See ticket 261.
comment:18 Changed 12 years ago by Jörg Richter
Core: transform 7 more hooks to listeners (#261).
Old Hook Method New Listener Method Listener Interface
preCreateHook -> preCreateTopic PreCreateTopicListener?
preUpdateHook -> preUpdateTopic PreUpdateTopicListener?
postUpdateHook -> postUpdateTopic PostUpdateTopicListener?
preDeleteAssociationHook -> preDeleteAssociation PreDeleteAssociationListener?
postDeleteAssociationHook -> postDeleteAssociation PostDeleteAssociationListener?
preSendTopicHook -> preSendTopic PreSendTopicListener?
preSendTopicTypeHook -> preSendTopicType PreSendTopicTypeListener?
2 hooks from DM3 are removed:
providePropertiesHook(Topic topic)
providePropertiesHook(Association assoc)
7 more hooks are pending.
See ticket 261.
comment:19 Changed 12 years ago by Jörg Richter
Core: internal events (#261).
A plugin can send an event to itself.
This is needed for the events (hook formerly) that are bound to a particular plugin (instead of fired globally):
- postInstallPluginHook
- modifyTopicTypeHook
- serviceArrived
- serviceGone
Transformed 1 more hook into a listener:
Old Hook Method New Listener Method Listener Interface
postInstallPluginHook -> postInstallPlugin PostInstallPluginListener?
Package renamed to ...service.listener (instead ...service.listeners)
6 more hooks are pending.
See ticket 261.
comment:20 Changed 12 years ago by Jörg Richter
Core: all hooks transformed into listeners (#261).
Transformed 5 hooks:
Old Hook Method New Listener Method Listener Interface
postRetypeAssociationHook -> postRetypeAssociation PostRetypeAssociationListener?
allPluginsReadyHook -> allPluginsReady AllPluginsReadyListener?
modifyTopicTypeHook -> introduceTopicType IntroduceTopicTypeListener?
serviceArrived -> serviceArrived ServiceArrivedListener?
serviceGone -> serviceGone ServiceGoneListener?
Removed 1 hook:
executeCommandHook()
Plugin hot deployment doesn't work yet.
Removed 1 core service call:
executeCommand()
The "Commands" concept is obsolete and will be dropped.
Note: the Commands related code is not yet dropped as it still provides a working file uplaod implementation. See:
de.deepamehta.plugins.webservice.WebservicePlugin#executeCommand?()
de.deepamehta.plugins.webservice.provider.CommandParamsProvider?
de.deepamehta.core.util.UploadedFile?
See ticket 261.
comment:21 Changed 12 years ago by Jörg Richter
Core: fix closing service trackers (#261).
We close the service trackers in reverse creation order.
Consider this case: when a consumed plugin service goes away the core service is still needed to deliver the SERVICE_GONE event.
Plugin redeployment still doesn't work properly.
See ticket 261.
comment:22 Changed 12 years ago by Jörg Richter
Core: unregister event listeners (#261).
When a plugin is stopped it unregisters its event listeners.
Plugin hot redeployment works.
Technically the listeners are fully functional.
The old hook concept and code is now obsolete.
Removal of unused code and code cleanup is pending.
See ticket 261.
comment:23 Changed 12 years ago by Jörg Richter
Core: remove unused code and cleanup (#261).
See ticket 261.
comment:24 Changed 12 years ago by Jörg Richter
Core: fix plugin and service tracking (#261).
Plugin redeployment and container shutdown works properly.
Two groups of services are distinguished: a) the 3 "core services" (dms, web publishing, and event admin), and b) the "plugin services" as provided by plugins.
Once the dms is removed from a plugin the trackers of the consumed plugin services are closed. This is necessary because the dms is still needed to deliver the respective SERVICE_GONE events. Once the dms arrives the trackers are opened.
Simplification of plugin dependency tracking: plugin concept of being "ready" is now equivalent with being "registered" (at the core). No separate semantic anymore. No double bookkeeping.
See ticket 261.
comment:25 Changed 12 years ago by Jörg Richter
Core: rename some events (#261).
3 core events are renamed:
SERVICE_ARRIVED -> PLUGIN_SERVICE_ARRIVED
SERVICE_GONE -> PLUGIN_SERVICE_GONE
ALL_PLUGINS_READY -> ALL_PLUGINS_ACTIVE
The listener interfaces and and handler methods are renamed accordingly.
1 internal OSGi event is renamed:
PLUGIN_READY -> PLUGIN_ACTIVATED
See ticket 261.
comment:26 Changed 12 years ago by jri
- Status changed from accepted to closed
- Resolution set to fixed
comment:27 Changed 12 years ago by Jörg Richter
Core: redesign server-side hook mechanism (#261).
Plugins implement listener interfaces instead of overriding hook methods.
IMPORTANT: developers must adapt their plugins.
The required changes are quite minor. For each used hook a dedicated listener interface must be imported and implemented. The existing hook method can still act as the listener implementation. Only the method name changes slightly (the "Hook" wording is obsolete). The registration of the listeners is performed automatically by the framework by reflecting the implemented interfaces.
See the postCreateHook() of the Workspaces plugin as an example:
Old code:
public class WorkspacesPlugin? extends Plugin implements WorkspacesService? {
@Override
public void postCreateHook(Topic topic, ClientState? clientState, Directives directives) {
...
}
}
New code:
import de.deepamehta.core.service.listeners.PostCreateTopicListener?;
public class WorkspacesPlugin? extends Plugin implements WorkspacesService?, PostCreateTopicListener? {
@Override
public void postCreateTopic(Topic topic, ClientState? clientState, Directives directives) {
...
}
}
The core service API has 2 new methods:
List<Object> fireEvent(CoreEvent? event, Object... params);
void addListener(CoreEvent? event, Listener listener);
These are usually not to be called by the plugin developer.
For the moment only the postCreateHook() is transformed.
The other hooks will follow.
See ticket 261.
comment:28 Changed 12 years ago by Jörg Richter
Core: transform 7 more hooks to listeners (#261).
Old Hook Method New Listener Method Listener Interface
preCreateHook -> preCreateTopic PreCreateTopicListener?
preUpdateHook -> preUpdateTopic PreUpdateTopicListener?
postUpdateHook -> postUpdateTopic PostUpdateTopicListener?
preDeleteAssociationHook -> preDeleteAssociation PreDeleteAssociationListener?
postDeleteAssociationHook -> postDeleteAssociation PostDeleteAssociationListener?
preSendTopicHook -> preSendTopic PreSendTopicListener?
preSendTopicTypeHook -> preSendTopicType PreSendTopicTypeListener?
2 hooks from DM3 are removed:
providePropertiesHook(Topic topic)
providePropertiesHook(Association assoc)
7 more hooks are pending.
See ticket 261.
comment:29 Changed 12 years ago by Jörg Richter
Core: internal events (#261).
A plugin can send an event to itself.
This is needed for the events (hook formerly) that are bound to a particular plugin (instead of fired globally):
- postInstallPluginHook
- modifyTopicTypeHook
- serviceArrived
- serviceGone
Transformed 1 more hook into a listener:
Old Hook Method New Listener Method Listener Interface
postInstallPluginHook -> postInstallPlugin PostInstallPluginListener?
Package renamed to ...service.listener (instead ...service.listeners)
6 more hooks are pending.
See ticket 261.
comment:30 Changed 12 years ago by Jörg Richter
Core: all hooks transformed into listeners (#261).
Transformed 5 hooks:
Old Hook Method New Listener Method Listener Interface
postRetypeAssociationHook -> postRetypeAssociation PostRetypeAssociationListener?
allPluginsReadyHook -> allPluginsReady AllPluginsReadyListener?
modifyTopicTypeHook -> introduceTopicType IntroduceTopicTypeListener?
serviceArrived -> serviceArrived ServiceArrivedListener?
serviceGone -> serviceGone ServiceGoneListener?
Removed 1 hook:
executeCommandHook()
Plugin hot deployment doesn't work yet.
Removed 1 core service call:
executeCommand()
The "Commands" concept is obsolete and will be dropped.
Note: the Commands related code is not yet dropped as it still provides a working file uplaod implementation. See:
de.deepamehta.plugins.webservice.WebservicePlugin#executeCommand?()
de.deepamehta.plugins.webservice.provider.CommandParamsProvider?
de.deepamehta.core.util.UploadedFile?
See ticket 261.
comment:31 Changed 12 years ago by Jörg Richter
Core: fix closing service trackers (#261).
We close the service trackers in reverse creation order.
Consider this case: when a consumed plugin service goes away the core service is still needed to deliver the SERVICE_GONE event.
Plugin redeployment still doesn't work properly.
See ticket 261.
comment:32 Changed 12 years ago by Jörg Richter
Core: unregister event listeners (#261).
When a plugin is stopped it unregisters its event listeners.
Plugin hot redeployment works.
Technically the listeners are fully functional.
The old hook concept and code is now obsolete.
Removal of unused code and code cleanup is pending.
See ticket 261.
comment:33 Changed 12 years ago by Jörg Richter
Core: remove unused code and cleanup (#261).
See ticket 261.
comment:34 Changed 12 years ago by Jörg Richter
Core: fix plugin and service tracking (#261).
Plugin redeployment and container shutdown works properly.
Two groups of services are distinguished: a) the 3 "core services" (dms, web publishing, and event admin), and b) the "plugin services" as provided by plugins.
Once the dms is removed from a plugin the trackers of the consumed plugin services are closed. This is necessary because the dms is still needed to deliver the respective SERVICE_GONE events. Once the dms arrives the trackers are opened.
Simplification of plugin dependency tracking: plugin concept of being "ready" is now equivalent with being "registered" (at the core). No separate semantic anymore. No double bookkeeping.
See ticket 261.
comment:35 Changed 12 years ago by Jörg Richter
Core: rename some events (#261).
3 core events are renamed:
SERVICE_ARRIVED -> PLUGIN_SERVICE_ARRIVED
SERVICE_GONE -> PLUGIN_SERVICE_GONE
ALL_PLUGINS_READY -> ALL_PLUGINS_ACTIVE
The listener interfaces and and handler methods are renamed accordingly.
1 internal OSGi event is renamed:
PLUGIN_READY -> PLUGIN_ACTIVATED
See ticket 261.