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