I recently migrated my legacy project from Wicket 1.4 to 6.6.
In this project there is a batch job for sending out
newsletters. As you might expect, in those newsletters there are
links to contents from the system.

In the old system this was done like this (1.4 code):

| public CharSequence 
getApplicationRelativeUrlFor(IBookmarkablePageRequestTarget target) {
|     if (!MyApplication.exists()) {
|         final MyApplication application = (MyApplication) 
MyApplication.get("MyApplication");
|         MyApplication.set(application);
|         application.newRequestCycle(null, null);
|     }
|     for (final IRequestTargetUrlCodingStrategy strat : getCodingStrategies()) 
{
|         if (strat.matches(target)) {
|             final CharSequence relativeURL = strat.encode(target);
|             return relativeURL.toString();
|         }
|     }
|     return null;
| }

The method 'getCodingStrategies()' returns all coding strategies that
were created at startup and subsequently added to a list which is returned
here.

To me it seems like the above pretty much exploits some implementation
details of Wicket 1.4, however my predecessors did not seem to know another
way out. This project contains a bit of a content management system, in
which for different kinds of contents there are different mount points and
often even totally different IRequestTargetUrlCodinStrategy's, thus I 
don't really see any alternative to asking Wicket which has this information.

Now, based on Wicket 6.6.0 the above does no longer work, obviously due
to the way the 'Application' object is initialised and then stored. 

My code looks pretty much like this:

| public CharSequence getApplicationRelativeUrlFor( 
BookmarkablePageRequestHandler handler) {
|     MyApplication application = WicketUtil.checkMyApplication();
|
|     try {
|         IRequestMapper mapper = application.getRootRequestMapper();
|         if ( mapper == null ) {
|             throw new IllegalStateException( "Internal error, no root request 
mapper configured!" );
|         }
|         final Url url = mapper.mapHandler( handler );
|         return url;
|     } finally {
|         WicketUtil.cleanupDummyApplication( application );
|     }
| }

If no application exists, I tried creating a dummy version of it, this
is done somewhere inside the 'checkMyApplication()' method, and it boils
down to this here:

| public static MyApplication createDummyApplicationAndRequestCycle() {
|     MyApplication application = new MyApplication( true );
|     final MockServletContext servletContext = new MockServletContext( 
application, null );
|     application.setServletContext( servletContext );
|     WicketFilter wicketFilter = new WicketFilter( application );
|     try {
|         wicketFilter.init( true, new FilterConfig() {
|             @Override
|             public ServletContext getServletContext() {
|                 return servletContext;
|             }
|
|             @Override
|             public Enumeration<String> getInitParameterNames() {
|                 return Collections.enumeration( Collections.<String> 
emptyList() );
|             }
|
|             @Override
|             public String getInitParameter( final String name ) {
|                 return null;
|             }
|
|             @Override
|             public String getFilterName() {
|                 return "MyApplication";
|             }
|         } );
|     } catch ( final ServletException e ) {
|         throw new IllegalStateException( "Exception caught", e );
|     }
|     if ( RequestCycle.get() == null ) {
|         final ServletContext context = application.getServletContext();
|
|         final HttpSession newHttpSession = new MockHttpSession( context );
|         final MockHttpServletRequest servletRequest = new 
MockHttpServletRequest( application, newHttpSession, context ) {
|
|             @Override
|             public String getServletPath() {
|                 return getServletPathOtherCodeReliesOn();
|             }
|         };
|         final MockHttpServletResponse servletResponse = new 
MockHttpServletResponse( servletRequest );
|
|         servletRequest.initialize();
|         servletResponse.initialize();
|
|         final ServletWebRequest webRequest = new ServletWebRequest( 
servletRequest, servletRequest.getFilterPrefix() );
|
|         final WebResponse webResponse = new BufferedWebResponse( new 
ServletWebResponse( webRequest, servletResponse ) );
|
|         RequestCycle requestCycle = application.createRequestCycle( 
webRequest, webResponse );
|         ThreadContext.setRequestCycle( requestCycle );
|     }
|
|     return application;
| }

Cleaning up the dummy application looks like this:

| public static void cleanupDummyApplication( MyApplication application ) {
|     if ( !application.isDummy() ) {
|         return;
|     }
|     ThreadContext.setApplication( null );
| }

Of course this is very inefficient if I have to do this each time
a batch job queries for an URL.

When I now run this in a batch job, I find that the dummy application is 
created only once, though I attempt to remove it from the ThreadContext.
Also, after this has happened, when I open a page from the system in the
browser, I find that I've created an inconsistent state within the system,
getting this exception:

| java.lang.IllegalStateException: Application with name 'MyApplication' 
already exists.'
|         at org.apache.wicket.Application.setName(Application.java:864)
|         at 
org.apache.wicket.protocol.http.WicketFilter.init(WicketFilter.java:373)
|         at 
org.apache.wicket.protocol.http.WicketFilter.init(WicketFilter.java:336)
|         at 
org.apache.catalina.core.ApplicationFilterConfig.getFilter(ApplicationFilterConfig.java:259)
|         at 
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:237)
|         at 
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:215)
|         at 
com.freiheit.commons.sensor.SensorFilter.doFilter(SensorFilter.java:812)
|         at 
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
|         at 
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:215)
|         at 
ch.qos.logback.classic.helpers.MDCInsertingServletFilter.doFilter(MDCInsertingServletFilter.java:51)
|         at 
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
|         at 
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:215)
|         at 
org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:277)
|         at 
org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:188)
|         at 
org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:641)
|         at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:97)
|         at 
com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:85)
|         at 
org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:185)
|         at 
org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:325)
|         at 
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:226)
|         at 
com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:165)
|         at 
com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:791)
|         at 
com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:693)
|         at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:954)
|         at 
com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:170)
|         at 
com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:135)
|         at 
com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:102)
|         at 
com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:88)
|         at 
com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:76)
|         at 
com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:53)
|         at 
com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:57)
|         at com.sun.grizzly.ContextTask.run(ContextTask.java:69)
|         at 
com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:330)
|         at 
com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:309)
|         at java.lang.Thread.run(Thread.java:619)

OK, enough code shown here. I am asking myself if there is any totally 
different,
and presumably much simpler way to do this? I mean, in principle querying the 
web 
framework for an URL from a batch job does not seem totally uncommon to me, so 
maybe
there already is a mechanism to achieve something like this?

Else, if not, is there any correct way to initialize an Application and fake a 
request
from within my batch job, so that Wicket finds the environment it needs to run 
the
request mappers on my bookmarkable handler?

Any help *greatly* appreciated, I've already spent far too many hours on this :/

Cheers,

M'bert

-- 
----------- / http://herbert.the-little-red-haired-girl.org / -------------
=+= 
Die groessten Liebesgeschichten sind die, die nie stattgefunden haben

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@wicket.apache.org
For additional commands, e-mail: users-h...@wicket.apache.org

Reply via email to