package org.dynmap.servlet; import java.io.IOException; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletResponse; @SuppressWarnings("serial") public class MainServlet extends HttpServlet { public static class Header { public String name; public String value; public Header(String name, String value) { this.name = name; this.value = value; } } private static class Registration { public String pattern; public HttpServlet servlet; public Registration(String pattern, HttpServlet servlet) { this.pattern = pattern; this.servlet = servlet; } } List<Registration> registrations = new LinkedList<Registration>(); public List<Header> customHeaders = new LinkedList<Header>(); public void addServlet(String pattern, HttpServlet servlet) { registrations.add(new Registration(pattern, servlet)); } @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { HashMap<String, Object> properties = new HashMap<String, Object>(); String path = req.getPathInfo(); for(Header header : customHeaders) { resp.setHeader(header.name, header.value); } Registration bestMatch = null; String bestMatchPart = null; HashMap<String, Object> bestProperties = null; for (Registration r : registrations) { String matchingPart = match(r.pattern, path, properties); if (matchingPart != null) { if (bestMatchPart == null || bestMatchPart.length() < matchingPart.length()) { bestMatch = r; bestMatchPart = matchingPart; bestProperties = properties; properties = new HashMap<String, Object>(); } } } if (bestMatch == null) { resp.sendError(404); } else { String leftOverPath = path.substring(bestMatchPart.length()); HttpServletRequest newreq = new RequestWrapper(req, leftOverPath); for(String key : bestProperties.keySet()) { newreq.setAttribute(key, bestProperties.get(key)); } bestMatch.servlet.service(newreq, resp); } } public String match(String pattern, String path, Map<String, Object> properties) { int patternStart = 0; int pathStart = 0; while (patternStart < pattern.length()) { if (pattern.charAt(patternStart) == '{') { // Found a variable. int endOfVariable = pattern.indexOf('}', patternStart+1); String variableName = pattern.substring(patternStart+1, endOfVariable); int endOfSection = indexOfAny(path, new char[] { '/', '?' }, pathStart); if (endOfSection < 0) { endOfSection = path.length(); } String variableValue = path.substring(pathStart, endOfSection); // Store variable. properties.put(variableName, variableValue); patternStart = endOfVariable+1; pathStart = endOfSection; } else { int endOfLiteral = pattern.indexOf('{', patternStart); if (endOfLiteral < 0) { endOfLiteral = pattern.length(); } String literal = pattern.substring(patternStart, endOfLiteral); int endOfPathLiteral = pathStart + literal.length(); if (endOfPathLiteral > path.length()) { return null; } String matchingLiteral = path.substring(pathStart, endOfPathLiteral); if (!literal.equals(matchingLiteral)) { return null; } patternStart = endOfLiteral; pathStart = endOfPathLiteral; } } // Return the part of the url that matches the pattern. (if the pattern does not contain any variables, this will be equal to the pattern) return path.substring(0, pathStart); } private int indexOfAny(String s, char[] cs, int startIndex) { for(int i = startIndex; i < s.length(); i++) { char c = s.charAt(i); for(int j = 0; j < cs.length; j++) { if (c == cs[j]) { return i; } } } return -1; } class RequestWrapper extends HttpServletRequestWrapper { String pathInfo; public RequestWrapper(HttpServletRequest request, String pathInfo) { super(request); this.pathInfo = pathInfo; } @Override public String getPathInfo() { return pathInfo; } } }