Introduction
If a user of my Apache Wicket web application (which runs on GAE/J) attempts to visit a non-existent page, for example:
http://[MyURL]/admin/PageSubscribeX
the web framework logs the following warning:
org.apache.wicket.core.util.lang.WicketObjects resolveClass: Could not resolve class [[...].admin.PageSubscribeX]
java.lang.ClassNotFoundException: [...].admin.PageSubscribeX
at com.google.appengine.runtime.Request.process-78915baf06af5f31(Request.java)
at java.lang.Class.forName(Class.java:133)
at org.apache.wicket.application.AbstractClassResolver.resolveClass(AbstractClassResolver.java:108)
at org.apache.wicket.core.util.lang.WicketObjects.resolveClass(WicketObjects.java:71)
at org.apache.wicket.core.request.mapper.AbstractComponentMapper.getPageClass(AbstractComponentMapper.java:139)
at org.apache.wicket.core.request.mapper.PackageMapper.parseRequest(PackageMapper.java:148)
...
at com.google.tracing.TraceContext$TraceContextRunnable.run(TraceContext.java:458)
at java.lang.Thread.run(Thread.java:679)
and GAE/J responds with an error 404 page and the text Error: NOT_FOUND
.
I know that currently with GAE/J I "cannot customize the 404 response page when no servlet mapping is defined for a URL".
My question
Is there any way I can specify a Wicket page for the response when no servlet mapping is defined for a URL? Alternatively, is there some servlet mapping I can define to map "all URLs not found" to a Wicket page of my choice?
My software environment is:
- Wicket: 6.2.0
- GAE/J: 1.7.3
- Java: 1.6.0_37.
A failed attempt
Following the comments of @biziclop, I have tried the following, but this failed. All I got was my error page PageError showing every time....
My code in my WebApplication#init()
was:
ICompoundRequestMapper crmRoot = getRootRequestMapperAsCompound();
URLNotFoundMapper mapperURLNotFound = new URLNotFoundMapper(null,
PageError.class);
crmRoot.add(mapperURLNotFound);
setRootRequestMapper(crmRoot);
My new mapper URLNotFoundMapper
was
/**
* This mapper class is intended to be the mapper of last resort, to be used
* if all other mappers cannot handle the URL of the current request.
* <br/>
* This mapper will cause a defined (error) page to be shown.
*/
public class URLNotFoundMapper extends BookmarkableMapper
{
private IRequestMapper m_rmRoot = null;
private Class<? extends IRequestablePage> m_classPage = null;
/**
* Constructor.
* @param rmRoot
* The application's previous root request mapper.
* If this is <code>null</code> then it is ignored.
* @param clError
* The class of the page which should handle erroneous requests.
* This must not be <code>null</code>.
*/
public URLNotFoundMapper(IRequestMapper rmRoot,
final Class<? extends IRequestablePage> clError)
{
m_rmRoot = rmRoot;
m_classPage = clError;
}
/**
* Use this mapper as the last option.
* So let all other mappers try to handle the request first.
* @param request
* The request.
* @return
* The score of the application's previous root request mapper.
*/
@Override
public int getCompatibilityScore(Request request)
{
return Integer.MIN_VALUE;
}
/**
* This method returns an <code>IRequestHandler</code> for the bookmarkable
* error page.
* @param request
* @return
* An <code>IRequestHandler</code> capable of processing a bookmarkable
* request.
*
*/
@Override
public IRequestHandler mapRequest(Request request)
{
IRequestHandler rhResult = null;
if (m_rmRoot != null)
rhResult = m_rmRoot.mapRequest(request);
if (rhResult != null)
rhResult = null; // Another mapper can handle this
else
{
rhResult = processBookmarkable(m_classPage, null);
}
return rhResult;
}
@Override
public Url mapHandler(IRequestHandler requestHandler)
{
Url urlResult = null;
if (m_rmRoot != null)
urlResult = m_rmRoot.mapHandler(requestHandler);
if (urlResult != null)
urlResult = null; // Another mapper can handle this
else
{
PageInfo info = new PageInfo();
UrlInfo urlInfo = new UrlInfo(new PageComponentInfo(info, null),
m_classPage, null);
urlResult = buildUrl(urlInfo);
}
return urlResult;
}
/**
* @return
* The URL info for the bookmarkable error page.
*/
@Override
protected UrlInfo parseRequest(Request request)
{
UrlInfo uiResult = null;
uiResult = new UrlInfo(null, m_classPage, null);
return uiResult;
}
}