August 20, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Leveraging the Restlet Routing System for Your Java Web Services

  • April 9, 2010
  • By Jerome Louvel, Thierry Boileau
  • Send Email »
  • More Articles »

Overview of the Available Filters

In addition to the base Filter class, the Restlet API comes with several filters ready to use, as illustrated in the Figure 3. First, we have the Extractor providing a way to extract values from request cookies, query parameters or posted forms, and to store them as request attributes for easier processing down the road, for example, using the Validator filter, which can check for the presence of attributes with a given name and the format of their string value.

Then, we find two security related filters, the Authenticator, to verify the credentials given by a user or to ask him to provide them, and the Authorizer, to enforce access policies.

org.restlet.routing.Filter subclasses
Figure 3.
Class diagram showing some common org.restlet.routing.Filter subclasses

Note that those filters should only be used if their behavior is useful for a set of target resources; otherwise, it is better to add this logic inside your resources directly. Finally, there is a fifth filter called TemplateRoute that isn't displayed in the figure because it is rarely used directly. Instead, you generally leverage it via the Router class, which is our next topic.

Dispatching Calls Based on URIs with a Router

So far, we illustrated how inbound or outbound calls could be filtered in order to apply pre-processing or post-processing. What is missing from this puzzle is a way to direct calls to target resources, to route them based on properties like the target URI. This is the purpose of the org.restlet.routing.Router class, a direct subclass of Restlet, which is composed of a list of routes and a set of properties that define how the routing of an incoming call to one of the routes actually happens. Of course, like all Restlet subclasses, a Router must be thread safe to support the routing of several concurrent calls.

In Figure 4, we illustrated how three calls (A, B, and C), supported by three concurrent threads, enter a Router instance to end into one of the three attached routes (1, 2, and 3) but not necessarily at the same time. In this example, call A reaches route 1, while calls B and C reach route 2. If you pay attention to the form of the figure used for routes, you will recognize the cylinder that we used for filters.

The actual class used is TemplateRoute in the same package, which defines the next Restlet like all filters, but also a score(Request, Response) method. As its name implies, this method computes an affinity score based on the matching of the URI of the target resource (contained in the Request#resourceRef property) with a given URI template. An example of URI template is http://localhost:8182/accounts/{accountId}.

Restlet router handling concurrent calls
Figure 4.
Router handling three concurrent calls and dispatching them to attached routes

In order to illustrate what we just learned, let's run a simple example based on the Tracer and Blocker filters that we previously developed and attach them to a Router instance (see Listing 4).

Listing 4. Illustrating URI-based routing
@@Override
    public Restlet createInboundRoot() {
        Tracer tracer = new Tracer(getContext());

        Blocker blocker = new Blocker(getContext());
        blocker.getBlockedAddresses().add("127.0.0.1");
        blocker.setNext(tracer);

        Router router = new Router(getContext());
        router.attach("http://localhost:8182/", tracer);
        router.attach("http://localhost:8182/accounts/", tracer);
        router.attach("http://localhost:8182/accounts/{accountId}", blocker);

        return router;
    }

In this scenario, we create two filters, one Tracer instance and one Blocker instance pointing to the tracer. Then, based on URI templates, we define which filter will be invoked when the request's target URI matches a given route. Note that TemplateRoute instance doesn't need to be explicitly created; instead, we can rely on the handy attach(String, Restlet) method. Let's start our updated application and test a few URIs in our browser, as detailed in Table 1.

Table 1. Results of a routing example.
URI retrieved Result observed
http://localhost:8182/ Trace results are displayed
http://localhost:8182/?param=value Trace results are displayed, including the query string
http://localhost:8182/123 Error: "The server has not found anything matching the request URI"
http://localhost:8182/accounts/ Trace results are displayed
http://localhost:8182/accounts/123 Error: "Your IP address was blocked"

One of the nice features of the Router and, especially, the TemplateRoute is that the URI variables are automatically extracted and stored in the request's attributes map. In our last example URI, the string 123 corresponding to the {accountId} variable in the URI template http://localhost:8182/accounts/{accountId} will be stored in an attribute named accountId. This will be very convenient when we actually handle the call in a ServerResource subclass to retrieve the underlying domain object from the database.

In some cases, it is necessary to customize the way the URI matching happens. The Router class has a full range of options to take care of this need, such as a defaultMatchingMode property indicating if only the beginning of the URI must match (see the org.restlet.routing.Template#STARTS_WITH constant) or if all the URI must match (see the EQUALS constant). The latter case is the default mode since Restlet 2.0, so be careful if you upgrade from the previous version.

Another property is defaultMatchQuery, which indicates if the query string at the end of target URIs (the characters after the optional "?" character) should be considered during matching. By default, its value is false as the order of query parameters is rarely enforceable. Restlet developers tend to prefer handling them inside the resource classes. Keep also in mind that it is possible to customize the characters that are matched by the URI template variables leveraging the Template and Variable classes.

Also, when the router evaluates each route, it is possible to define when it considers a given route as the one to select and pass the call to. This is the purpose of the routingMode property, which can have one of the following values (those constants are defined in the Router class):

  • Best match
  • First match (default since Restlet 2.0)
  • Last match
  • Random match
  • Round robin
  • Custom

This opens the way for many interesting usages, such as writing a load-balancer of calls to several instances of a back-end web service. But there is more: in addition to Restlet instances, you can also attach server resource classes directly to a Router using an attach(String, Class) method, as illustrated in Figure 5. But what happen exactly inside this method?

Restlet router dispatching concurrent calls
Figure 5.
Router dispatching concurrent calls to three target server resources

First, a TemplateRoute instance is created and added to the list of routes of the router, and then a special Restlet subclass called org.restlet.resource.Finder is attached to the route. This class will store the class name of the target resource and create a new instance of it for each incoming call. This is very similar to the factory design pattern. With the introduction of the Finder class, we see how the transition from the user routing layer to the resource handling layer will happen.

Summary

In this article, we learned how Restlet applications are structured in three concentric layers and the detailed design of each layer. In addition, we explored the Restlet routing system, which allows the pre-processing and post-processing of both inbound and outbound calls with the Filter class and the dispatching of calls to attached routes by the Router class.

About the Author

Jerome Louvel is the co-founder of Noelios Technologies and the creator of Restlet.

Thierry Boileau is the co-founder of Noelios Technologies and has been a core developer of the Restlet Framework since 2006.



Page 2 of 2



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel