Peter Morris Peter Morris - 3 months ago 6
Scala Question

How do I extract the value of a route variable from the URL in a Scala-Play app?

I am writing a module for the Play Framework. In part of my module I have the following code

abstract class SecurityFiltering extends GlobalSettings{
override def onRequestReceived(request: RequestHeader) = {
play.Logger.debug("onRequestReceived: " + request)
super.onRequestReceived(request)
}

override def doFilter(next: RequestHeader => Handler): (RequestHeader => Handler) = {
request => {
play.Logger.debug("doFilter: " + request)
super.doFilter(next)(request)
}
}

override def onRouteRequest(request: RequestHeader): Option[Handler] = {
play.Logger.debug("onRouteRequest: " + request)
super.onRouteRequest(request)
}
}


In the doFilter method I am able to determine the following useful information

ROUTE_PATTERN = /x/$name<[^/]+>/$age<[^/]+>
ROUTE_CONTROLLER = controllers.Application
ROUTE_ACTION_METHOD = tester
ROUTE_VERB = GET
path = /x/hello


What I need in addition to this is the values for the named parts of the URL before the QueryString. So given the following route in my test application I need to retrieve Name=Pete and Age=41

localhost:9000/x/Pete/41


There is surely some code in the Play Framework which already does this but I am unable to find it. Can someone suggest how I achieve this goal, or point me at which Play class extracts these values?

Answer

package models.com.encentral.tattara.web.util;

 import java.util.HashMap;
 import java.util.Map;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;


 public class RouteExtractor {

//something like "/foo/$id<[^/]+>/edit/$james<[^/]+>"
private String routePattern;
private String path;

//something like /$id<[^/]+>
private static final String INDEX_PATTERN = "\\$(.+?)\\<\\[\\^\\/\\]\\+\\>";

public RouteExtractor(String routePattern, String path) {

    this.routePattern = routePattern;
    this.path = path;
}

private Map<Integer, String> extractPositions() {
    Pattern pattern = Pattern.compile(INDEX_PATTERN);
    Matcher matcher = pattern.matcher(this.routePattern);
    Map<Integer, String> results = new HashMap<>();
    int index = 0;
    while (matcher.find()) {
        results.put(index++, matcher.group(1));
    }
    return results;
}

private String replaceRoutePatternWithGroup() {
    Pattern pattern = Pattern.compile(INDEX_PATTERN);
    Matcher matcher = pattern.matcher(this.routePattern);
    return matcher.replaceAll("([^/]+)");
}

public Map<String, String> extract() {
    Pattern pattern = Pattern.compile(this.replaceRoutePatternWithGroup());
    Matcher matcher = pattern.matcher(this.path);
    final Map<String, String> results = new HashMap<>();
    if (matcher.find()) {
        this.extractPositions().entrySet().stream().forEach(s -> {
            results.put(s.getValue(), matcher.group(s.getKey() + 1));
        });
    }
    return results;
}

}