All,
I wanted to offhand thank everyone who provided insight and tips on how
to resolve this issue. As Ben, Aaron and Frank pointed out there is a
disconnect between Spring initialization and the Stripes filter
initialization. After a lot of googling and listening to advice and
some great code out on the Internet I have a solution that I am happy
with. Project uses JPA + Spring + Stripersist + Hibernate + other
stuff....
Problem Description:
---------------------------
Leverage @SpringBean, @Service, @Repository, @Autowire, etc...
annotations with minimal ApplicationContext.xml configuration (just
component scans) AND have Spring beans perform post-creation
initialization that involves making calls through Stripersist without
throwing exceptions e.g. initializing DAO's that provide pick lists... .
Problem Overview:
-------------------------
Placing the following in web.xml results in Spring reading the
ApplicationContext.xml and wiring of Spring defined and annotated beans...
<listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener>
However Stripersist is only initialized - much later - once the
StripesFilter is initialized and moreover that will only occur on
initial request filter processing therefore performing any sort of
initialization that depends on Stripersist in the a Spring bean's
constructor OR in in a @PostConstruct OR whatever will result in
possible exceptions as Stripersist has not had its init(config) method
invoked yet to initialize itself.
2 Solution Alternatives:
------------------------------
#1 Somehow force Stripersist to have its init(config) method invoked
PRIOR to Spring initialization.
#2 Somehow perform delayed initialization on the beans that would like
to initialize themselves AFTER Spring and Stripersist init
Solution #1 - "the easy solution"
-----------------------------------------
A rather simple way to do this is to define a bean at the top of
ApplicationContext.xml that simply calls a class with the following code
in its constructor:
(new Stripersist()).init((Configuration) null);
Null is passed in above as normally one would pass in
StripesFilter.getConfiguration() however as the Stripes Filter has not
been initialized yet the result is null anyways along with a debug
logging exception being harmlessly displayed.
However this has a few drawbacks besides being a kludge... the primary
one being that when Stripersist gets its chance to initialize as part of
the Stripes Filter initialization... persistence.xml, entity manager
factories et al. will ALL be recreated a 2nd time which is quite
expensive... not to mention Stripersist will spew a NullPointerException
we should trap around the code above.
Despite the drawbacks... the above will allow our @PostConstruct method
to call Stripersist methods and all is well... though the solution is
clearly a dirty hack...
Solution #2 - "the longer IMHO more elegant solution"
---------------------------------------------------------------------
There are MANY ways to do this I simply present ONE way....
Create a new annotation called say @DelayedInitialize that is associated
with the methods in the Spring beans that need to say call Stripersist
or anything e.g.:
@DelayedInitialize
public void initService() {
List<Modality> modalityList = this.modalityDao.findAll();
this.modalityCache = new ModalityCache();
this.modalityCache.init(modalityList);
}
Have this annotation's runner listen to Spring ContextRefreshedEvent
(which means that Spring has finished building its Application Context
BUT does not mean that Stripes Filter OR transitively Stripersist has
initialized yet) and retain methods annotated with this annotation in a
static list. Also this annotation's runner should allow for a static
initializeNow() method call that simply iterates over the static list
and fires the annotated methods.
A REALLY useful piece of code to use to model this is provided here and
provides the framework for a similar premise... adding @PostInitialize
to Spring:
http://issues.springframework.org/browse/SPR-5966?page=com.atlassian.jirafisheyeplugin%3Acrucible-issuepanel
(Thanks to Baruch Sadogursky and zvizvi for putting this code together)
Lastly, how to trigger this delayed initialization. Well one could
create a dummy filter to run after Stripes filter but an even easier
solution is leveraging a hook allowed for by Stripersist itself which
essentially allows custom init code to be executed as the last step of
Stripersist init(config). The class is simply as follows:
public class StripersistDelayedInitialize implements StripersistInit{
@Override
public void init() {
DelayedInitializerRunner.initializeNow();
}
}
So here is what happens in a nutshell:
a) Spring creates the Application Context leveraging
ApplicationContext.xml and Spring beans are created and wired...
b) Once the Context is created Spring fires the ContextRefreshedEvent
ApplicationEvent which is picked up by our DelayedInitializerRunner and
invokes code that finds all the @DelayedInitialize annotations and
creates a static list of those method calls
c) Stripes Filter initializes and as part of that initialization
Stripersist initializes and as part of that initialization our simple
class triggers the initializeNow method statically on our
DelayedInitializerRunner which causes the static list of methods to call
to be invoked one by one
Lastly, although the @DelayedInitialize is being used in the context of
code that needs to execute AFTER Stripersist is initialized the code is
generic enough that it could be used for other purposes as well... i.e.
wherever any methods that need to be called at some later point in time
is involved.
Thanks Again to everyone who responded!
HTH,
--Nikolaos
------------------------------------------------------------------------------
_______________________________________________
Stripes-users mailing list
Stripes-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/stripes-users