/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.jooby.internal; import java.util.Arrays; import java.util.Map; import org.jooby.Err; import org.jooby.MediaType; import org.jooby.Renderer; import org.jooby.View; public class DefaulErrRenderer implements Renderer { private boolean showStacktrace; public DefaulErrRenderer(final boolean stacktrace) { this.showStacktrace = stacktrace; } @SuppressWarnings("unchecked") @Override public void render(final Object object, final Context ctx) throws Exception { if (object instanceof View) { View view = (View) object; // assume it is the default error handler if (Err.DefHandler.VIEW.equals(view.name())) { Map<String, Object> model = (Map<String, Object>) view.model().get("err"); Object status = model.get("status"); Object reason = model.get("reason"); Object message = model.get("message"); String[] stacktrace = this.showStacktrace ? (String[]) model.get("stacktrace") : null; StringBuilder html = new StringBuilder("<!doctype html>\n") .append("<html>\n") .append("<head>\n") .append("<meta charset=\"").append(ctx.charset().name()).append("\">\n") .append("<style>\n") .append("body {font-family: \"open sans\",sans-serif; margin-left: 20px;}\n") .append("h1 {font-weight: 300; line-height: 44px; margin: 25px 0 0 0;}\n") .append("h2 {font-size: 16px;font-weight: 300; line-height: 44px; margin: 0;}\n") .append("footer {font-weight: 300; line-height: 44px; margin-top: 10px;}\n") .append("hr {background-color: #f7f7f9;}\n") .append("div.trace {border:1px solid #e1e1e8; background-color: #f7f7f9;}\n") .append("p {padding-left: 20px;}\n") .append("p.tab {padding-left: 40px;}\n") .append("</style>\n") .append("<title>\n") .append(status).append(" ").append(reason) .append("\n</title>\n") .append("<body>\n") .append("<h1>").append(reason).append("</h1>\n") .append("<hr>"); html.append("<h2>message: ").append(message).append("</h2>\n"); html.append("<h2>status: ").append(status).append("</h2>\n"); if (stacktrace != null) { html.append("<h2>stack:</h2>\n") .append("<div class=\"trace\">\n"); Arrays.stream(stacktrace).forEach(line -> { html.append("<p class=\"line"); if (line.startsWith("\t")) { html.append(" tab"); } html.append("\">") .append("<code>") .append(line.replace("\t", " ")) .append("</code>") .append("</p>\n"); }); html.append("</div>\n"); } html.append("</body>\n") .append("</html>\n"); ctx.type(MediaType.html) .send(html.toString()); } } } @Override public String name() { return "defaultErr"; } }