package org.webpieces.plugins.json; import java.nio.charset.StandardCharsets; import java.util.concurrent.CompletableFuture; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.webpieces.httpparser.api.dto.KnownStatusCode; import org.webpieces.router.api.actions.Action; import org.webpieces.router.api.actions.RenderContent; import org.webpieces.router.api.dto.MethodMeta; import org.webpieces.router.api.exceptions.ClientDataError; import org.webpieces.router.api.exceptions.NotFoundException; import org.webpieces.router.api.routing.RouteFilter; import org.webpieces.router.impl.compression.MimeTypes.MimeTypeResult; import org.webpieces.util.filters.Service; import org.webpieces.util.logging.Logger; import org.webpieces.util.logging.LoggerFactory; public abstract class JacksonCatchAllFilter extends RouteFilter<JsonConfig> { private static final Logger log = LoggerFactory.getLogger(JacksonCatchAllFilter.class); public static final MimeTypeResult MIME_TYPE = new MimeTypeResult("application/json", StandardCharsets.UTF_8); private Boolean isNotFoundFilter; private Pattern pattern; @Override public CompletableFuture<Action> filter(MethodMeta meta, Service<MethodMeta, Action> nextFilter) { if(isNotFoundFilter) return createNotFoundResponse(nextFilter, meta); return nextFilter.invoke(meta).handle((a, t) -> translateFailure(a, t)); } @Override public void initialize(JsonConfig config) { this.isNotFoundFilter = config.isNotFoundFilter(); this.pattern = config.getFilterPattern(); } private Action translateFailure(Action action, Throwable t) { if(t != null) { if(t instanceof ClientDataError) { return translate((ClientDataError)t); } else if (t instanceof NotFoundException) { return createNotFound(); } log.error("Internal Server Error", t); return translateError(t); } else { return action; } } private RenderContent translateError(Throwable t) { byte[] content = translateServerError(t); return new RenderContent(content, KnownStatusCode.HTTP_500_INTERNAL_SVR_ERROR.getCode(), MIME_TYPE); } private RenderContent translate(ClientDataError t) { byte[] content = translateClientError(t); return new RenderContent(content, KnownStatusCode.HTTP_400_BADREQUEST.getCode(), MIME_TYPE); } private CompletableFuture<Action> createNotFoundResponse(Service<MethodMeta, Action> nextFilter, MethodMeta meta) { Matcher matcher = pattern.matcher(meta.getCtx().getRequest().relativePath); if(!matcher.matches()) return nextFilter.invoke(meta); return CompletableFuture.completedFuture( createNotFound() ); } private Action createNotFound() { byte[] content = createNotFoundJsonResponse(); return new RenderContent(content, KnownStatusCode.HTTP_404_NOTFOUND.getCode(), MIME_TYPE); } protected abstract byte[] translateServerError(Throwable t); protected abstract byte[] translateClientError(ClientDataError t); /** * If you really want, return null and the filter will return the 404 html instead of * json if you really want */ protected abstract byte[] createNotFoundJsonResponse(); }