code: public boolean match(String[] requestPathTokens, Map<String, String> params) {
  		if (tokens.length == requestPathTokens.length) {
  			for (int i = 0; i < tokens.length; i++) {
  				String key = tokens[i];
  				String value = requestPathTokens[i];
  
  				if (key.length() > 0 && key.charAt(0) == ':') {
  					// This is a placeholder
  					params.put(key.substring(1), value);
  				} else if (!key.equals(value)) {
  					// This is a constant
  					return false;
  				}
  			}
  
  			return true;
  		}
  
  		if (tokens.length > 0 &&
  			tokens[tokens.length - 1].equals(":*") &&
  			tokens.length <= requestPathTokens.length) {
  			// The first part
  			for (int i = 0; i < tokens.length - 2; i++) {
  				String key = tokens[i];
  				String value = requestPathTokens[i];
  
  				if (key.length() > 0 && key.charAt(0) == ':') {
  					// This is a placeholder
  					params.put(key.substring(1), value);
  				} else if (!key.equals(value)) {
  					// This is a constant
  					return false;
  				}
  			}
  
  			// The last :* part
  			StringBuilder b = new StringBuilder(requestPathTokens[tokens.length - 1]);
  			for (int i = tokens.length; i < requestPathTokens.length; i++) {
  				b.append('/');
  				b.append(requestPathTokens[i]);
  			}
  			params.put("*", b.toString());
  
  			return true;
  		}
  
  		return false;
  	}
docs: {@code params} will be updated with params embedded in the request path.
  
  <p>This method signature is designed so that {@code requestPathTokens} and {@code params}
  can be created only once then reused, to optimize for performance when a
  large number of path patterns need to be matched.
  
  @return {@code false} if not matched; in this case params should be reset