Hi Asiri,
On May 6, 2009, at 7:24 AM, Asiri Rathnayake wrote:
Hi Devs,
I was working on openoffice server auto-start feature and faced a few
problems with it.
To start the openoffice server when XE is started, I need to send a
notification to openoffice server manager when XE is started. The
first
attempt was to use our ObservationManager component to send startup /
shutdown events and let OpenOfficeServerManager listen to them. But
this
approach requires that OpenOfficeServerManager component is loaded
on XE
startup so that it can recieve the startup notification.
As a solution I tried to use <load-on-startup> components list in
plexus.xml
file but since OpenOfficeServerManager has a dependancy on
ConfigurationSourceCollection component, it fails to load on
startup. This
is because ConfigurationSourceCollection requires a valid
ApplicationContext
to be present for it's operation but at the time plexus is loading
<load-on-startup> components, no ApplicationContext is present. The
core
issue is, plexus is initialized before we initialize
ApplicationContext; and
we can't change this order either.
Facts:
- Right now the Container component is initialized explicitly by
calling a container initializer component. This is done at all thread
entry points in XWiki and is dependent on the environment (servlet,
daemon, portlet, etc).
- Since this is tied to the environment we can't autoload the
container initialization component at plexus startup (it requires info
from the environment) and since the Container is a component it
requires plexus to be loaded before it's initialized.
- Since we dynamically register components using annotations, I don't
think the plexus load on startup configuration option will work (it'll
run before we register the components).
Need:
- Load on startup components but after the Application Context is
initialized (at least for components using it).
- One reason we need to load some components are startup is because
they are accessing resources and we need to ensure these resources are
present when the app is started as otherwise it'll fail lazily later
on which is bad (better to know when the admin starts the app)
- Another need is to do something when the app is started, like store
something in the application context
Solution:
- The one proposed below using ApplicationContextListener/
ApplicationContextListenerManager
- Component who need to be started at start time can implement
ApplicationContextListener (directly or through another component
which would have the component to startup injected as a dependency for
ex in order to load it automatically).
Since the above approach is not going to work, I
propose to
introduce an
ApplicationContextInitializer component pretty much alike
RequestInitializer
and ExecutionContextInitializer. The idea is to allow any component
to do
further initializations on ApplicationContext if they need to do so.
When XE
is started up and an ApplicationContext is created,
ApplicationContextInitializerManager will lookup for all the
components that
implement ApplicationContextInitializer and let them a chance to
execute
their own initializations.
But this doesn't solve the problem of shutdown notifications. For
shutdown
notifications we can either use the plain old ObservationManager
component
or we can do the following; rather than having
ApplicationContextInitializer
and ApplicationContextInitializerManager, we will have
ApplicationContextListener and ApplicationContextListenerManager.
ApplicationContextListener will have two methods like
contextCreated() and
contextDestroyed() that will allow any component to perform startup /
shutdown tasks.
initializeApplicationContext()
destroyApplicationContext()
But still, I don't see where we can invoke
contextDestroyed() method from, I looked at both servlet container
API and
portlet container API and couldn't find a consistent way of invoking
the
contextDestroyed() method.
For servlet api, in XWikiPlexusServletContextListener you'll override
contextDestroyed() and call it.
I'm pretty sure the same can be done for portlets.
+1 to all this. Don't forget to rename RequestInitializerManager into
RequestListenerManager and RequestInitializer into RequestListener.
And ExecutionContextInitializer* into ExecutionContextListener* for
consistency (since we'll want to implement destroy() methods for them
too).
Thanks
-Vincent
Please let me know what you think about this idea.
Thanks.
- Asiri