@Override
public void route(RestxRequest restxRequest, final RestxResponse restxResponse) throws IOException {
logger.debug("<< {}", restxRequest);
Stopwatch stopwatch = Stopwatch.createStarted();
Monitor monitor = metrics.timer("<HTTP> " + restxRequest.getHttpMethod() + " " + restxRequest.getRestxPath()).time();
try {
Optional<RestxRouting.Match> m = routing.match(restxRequest);
if (!m.isPresent()) {
// no route matched
String path = restxRequest.getRestxPath();
StringBuilder sb = new StringBuilder()
.append("no restx route found for ")
.append(restxRequest.getHttpMethod()).append(" ").append(path).append("\n");
if (hasApiDocs()) {
sb.append("go to ").append(restxRequest.getBaseUri()).append("/@/ui/api-docs/")
.append(" for API documentation\n\n");
}
sb.append("routes:\n")
.append("-----------------------------------\n");
for (RestxRoute route : routing.getRoutes()) {
sb.append(route).append("\n");
}
sb.append("-----------------------------------");
restxResponse.setStatus(HttpStatus.NOT_FOUND);
restxResponse.setContentType("text/plain");
PrintWriter out = restxResponse.getWriter();
out.print(sb.toString());
} else {
MDC.put("restx.path", restxRequest.getRestxPath());
MDC.put("restx.method", restxRequest.getHttpMethod());
logger.debug("<< {}\nHANDLERS: {}", restxRequest, m.get().getMatches());
RestxContext context = new RestxContext(getMode(), new AbstractRouteLifecycleListener() {},
ImmutableList.copyOf(m.get().getMatches()));
RestxHandlerMatch match = context.nextHandlerMatch();
match.handle(restxRequest, restxResponse, context);
}
} catch (JsonProcessingException ex) {
logger.warn("request raised " + ex.getClass().getSimpleName(), ex);
restxResponse.setStatus(HttpStatus.BAD_REQUEST);
restxResponse.setContentType("text/plain");
PrintWriter out = restxResponse.getWriter();
if (restxRequest.getContentStream() instanceof BufferedInputStream) {
try {
JsonLocation location = ex.getLocation();
restxRequest.getContentStream().reset();
out.println(CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, ex.getClass().getSimpleName()) + "." +
" Please verify your input:");
List<String> lines = CharStreams.readLines(
new InputStreamReader(restxRequest.getContentStream()));
if (lines.isEmpty()) {
if ("application/x-www-form-urlencoded".equalsIgnoreCase(restxRequest.getContentType())) {
out.println("Body was considered as parameter due to Content-Type: " +
restxRequest.getContentType() + ". " +
"Setting your Content-Type to \"application/json\" may resolve the problem");
} else {
out.println("Empty body. Content-type was \"" + restxRequest.getContentType() + "\"");
}
} else {
out.println("<-- JSON -->");
for (int i = 0; i < lines.size(); i++) {
String line = lines.get(i);
out.println(line);
if (location != null && (i + 1 == location.getLineNr())) {
boolean farColumn = location.getColumnNr() > 80;
/*
* if error column is too far, we precede the error message with >> to show
* that there is an error message on the line
*/
out.println(
Strings.repeat(" ", Math.max(0, location.getColumnNr() - 2)) + "^");
out.println(Strings.repeat(farColumn ? ">" : " ", Math.max(0, location.getColumnNr()
- (ex.getOriginalMessage().length() / 2) - 3))
+ ">> " + ex.getOriginalMessage() + " <<");
out.println();
}
}
out.println("</- JSON -->");
}
restxRequest.getContentStream().reset();
logger.debug(ex.getClass().getSimpleName() + " on " + restxRequest + "." +
" message: " + ex.getMessage() + "." +
" request content: " + CharStreams.toString(new InputStreamReader(restxRequest.getContentStream())));
} catch (IOException e) {
logger.warn("io exception raised when trying to provide original input to caller", e);
out.println(ex.getMessage());
}
}
} catch (RestxError.RestxException ex) {
logger.debug("request raised RestxException", ex);
restxResponse.setStatus(ex.getErrorStatus());
restxResponse.setContentType("application/json");
PrintWriter out = restxResponse.getWriter();
out.println(ex.toJSON());
} catch (WebException ex) {
ex.writeTo(restxRequest, restxResponse);
} catch (IllegalArgumentException | IllegalStateException ex) {
logger.warn("request raised " + ex.getClass().getSimpleName() + ": " + ex.getMessage(), ex);
restxResponse.setStatus(HttpStatus.BAD_REQUEST);
restxResponse.setContentType("text/plain");
PrintWriter out = restxResponse.getWriter();
out.println("UNEXPECTED CLIENT ERROR:");
out.print(ex.getMessage());
} catch (Throwable ex) {
logger.error("request raised " + ex.getClass().getSimpleName() + ": " + ex.getMessage(), ex);
restxResponse.setStatus(HttpStatus.INTERNAL_SERVER_ERROR);
restxResponse.setContentType("text/plain");
PrintWriter out = restxResponse.getWriter();
out.println("UNEXPECTED SERVER ERROR:");
out.print(ex.getMessage());
} finally {
try { restxRequest.closeContentStream(); } catch (Exception ex) { }
try { restxResponse.close(); } catch (Exception ex) { }
monitor.stop();
stopwatch.stop();
restxResponse.getLogLevel().log(logger, restxRequest, restxResponse, stopwatch);
MDC.clear();
}
}