Hi, I spent some time recently digging around in the URLRewrite code to track down the bug with forms. I had used this interface previously but didn't stop to think about it until I was knee deep in the code.
I'm curious about the inspiration for implementation and interface. It really makes no sense to me that we are editing a Request for outgoing links, or that we need a context for incoming requests. The incoming requests can't have the Page/ComponentEvent Parameters because rewritten urls are often not going to match a page/component event. The URLRewriteContext seems like an unnecessary crutch. The interface can be significantly simplified to just: public interface URIRewriteWorker { /** * Incoming request. Does not contain the servlet context. **/ String rewrite(String uri); /** * Outgoing page render link. Contains the servlet context, if not deployed as the root context **/ String rewrite(String uri, PageRenderRequestParameters params); /** * Outgoing component event render link. Contains the servlet context, if not deployed as the root context **/ String rewrite(String uri, ComponentEventRequestParameters params); } Although, if Link had set methods for the the URI, and remove methods for the parameters we could just use the LinkCreationListener for the outgoing half of the API. I've included the code below with an example. If you find a defect please let me know. I'm using this in my own projects. // From AppModule, add a simple rewrite. public static void contributeURIRewriteInvoker(OrderedConfiguration<URIRewriteWorker> config) { config.add("SimpleRewrite", new URIRewriteWorker() { public String rewrite(String uri) { final String s = "request=yes"; return addParam(uri, s); } public String rewrite(String uri, PageRenderRequestParameters params) { return addParam(uri, "page=yes"); } public String rewrite(String uri, ComponentEventRequestParameters params) { return addParam(uri, "event=yes"); } private String addParam(String uri, String s) { String sep = uri.indexOf("?") != -1 ? "&" : "?"; return uri + sep + s; } } ); } /** * Implements the hooks to catch incoming and outgoing URIs. **/ public class URIRewriteInvokerImpl implements URIRewriteInvoker { private final List<URIRewriteWorker> _workers; private final HttpServletRequest _servletRequest; private final Response _response; public URIRewriteInvokerImpl(List<URIRewriteWorker> workers, HttpServletRequest servletRequest, Response response ) { _workers = workers; _servletRequest = servletRequest; _response = response; } public boolean service(Request request, Response response, RequestHandler handler) throws IOException { // Support rewriting query params final String startURI = request.getPath() + '?' + _servletRequest.getQueryString(); String uri = startURI; for (URIRewriteWorker worker : _workers) { uri = worker.rewrite(uri); if (uri == null) { throw new NullPointerException("URIRewriteInvoker: worker returned null uri for " + startURI); } } if (!startURI.equals(uri)) { // build modified request request = new RewriteRequest(uri, request); } return handler.service(request, response); } public void advise(Invocation invocation) { // let the method create the link. invocation.proceed(); // give the workers a chance to change it final Link link = (Link) invocation.getResult(); String startURI, uri; startURI = uri = link.toAbsoluteURI(); boolean forForm = false; // hold this for later. if (invocation.getMethodName().equals("createPageRenderLink")) { for (URIRewriteWorker worker : _workers) { uri = worker.rewrite(uri, (PageRenderRequestParameters) invocation.getParameter(0)); } } else { forForm = (Boolean) invocation.getParameter(1); for (URIRewriteWorker worker : _workers) { uri = worker.rewrite(uri, (ComponentEventRequestParameters) invocation.getParameter(0)); } } if (!startURI.equals(uri)) { final int q = uri.indexOf("?"); final String query = q == -1 ? null : uri.substring(q + 1); // The link doesn't need query params in the uri if (q != -1) { uri = uri.substring(0, q); } // LinkImpl is internal, but I don't want to write a new one... final Link newLink = new LinkImpl(uri, false, forForm, _response, null); // Extract params from the uri and stuff them back into the link if (query != null) { String[] params = query.split("&"); for (String param : params) { final String[] parts = param.split("="); newLink.addParameter(parts[0], parts[1]); } } invocation.overrideResult(newLink); } } /** * We override the uri, so take over the request parameters and path. */ private class RewriteRequest extends DelegatingRequest { private URI _overrideURI; private Map<String, Object> _parameters; public RewriteRequest(String uri, Request request) { super(request); try { _overrideURI = new URI(uri); } catch (URISyntaxException e) { throw new RuntimeException("Failed parsing uri: " + uri, e); } } @Override public String getParameter(String name) { if (_parameters == null) parseParameters(); final Object o = _parameters.get(name); if (o == null) return null; if (o instanceof ArrayList) { @SuppressWarnings("unchecked") final ArrayList<String> strings = (ArrayList<String>) o; return strings.get(0); } return (String) o; } @Override public List<String> getParameterNames() { if (_parameters == null) parseParameters(); return new ArrayList<String>(_parameters.keySet()); } @Override public String[] getParameters(String name) { if (_parameters == null) parseParameters(); final Object o = _parameters.get(name); if (o == null) return null; if (o instanceof ArrayList) { @SuppressWarnings("unchecked") ArrayList<String> list = ((ArrayList<String>) o); return list.toArray(new String[list.size()]); } return new String[]{(String) o}; } @Override public String getPath() { return _overrideURI.getPath(); } private void parseParameters() { final String query = _overrideURI.getQuery(); _parameters = new HashMap<String, Object>(); if (query != null && !query.equals("")) { String[] params = query.split("&"); for (String param : params) { final String[] parts = param.split("="); Object o = _parameters.get(parts[0]); if (o instanceof String) { final ArrayList<String> list = new ArrayList<String>(); list.add((String) o); list.add(parts[0]); o = list; } else if (o instanceof ArrayList) { @SuppressWarnings("unchecked") final ArrayList<String> strings = (ArrayList<String>) o; strings.add(parts[0]); } else { // for example ?x=1&y&z=2 y has no value if (parts.length > 1) { o = parts[1]; } else { o = null; } } _parameters.put(parts[0], o); } } } } } // Add the hook for request handler and advise the CompentEventLinkEncoder (goes in the LibModule, or AppModule) public void contributeRequestHandler(OrderedConfiguration<RequestFilter> configuration, URIRewriteInvoker urlRewrite ) { configuration.add("URIRewriteInvoker", urlRewrite); } @Match("ComponentEventLinkEncoder") public static void adviseURIRewriteService( MethodAdviceReceiver receiver, URIRewriteInvoker urlRewrite) throws Exception { Class<ComponentEventLinkEncoder> clasz = ComponentEventLinkEncoder.class; Method createPageRenderLink = clasz.getMethod("createPageRenderLink", PageRenderRequestParameters.class); Method createComponentEventLink = clasz.getMethod("createComponentEventLink", ComponentEventRequestParameters.class, boolean.class); receiver.adviseMethod(createComponentEventLink, urlRewrite); receiver.adviseMethod(createPageRenderLink, urlRewrite); } Josh -- -- http://www.bodylabgym.com - a private, by appointment only, one-on-one health and fitness facility. -- http://www.ectransition.com - Quality Electronic Cigarettes at a reasonable price! -- TheDailyTube.com. Sign up and get the best new videos on the internet delivered fresh to your inbox. --------------------------------------------------------------------- To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org For additional commands, e-mail: users-h...@tapestry.apache.org