public interface Middleware {

	/**
	 * This method is called by {@link Jogger} when a request arrives. Notice that the implementation has to call 
	 * {@link MiddlewareChain#next} to execute the next middlewares.
	 * 
	 * @param request the Jogger HTTP request.
	 * @param response the Jogger HTTP response.
	 * @param chain an object used to call the next middleware.
	 * @throws Exception
	 */
	void handle(Request request, Response response, MiddlewareChain chain) throws Exception;
	
} public interface MiddlewareChain {

	/**
	 * Calls the next middleware.
	 * 
	 * @throws Exception
	 */
	void next() throws Exception;
	
} public class Path {

	/**
	 * The regular expression to find holders in a path (e.g. {userId}).
	 */
	public static final String VAR_REGEXP = "\\{([^{}]+)\\}";

	public static final String VAR_REPLACE = "([^#/?]+)";

	public static String fixPath(String path) {
		if (path == null) {
			return "/";
		}

		if (!path.startsWith("/")) {
			path = "/" + path;
		}

		if (path.length() > 1 && path.endsWith("/")) {
			path = path.substring(0, path.length() - 1);
		}

		return path;
	}

} public interface Request {

	String getHost();

	/**
	 * Returns the full URL including scheme, host, port, path and query string.
	 *
	 * @return a String object with the URL.
	 */
	String getUrl();

	/**
	 * Retrieves the path that was requested without the context path - if any. For example, if the URL is
	 * "http://localhost:8080/app/users/1", the path would be "/users/1".
	 *
	 * @return a String object with the path of the request.
	 */
	String getPath();

	/**
	 * Retrieves the path variables. Path variables are wildcards that you can add to the url in the routes.config
	 * file.
	 *
	 * @return a Map<String,String> object with the path variables.
	 */
	Map<String,String> getPathVariables();

	/**
	 * Retrieves the value of a path variable.
	 *
	 * @param name the name of the path variable.
	 *
	 * @return a String object. Null if it doesn't exists.
	 */
	String getPathVariable(String name);

	/**
	 * Retrieves the raw query string part of the URL.
	 *
	 * @return a String object with the query string part of the URL. An empty String if there is no query string.
	 */
	String getQueryString();

	/**
	 * Retrieves the request parameters.
	 *
	 * @return a Map<String,String> object with the request parameters.
	 */
	Map<String,String> getParameters();

	/**
	 * Retrieves the value of a request parameter.
	 *
	 * @param name the name of the parameter
	 *
	 * @return a String object. Null if it doesn't exists.
	 */
	String getParameter(String name);

	/**
	 * Returns the HTTP method of the request.
	 *
	 * @return a String object with the HTTP method.
	 */
	String getMethod();

	String getRemoteAddress();

	String getContentType();

	int getPort();

	boolean isSecure();

	/**
	 * Tells whether the request was done using an AJAX call or not.
	 *
	 * @return true if this was an AJAX call, false otherwise.
	 */
	boolean isAjax();

	Map<String,Cookie> getCookies();

	/**
	 * Retrieves the {@link Cookie} with the specified name.
	 *
	 * @param name the name of the cookie to be retrieved.
	 *
	 * @return itself for method chaining.
	 */
	Cookie getCookie(String name);

	Map<String,String> getHeaders();

	String getHeader(String name);

	/**
	 * Retrieves the files from the request (if any).
	 *
	 * @return an array of {@link FileItem} objects or an empty array if no files.
	 */
	FileItem[] getFiles();

	/**
	 * Returns an object that will allow us to retrieve the body in multiple ways.
	 *
	 * @return a {@link BodyParser} implementation.
	 */
	BodyParser getBody();
	
	void setRoute(Route route);

	/**
	 * This is what we returned when the {@link Request#getBody()} is called. Provides convenient methods to parse the
	 * request body.
	 *
	 * @author German Escobar
	 */
	interface BodyParser {

		/**
		 * Returns the body of the request as a string.
		 *
		 * @return a String object with the body.
		 */
		String asString();

		/**
		 * @return the body as an InputStream.
		 */
		InputStream asInputStream();

	}

} public interface Response {

	int OK = 200;
	int CREATED = 201;
	int ACCEPTED = 202;
	int PARTIAL_INFO = 203;
	int NO_RESPONSE = 204;
	int MOVED = 301;
	int FOUND = 302;
	int METHOD = 303;
	int NOT_MODIFIED = 304;
	int BAD_REQUEST = 400;
	int UNAUTHORIZED = 401;
	int PAYMENT_REQUIRED = 402;
	int FORBIDDEN = 403;
	int NOT_FOUND = 404;
	int CONFLICT = 409;
	int INTERNAL_ERROR = 500;
	int NOT_IMPLEMENTED = 501;
	int OVERLOADED = 502;
	int GATEWAY_TIMEOUT = 503;

	int getStatus();

	/**
	 * Sets the status of the response to the received argument.
	 *
	 * @param status the status to set to the response.
	 *
	 * @return itself for method chaining.
	 */
	Response status(int status);

	/**
	 * Sets the status of the response to 400 - Bad Request.
	 *
	 * @return itself for method chaining.
	 */
	Response badRequest();

	/**
	 * Sets the status of the response to 401 - Unauthorized.
	 *
	 * @return itself for method chaining.
	 */
	Response unauthorized();

	/**
	 * Sets the status of the response to 404 - Not Found.
	 *
	 * @return itself for method chaining.
	 */
	Response notFound();

	/**
	 * Sets the status of the response to 409 - Conflict
	 *
	 * @return itself for method chaining.
	 */
	Response conflict();

	String getContentType();

	Response contentType(String contentType);

	String getHeader(String name);

	Response setHeader(String name, String value);

	/**
	 * Sets a cookie.
	 *
	 * @param cookie the {@link Cookie} to be set.
	 *
	 * @return itself for method chaining.
	 */
	Response setCookie(Cookie cookie);

	/**
	 * Removes a cookie.
	 *
	 * @param cookie the name of the cookie to be removed.
	 *
	 * @return itself for method chaining.
	 */
	Response removeCookie(Cookie cookie);

	Map<String,Object> getAttributes();

	Response setAttribute(String name, Object object);

	/**
	 * Writes an HTML string into the response.
	 *
	 * @param output the output code to write in the response.
	 *
	 * @return itself for method chaining.
	 */
	Response write(String output);

	/**
	 * Writes an InputStream into the response.
	 *
	 * @param asset the {@link Asset} to write in the response.
	 *
	 * @return itself for method chaining.
	 */
	Response write(Asset asset);

	/**
	 * Renders the specified template with no additional attributes (besides those already in the response)
	 *
	 * @param templateName the name of the template to be rendered.
	 *
	 * @return itself for method chaining.
	 * @throws TemplateException
	 */
	Response render(String templateName) throws TemplateException;

	/**
	 * Renders the specified template with the specified attributes (and those already in the response). If an
	 * attribute with the same name already exists in the response it will be overriden.
	 *
	 * @param templateName the name of the template to be rendered.
	 * @param attributes a map of attributes to be passed to the view.
	 *
	 * @return itself for method chaining.
	 * @throws TemplateException
	 */
	Response render(String templateName, Map<String,Object> attributes) throws TemplateException;

	/**
	 * Sends a redirect.
	 *
	 * @param path the path to which the request is redirected.
	 */
	void redirect(String path);
	
	boolean isWritten();

} public enum HttpMethod {
	GET,
	POST,
	PUT,
	DELETE,
	OPTIONS,
	HEAD,
	PATCH
} public interface Action {

	/**
	 * Retrieves an annotation from the action if the annotation is present.
	 *
	 * @param <A> the type of the annotation to be retrieved.
	 * @param annotation the class of the annotation to be retrieved.
	 *
	 * @return a java.lang.annotation.Annotation object or null if not found.
	 */
	<A extends Annotation> A getAnnotation(Class<A> annotation);
} public interface Controller {

	/**
	 * Retrieves an annotation from the controller if the annotation is present.
	 *
	 * @param <A> the type of the annotation to be retrieved.
	 * @param annotationClass the class of the annotation to be retrieved.
	 *
	 * @return a java.lang.annotation.Annotation object or null if not found.
	 */
	<A extends Annotation> A getAnnotation(Class<A> annotationClass);

} public interface Interceptor {

	/**
	 * This method is called when a matching request is received. Implementations of this method are responsible of
	 * calling the {@link InterceptorExecution#proceed()} method to continue with the execution of the request unless it
	 * actually wants to stop the execution (in which case it should set the response in the controller)
	 *
	 * @param request
	 * @param response
	 * @param execution
	 *
	 * @throws Exception
	 */
	void intercept(Request request, Response response, InterceptorExecution execution) throws Exception;

} public class InterceptorEntry {

	private Interceptor interceptor;

	private String[] paths;

	public InterceptorEntry(Interceptor interceptor, String... paths) {
		this.interceptor = interceptor;
		this.paths = paths;
	}

	public Interceptor getInterceptor() {
		return interceptor;
	}

	public String[] getPaths() {
		return paths;
	}

} public interface InterceptorExecution {

	/**
	 * Causes the next interceptor (or controller if there are no more interceptors) to be invoked.
	 *
	 * @throws Exception
	 */
	void proceed() throws Exception;

	/**
	 * Retrieves the controller. Useful to retrieve information from the controller.
	 *
	 * @return a {@link Controller} implementation.
	 */
	Controller getController();

	/**
	 * Retrieves the action. Useful to retrieve information from the action.
	 *
	 * @return a {@link Action} implementation.
	 */
	Action getAction();

} public final class Preconditions {

	/**
	 * Hide constructor.
	 */
	private Preconditions() {}

	/**
	 * Checks that an object is not null.
	 *
	 * @param object the object to be tested
	 * @param message the message for the exception in case the object is null.
	 *
	 * @throws IllegalArgumentException if the object is null.
	 */
	public static void notNull(Object object, String message) throws IllegalArgumentException {
		if (object == null) {
			throw new IllegalArgumentException("A precondition failed: " + message);
		}
	}

	/**
	 * Checks that a string is not null or empty.
	 *
	 * @param value the string to be tested.
	 * @param message the message for the exception in case the string is empty.
	 *
	 * @throws IllegalArgumentException if the string is empty.
	 */
	public static void notEmpty(String value, String message) throws IllegalArgumentException {
		if (value == null || "".equals(value.trim())) {
			throw new IllegalArgumentException("A precondition failed: " + message);
		}
	}
}
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import com.elibom.jogger.Middleware;
import com.elibom.jogger.MiddlewareChain;
import com.elibom.jogger.http.Path;
import com.elibom.jogger.http.Request;
import com.elibom.jogger.http.Response;
import com.elibom.jogger.middleware.router.Route.HttpMethod;
import com.elibom.jogger.middleware.router.interceptor.Action;
import com.elibom.jogger.middleware.router.interceptor.Controller;
import com.elibom.jogger.middleware.router.interceptor.Interceptor;
import com.elibom.jogger.middleware.router.interceptor.InterceptorEntry;
import com.elibom.jogger.middleware.router.interceptor.InterceptorExecution;
import com.elibom.jogger.util.Preconditions;
package com.elibom.jogger.middleware.router;



/**
 * This middleware routes requests through <em>interceptors</em> and <em>controller actions</em> using the <em>routes</em> 
 * provided by the user.
 * 
 * @author German Escobar
 */
public class RouterMiddleware implements Middleware {
	
	/**
	 * The list of routes.
	 */
	private List<Route> routes = new CopyOnWriteArrayList<Route>();

	/**
	 * The list of interceptors.
	 */
	private List<InterceptorEntry> interceptors = new CopyOnWriteArrayList<InterceptorEntry>();
	
	@Override
	public void handle(Request request, Response response, MiddlewareChain chain) throws Exception {
		Route route = getRoute(request.getMethod(), request.getPath());
		if (route == null) {
			chain.next();
			return;
		}
		
		request.setRoute(route);
		response.status(Response.OK);
		
		// load the interceptors of the request
		List<Interceptor> requestInterceptors = getInterceptors(request.getPath());