How to get the URL to a Wicket shared resource?

Adrian Smith picture Adrian Smith · Nov 1, 2010 · Viewed 10.4k times · Source

The web designer has given me HTML which looks like:

<div .... style="background: transparent url(xxx.png) 170px center no-repeat">

Unfortunately the contents of the image xxx.png is generated by the software, so I have made it a WebResource and use the following strategy to generate the URL for the resource which I then embed in the style= attribute using a Wicket AttributeModifier.

// App initialization code
String resourceName = ....;
getSharedResources().add(resourceName, myWebResource);

// Creating the widget
String url = getServletContext().getContextPath()
    + "/resources/org.apache.wicket.Application/" + resourceName ;
String style = "background: transparent url(" + url + ") 170px center no-repeat";
div.add(new AttributeModifier("style", new Model<String>(style)));

This works fine when I test it locally using Eclipse, but :

  • When I install this in production, I want to have Apache as a proxy to Jetty such that the context root isn't visible, i.e. Apache forwards a request of /foo onto Jetty as /context-root/foo.
  • In general, I don't think this is very elegant. I'm sure I am duplicating Wicket code here?

I understand Wicket solves this problem of context-roots and Apache proxying by only using relative URLs. That would be the most elegant solution I suspect. But if I have e.g. a IndexedParamUrlCodingStrategy then the URL could be of arbitrary length and I don't know how many .. to include to get back to /resources.

Edit: The current solution is to use absolute URLs as in my code example above, and in Apache (a) rewrite /context-root/* into /* (b) as before then ADD the context root to all requests (c) forward to Jetty. That way most URLs can be without the context root but some URLs (to my resources) can have the context root and it's OK. But I don't like this solution!

Answer

tetsuo picture tetsuo · Nov 18, 2010

If the code is called from inside a component (or page):

urlFor(new ResourceReference("sharedResourceName"));

or

RequestCycle.get().urlFor(new ResourceReference("sharedResourceName"));

Sample application below. I used a ByteArrayResource for simplicity, but any Resource subclass will do:

WicketApplication.java

package app1;

import org.apache.wicket.protocol.http.WebApplication;
import org.apache.wicket.request.target.coding.IndexedParamUrlCodingStrategy;
import org.apache.wicket.resource.ByteArrayResource;

public class WicketApplication extends WebApplication {
    @Override
    protected void init() {
        super.init();
        getSharedResources().add("testResource", new ByteArrayResource("text/plain", "This is a test".getBytes()));
        mount(new IndexedParamUrlCodingStrategy("home/very/deep/folder", getHomePage()));
    }
    public Class<HomePage> getHomePage() {
        return HomePage.class;
    }
}

HomePage.java

package app1;

import org.apache.wicket.PageParameters;
import org.apache.wicket.ResourceReference;
import org.apache.wicket.behavior.SimpleAttributeModifier;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.WebPage;

public class HomePage extends WebPage {
    public HomePage(final PageParameters parameters) {
        CharSequence resourceHref = urlFor(new ResourceReference("testResource"));
        add(new Label("link", "Click me!")
            .add(new SimpleAttributeModifier("href", resourceHref)));
    }
}

HomePage.html

<html xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd" >
    <body>
        <a wicket:id="link"></a>
    </body>
</html>