private PatternBinding getBinding(String nameOrUriPattern) { Collection<List<PatternBinding>> values = bindingsCache.values(); Route route; for (List<PatternBinding> bindings : values) { for (PatternBinding binding : bindings) { route = binding.getRoute(); if (nameOrUriPattern.equals(route.getName()) || nameOrUriPattern.equals(route.getUriPattern())) { return binding; } } } return null; }
private void addPattern( String verb, String input, Middleware[] handler, List<PatternBinding> bindings) { // We need to search for any :<token name> tokens in the String and replace them with named // capture groups Matcher m = Pattern.compile(":([A-Za-z][A-Za-z0-9_]*)").matcher(input); StringBuffer sb = new StringBuffer(); Set<String> groups = new HashSet<>(); while (m.find()) { String group = m.group().substring(1); if (groups.contains(group)) { throw new IllegalArgumentException( "Cannot use identifier " + group + " more than once in pattern string"); } m.appendReplacement(sb, "(?<$1>[^\\/]+)"); groups.add(group); } m.appendTail(sb); // ignore tailing slash if not part of the input, not really REST but common on other frameworks if (sb.charAt(sb.length() - 1) != '/') { sb.append("\\/?$"); } Pattern regex = Pattern.compile(sb.toString()); boolean exists = false; // verify if the binding already exists, if yes add to it for (PatternBinding pb : bindings) { if (pb.isFor(input)) { exists = true; pb.addMiddleware(handler); break; } } if (!exists) { PatternBinding binding = new PatternBinding(hashCode(), verb, input, regex, groups, handler); bindings.add(binding); } // also pass the vertx object to the routes for (Middleware h : handler) { if (!h.isInitialized() && isInitialized()) { h.init(yoke, mount); } } }
private Map<String, String> getParameters(PatternBinding binding, String requestUri) { if (binding.getParameterNames().isEmpty()) { return Collections.EMPTY_MAP; } Map<String, String> parameters = new HashMap<>(); List<String> parameterNames = binding.getParameterNames(); Matcher matcher = binding.getPattern().matcher(requestUri); matcher.matches(); int groupCount = matcher.groupCount(); if (groupCount > 0) { for (int i = 0; i < parameterNames.size(); i++) { parameters.put(parameterNames.get(i), matcher.group(i + 1)); } } return parameters; }
@Override public List<RouteMatch> findRoutes(String requestUri, String requestMethod) { log.trace("Finding route matches for {} '{}'", requestMethod, requestUri); List<RouteMatch> routeMatches = new ArrayList<>(); List<PatternBinding> bindings = getBindings(requestMethod); for (Route route : routes) { // to preserve the routes order for (PatternBinding binding : bindings) { if (route.equals(binding.getRoute()) && binding.getPattern().matcher(requestUri).matches()) { // TODO improve (it's possible to have the same uriPattern for many routes => same // parameters) routeMatches.add(new RouteMatch(route, getParameters(binding, requestUri))); break; } } } log.debug("Found {} route matches for {} '{}'", routeMatches.size(), requestMethod, requestUri); return routeMatches; }
public void visitPatternsSpec(PatternsSpec aPatternsSpec) { out.print("PatternsSpec("); ++indentLevel; out.println(); printIndent(); out.print("bindings="); if (aPatternsSpec.getBindings() != null) { out.println("["); ++indentLevel; for (PatternBinding e : aPatternsSpec.getBindings()) { printIndent(); e.visit(this); } --indentLevel; printIndent(); out.println("]"); } else { out.println("null"); } --indentLevel; printIndent(); out.println(")"); }
private void addRegEx( String verb, Pattern regex, Middleware handler[], List<PatternBinding> bindings) { boolean exists = false; // verify if the binding already exists, if yes add to it for (PatternBinding pb : bindings) { if (pb.isFor(regex)) { pb.addMiddleware(handler); exists = true; break; } } if (!exists) { PatternBinding binding = new PatternBinding(hashCode(), verb, null, regex, null, handler); bindings.add(binding); } // also pass the vertx object to the routes for (Middleware h : handler) { if (!h.isInitialized() && isInitialized()) { h.init(yoke, mount); } } }
private String uriFor(PatternBinding binding, Map<String, Object> parameters) { String uri = binding.getRoute().getUriPattern(); List<String> parameterNames = binding.getParameterNames(); if (!parameters.keySet().containsAll(parameterNames)) { log.error( "You must provide values for all path parameters. {} vs {}", parameterNames, parameters.keySet()); } Map<String, Object> queryParameters = new HashMap<>(parameters.size()); for (Entry<String, Object> parameterPair : parameters.entrySet()) { boolean foundAsPathParameter = false; StringBuffer sb = new StringBuffer(); String buffer = String.format(VARIABLE_PART_PATTERN_WITH_PLACEHOLDER, parameterPair.getKey()); Pattern pattern = Pattern.compile(buffer); Matcher matcher = pattern.matcher(uri); while (matcher.find()) { String pathValue = parameterPair.getValue().toString(); matcher.appendReplacement(sb, pathValue); foundAsPathParameter = true; } matcher.appendTail(sb); uri = sb.toString(); if (!foundAsPathParameter) { queryParameters.put(parameterPair.getKey(), parameterPair.getValue()); } } // now prepare the query string for this url if we got some query params if (!queryParameters.isEmpty()) { // add remaining parameters as query parameters StringBuilder query = new StringBuilder(); Iterator<Entry<String, Object>> iterator = queryParameters.entrySet().iterator(); while (iterator.hasNext()) { Entry<String, Object> parameterEntry = iterator.next(); String parameterName = parameterEntry.getKey(); Object parameterValue = parameterEntry.getValue(); String encodedParameterValue = null; try { encodedParameterValue = URLEncoder.encode(parameterValue.toString(), PippoConstants.UTF8); } catch (UnsupportedEncodingException e) { throw new PippoRuntimeException( "Cannot encode the parameter value '" + parameterValue.toString() + "'", e); } query.append(parameterName).append("=").append(encodedParameterValue); if (iterator.hasNext()) { query.append("&"); } } uri += "?" + query; } return uri; }