package io.myweb;
import java.io.IOException;
import java.util.List;
import io.myweb.http.HttpException;
import io.myweb.http.HttpInternalErrorException;
import io.myweb.http.HttpNotFoundException;
import io.myweb.http.Method;
import io.myweb.http.MimeTypes;
import io.myweb.http.Request;
import io.myweb.http.Response;
public class RequestProcessor {
private static final String INDEX_HTML = "/index.html";
private static final String SERVICES_JSON = "/services.json";
private final List<? extends Endpoint> endpoints;
private final List<Filter> filters;
public RequestProcessor(List<? extends Endpoint> endpoints, List<Filter> filters) {
this.endpoints = endpoints;
this.filters = filters;
}
public Response processRequest(Request request) throws HttpException, IOException {
String uri = request.getURI().toString();
String effectiveUri = uri;
Response response = null;
while (response == null) {
Endpoint endpoint = findEndpoint(request.getMethod(), effectiveUri);
// TODO think how to handle better default requests (like "/index.html" on "/")
if (("/".equals(uri) || "".equals(uri)) && endpoint == null) {
effectiveUri = INDEX_HTML;
endpoint = findEndpoint(request.getMethod(), effectiveUri);
}
if (("/".equals(uri) || "".equals(uri)) && endpoint == null) {
effectiveUri = SERVICES_JSON;
endpoint = findEndpoint(request.getMethod(), effectiveUri);
}
if (endpoint == null) {
throw new HttpNotFoundException("Not found " + uri);
} else {
try {
Request filteredRequest = filterBefore(effectiveUri, request);
if (filteredRequest.isRedirected()) {
request = filteredRequest.withRedirection(null);
continue;
}
response = endpoint.invoke(effectiveUri, filteredRequest);
response = filterAfter(effectiveUri, response);
response = ensureProperContentType(response, endpoint.produces());
} catch (Throwable t) {
if (response != null) response.onError(t);
if (t instanceof HttpException) throw (HttpException) t;
if (t instanceof IOException) throw (IOException) t;
throw new HttpInternalErrorException(t.getMessage(), t);
}
}
}
return response;
}
private Response ensureProperContentType(Response response, String defaultContentType) {
String contentType = response.getContentType();
if (defaultContentType == null) defaultContentType = MimeTypes.MIME_TEXT_HTML;
if (contentType == null) contentType = defaultContentType;
// if content type is text, make sure charset is specified
if (!contentType.contains("charset=") && isTextContent(contentType)) {
contentType = contentType + "; charset=" + response.getCharset();
}
return response.withContentType(contentType);
}
private static boolean isTextContent(String content) {
return content.contains("text") || content.contains("xml") || content.contains("json");
}
private Response filterAfter(String effectiveUri, Response response) {
for (Filter filter: filters) {
if (filter.matchAfter(effectiveUri)) response = filter.after(response);
}
return response;
}
private Request filterBefore(String effectiveUri, Request request) {
for (Filter filter: filters) {
if (filter.matchBefore(effectiveUri)) {
request = filter.before(request);
if (request.isRedirected()) break;
}
}
return request;
}
private Endpoint findEndpoint(Method method, String uri) {
for (Endpoint endpoint : endpoints) {
if (endpoint.match(method, uri)) {
return endpoint;
}
}
return null;
}
}