package io.github.ibuildthecloud.gdapi.servlet; import io.cattle.platform.util.type.CollectionUtils; import io.github.ibuildthecloud.gdapi.context.ApiContext; import io.github.ibuildthecloud.gdapi.factory.SchemaFactory; import io.github.ibuildthecloud.gdapi.id.IdFormatter; import io.github.ibuildthecloud.gdapi.model.Schema; import io.github.ibuildthecloud.gdapi.request.ApiRequest; import io.github.ibuildthecloud.gdapi.request.handler.ApiRequestHandler; import io.github.ibuildthecloud.gdapi.request.parser.ApiRequestParser; import io.github.ibuildthecloud.gdapi.server.model.ApiServletContext; import io.github.ibuildthecloud.gdapi.util.ExceptionUtils; import io.github.ibuildthecloud.gdapi.version.Versions; import java.io.EOFException; import java.io.IOException; import java.net.URL; import java.util.List; import java.util.Map; import javax.inject.Inject; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ApiRequestFilterDelegate { public static final String SCHEMAS_HEADER = "X-API-Schemas"; private static final Logger log = LoggerFactory.getLogger(ApiRequestFilterDelegate.class); @Inject Versions versions; ApiRequestParser parser; List<ApiRequestHandler> handlers; boolean throwErrors = false; Map<String, SchemaFactory> schemaFactories; IdFormatter idFormatter; public ApiContext doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) { chain.doFilter(request, response); return null; } HttpServletRequest httpRequest = (HttpServletRequest)request; HttpServletResponse httpResponse = (HttpServletResponse)response; String version = parser.parseVersion(httpRequest.getServletPath()); SchemaFactory schemaFactory = schemaFactories.get(version); ApiRequest apiRequest = new ApiRequest(new ApiServletContext(httpRequest, httpResponse, chain), schemaFactory); apiRequest.setAttribute("requestStartTime", System.currentTimeMillis()); ApiContext context = null; try { context = ApiContext.newContext(); context.setApiRequest(apiRequest); if (idFormatter != null) { context.setIdFormatter(idFormatter); } if (!parser.parse(apiRequest)) { chain.doFilter(httpRequest, httpResponse); return null; } URL schemaUrl = null; if (schemaFactory == null) { // Not a valid version SchemaFactory defaultFactory = schemaFactories.get(versions.getLatest()); if (apiRequest.getVersion() == null) { apiRequest.setVersion(versions.getRootVersion()); } else { apiRequest.setVersion(versions.getLatest()); } apiRequest.setSchemaFactory(defaultFactory); schemaUrl = ApiContext.getUrlBuilder().resourceCollection(Schema.class); } else { schemaUrl = ApiContext.getUrlBuilder().resourceCollection(Schema.class); } if (schemaUrl != null) { httpResponse.setHeader(SCHEMAS_HEADER, schemaUrl.toExternalForm()); } Throwable currentError = null; for (ApiRequestHandler handler : handlers) { try { if (currentError == null) { handler.handle(apiRequest); } else { if (handler.handleException(apiRequest, currentError)) { currentError = null; } } } catch (EOFException e) { throw e; } catch (Throwable t) { currentError = t; apiRequest.getExceptions().add(t); try { if (handler.handleException(apiRequest, currentError)) { currentError = null; } } catch (Throwable t1) { currentError = t1; } } } if (currentError != null) { throw currentError; } } catch (EOFException e) { log.trace("Caught EOFException, ignoring", e); throw e; } catch (Throwable t) { log.error("Unhandled exception in API for request [{}]", apiRequest, t); if (throwErrors) { ExceptionUtils.rethrowRuntime(t); ExceptionUtils.rethrow(t, IOException.class); ExceptionUtils.rethrow(t, ServletException.class); throw new ServletException(t); } else { if (!httpResponse.isCommitted()) { httpResponse.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } } } finally { apiRequest.commit(); ApiContext.remove(); } return context; } public ApiRequestParser getParser() { return parser; } @Inject public void setParser(ApiRequestParser parser) { this.parser = parser; } public boolean isThrowErrors() { return throwErrors; } public void setThrowErrors(boolean throwErrors) { this.throwErrors = throwErrors; } public List<ApiRequestHandler> getHandlers() { return handlers; } @Inject public void setHandlers(List<ApiRequestHandler> handlers) { this.handlers = CollectionUtils.orderList(ApiRequestHandler.class, handlers); } public IdFormatter getIdFormatter() { return idFormatter; } public void setIdFormatter(IdFormatter idFormatter) { this.idFormatter = idFormatter; } public Map<String, SchemaFactory> getSchemaFactories() { return schemaFactories; } public void setSchemaFactories(Map<String, SchemaFactory> schemaFactories) { this.schemaFactories = schemaFactories; } }