Jurlmap Manual

What is jurlmap

A Java library for enabling your webapps to have clean, REST like urls. Rather than being a swiss army knife tool like others, it is optimized for this single role, and as such it is (hopefully) easier to use, less verbose and packed with convenience features (such as binding matched url parts directly to javabean properties).

How can I add jurlmap to my application

Download the jar and add it to your application library directory. Create a subclass of com.codegremlins.jurlmap.DispatchFilter and override the configure method to add your configuration. Add a mapping of your filter to your web.xml file.

<filter>
    <filter-name>DispatchFilter</filter-name>
    <filter-class>com.myapp.MyDispatchFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>DispatchFilter</filter-name>
     <url-pattern>/*</url-pattern>
</filter-mapping>

How do I configure URL mappings

Lets start with some examples:

protected void configure() {
    // Match given pattern, in which $ mean a string, bind to parameter
    // `Username` and forward to profile.jsp
    // Parameter will be accessible via request.getParameter()
    forward("/profile.jsp", "/profile/$Username");

    // Match given pattern in which % means integer and * mean until end of pattern,
    // bind integer to parameter ArticleId and forward to article.jsp
    forward("/article.jsp", "/article/%ArticleId/*");

    // match pattern, bind parameter and redirect to `/servlets/profileservlet?Username=...`
    redirect("/servlets/profileservlet", "/member/$Username");

    // Same as above only send 301 permanent redirect
    relocate("/servlets/profileservlet", "/member/$Username");


    // Shows how to add http methods to patterns. First one will be run when pattern matches
    // AND method is POST (and only POST). Second will run when method is GET. 
    // Default is GET and POST.
    // Both patterns are the same (besides the http method that is).
    forward("/edit_person.jsp", "/member/$Username;POST");
    forward("/person.jsp", "/member/$Username");

    // Shows use of deploy rule
    deploy(LogoutPage.class, "/logout");

    // Deploy is also possible without passing a pattern parameter, if LoginPage class is 
    // annotated with a @Deploy(path) annotation
    deploy(LoginPage.class);

    // Shows that multiple patterns are possible in single rule call.
    // Also demonstrates `enum` pattern element where one of several given values is matched
    deploy(ArticlesHomePage.class, "/", "/sort/[newest|oldest|hottest]SortOrder");
}

The above examples show 90% of what you need to know to effectively use jurlmap.

Rather than having external configuration files jurlmap is configured in plain old Java.

As can be seen from the example (the one way way above...) there are currently four possible actions: forward, redirect, relocate and deploy. Each takes as parameters a target, and one (or in the case of deploy zero) or multiple patterns. On invocation if the pattern is matched the action is executed...obviously.

What do these action types mean exactly:

  • forward When matched it will make parameters accesible via request.getParameter and will forward to target

  • redirect When matched it will append parameters as query string and will send redirect to target

  • relocate It is similar to redirect but sends 301 permanent redirect.

  • deploy When matched it will create a new instance of target class, will bind parameters to new instance via setters or raw fields (whichever it finds) and finally invoke the service method.

The first two action types are useful when you are working with an existing application, or an application written in an existing framework for which you want to enable clean URLs. The deploy action is more interesting if you are developing a new application and you are looking for an alternative to the limited servlet mapping facilities of web.xml.

Pattern syntax

The available pattern syntax is very simple:

A pattern is separated between a ; character. Anything before ; is the path pattern. Anything after is the http methods such as GET, POST, PUT, DELETE. You can specify multiple http methods separated by | such as GET|PUT.

Any given path is split at each / character and each subelement can be one of the following:

  • $ Matches any string.

  • % Matches a long/integer.

  • [] Matches one of several options separated by | in the like: [options1|option2|option3]

  • * Matches everything until the end of the pattern, including subsequent /.

  • Any other text is matched as is. it behaves same as [text] with a single element, only in this case it cannot be followed by ? or binding options.

If a ? follows any of the above elements (except the last one) then that element is optional, that is the pattern matches whether the element is present or not.

Any of the above elements can be followed by binding options that specify to which parameter to bind the matched result. example

/member/$Username will match a string and bind it to parameter username. Parameters can also be compound such as /member/%User.Id, which will work as follows:

You can define subpatterns by using parenthesis. For example /home(/room/$roomname) will expand to both /home and /home(/room/$roomname) patterns and will match any results that resolves to either pattern.

For the forward and redirect actions the matched parameter will contain a dot and will be User.Id exactly as give. For the deploy action, the result will be more complicated, in that first the object property User will be looked up, a new object will be instantiated to the type of that property, the property set to that object, and the Id property or the new instance will be set. Lets draw a picture to explain that:

Assuming the following:

class MyPage implements Page {
    User user;
}

class User {
   int id;
}

When binding User.Id this will happen:

- result = new User()
- result.id = @@MatchedIntegerParameter@@
- myPage.user = result;

There is one case where the binding syntax is a little different. It is possible to annotate methods of a class with pattern annotations @Deploy and then use them as targets in a pattern dispatch like:

class MyClass {
    private static final PathSet PATHS = new PathSet(MyClass.class);

    public void doMe(String path) {
              PATHS.dispatch(this, path);
    }

    @Deploy("/something/to/do")
    public void runSomething() {
        ...
    }

    @Deploy("/person/$1/%2/%3.Id")
    public void runSomething(String parameter1, int parameter2, User parameter3) {
        ...
    }
}

In this case, as the examples show the parameter bindings are specified as numbers, corresponding to the method parameters as they appear in order.

One problem you will never have with jurlmap is the issue of trailing /. In many frameworks /path is different from /path/ and sometimes you get one when you want the other or you are confused about which is which. With jurlmap all extra / characters are ignored so /my/path is the same as /my/path/ which is the same as /my/////path//

Important Classes

Here is a list of the classes and interfaces that you can use as part of jurlmap:

public class DispatchFilter implements javax.servlet.Filter {
    abstract protected void configure();
    public final void forward(String target, String ...patterns);
    public final void redirect(String target, String ...patterns);
    public final void deploy(Class<?> clazz, String ...patterns);
    public final void setDispatchServlet(String dispatchServlet);
    public final void setDefaultHttpMethods(String methods)
}

public class DispatchServlet {
}


public interface Page {
    public void service(ServletContext context, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException;
}


abstract public class AbstractPage implements Page {
    public void run() throws ServletException, IOException;
    protected boolean dispatch();
    protected boolean dispatch(String path);
    protected HttpServletRequest getRequest();
    protected HttpServletResponse getResponse();
    protected ServletContext getServletContext();
    protected void forward(String target) throws ServletException, IOException;
    protected void redirect(String target) throws IOException;
    protected boolean modified(long lastModified);
    protected void serialize(Object object);    
}

public class PathSet {
    public PathSet(Class targetClass);
    public Object dispatch(Object self, String path);
    public Object dispatch(Object self, String path, HttpServletRequest request);
}

public @Retention(RetentionPolicy.RUNTIME) 
@interface Deploy {
    String[] value();
}

What else?

License is LGPL.

If you think there is something missing either from this manual or a feature that should be added to jurlmap let me know.