I'm developing a web application using Wicket
.
While most of the website is dynamically generated through wicket, I need to have a portion of the site be a normal "static" html
website. Basically a small "subsite" inside the main website that is not managed by wicket at all, but that, instead, is just a collection of static content (html pages, css, images).
Can this be done? The idea would be to "mount" a certain subpath to point to the sub-site, but I don't know if this is even possible, as the mountResource()
method wants a Resource as input.
EDIT: I need a solution that allow me to modify the static html files directly on the filesystem, thus the reason I was trying to "mount a directory" via wicket. I cannot simply put the pages in my webapp folder, since that way they end up inside the app's WAR file and every modification to the static pages would need a full deploy every time.
Any ideas?
Well, I implementet this myself in the end, using a dynamic resource. I'm not an expert of Wicket, so this may be a "bad" solution for some reason, but it seems to work. Posting the code here so other people can use it if they want:
What I did was create this resource:
public class DirectoryResolverResource implements IResource {
private static final long serialVersionUID = 1L;
private File servedDirectory;
private String urlPrefix;
//served directory is the directory you want to mount as a static sub-site
//urlPrefix is the mountpoint where you're going to mount this resource, without the leading "/". E.g.: if you mount your directory in "/help" so that the sub-site URL is www.yoursite.com/pages/help the urlPrefix value must be "help"
public DirectoryResolverResource(File servedDirectory, String urlPrefix) {
super();
if (servedDirectory == null || !servedDirectory.isDirectory()) {
throw new IllegalArgumentException("Directory is null or doesn't exist");
}
this.servedDirectory = servedDirectory;
this.urlPrefix = urlPrefix;
}
@Override
public void respond(Attributes attributes) {
Url url = attributes.getRequest().getUrl();
String subPath = "";
try {
//we decode the URL by reversing the percent-encoding, so that filenames are properly resolved
subPath = URLDecoder.decode(url.toString(), "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new AbortWithHttpErrorCodeException(HttpServletResponse.SC_BAD_REQUEST, "Encoding is invalid");
}
if (subPath.startsWith(urlPrefix)) {
subPath = subPath.substring(urlPrefix.length());
} else {
throw new AbortWithHttpErrorCodeException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Url is invalid");
}
File file = new File(servedDirectory.getAbsolutePath() + (subPath.startsWith("/") ? "" : "/") + subPath);
if (file.isDirectory()) {
// In case of a directory, redirect to the path ending in "/", otherwise browsers will fail to resolve relative paths in the page
if (!subPath.endsWith("/")) {
throw new RedirectToUrlException("." + (subPath.isEmpty() ? "/" + urlPrefix : subPath) + "/", HttpServletResponse.SC_MOVED_PERMANENTLY);
}
// no specific file specified, try to return index.html
file = new File(file.getAbsolutePath(), "index.html");
}
if (!file.exists() || file.isDirectory()) {
// file not found
throw new AbortWithHttpErrorCodeException(HttpServletResponse.SC_NOT_FOUND, "Resource not found");
}
if (!FSManager.isInSubDirectory(servedDirectory, file)) {
// Security check: user is trying to escape the served directory via a non-canonical path
throw new AbortWithHttpErrorCodeException(HttpServletResponse.SC_FORBIDDEN, "Access to this resource is forbidden");
}
// Serve the file
FileResourceStream fileResourceStream = new FileResourceStream(file);
ResourceStreamResource resource = new ResourceStreamResource(fileResourceStream);
resource.respond(attributes);
}
}
You can mount this resource like this:
mountResource("/help", new ResourceReference("helpres") {
private static final long serialVersionUID = 1L;
@Override
public IResource getResource() {
return new DirectoryResolverResource(helpDir, "help");
}
});
Hope this is helpful to someone. Any improvements/comments/corrections/constructive criticisms are higly appreciated!
NOTE: the isInSubDirectory()
method just checks if a file is inside a certain directory tree. Won't bore you with the details, you can find implementations of such method here: Check if file is in (sub)directory