All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.peterphi.std.guice.web.rest.pagewriter.TwitterBootstrapRestFailurePageRenderer Maven / Gradle / Ivy

There is a newer version: 10.1.5
Show newest version
package com.peterphi.std.guice.web.rest.pagewriter;

import com.peterphi.std.guice.restclient.jaxb.ExceptionInfo;
import com.peterphi.std.guice.restclient.jaxb.RestFailure;
import com.peterphi.std.guice.web.HttpCallContext;
import com.peterphi.std.util.ListUtility;
import org.apache.commons.lang.StringUtils;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.List;
import java.util.Map;

public class TwitterBootstrapRestFailurePageRenderer extends TwitterBootstrapPageWriter
{
	private final RestFailure failure;

	private boolean jiraEnabled = false;
	private String jiraEndpoint;
	private int jiraPid;
	private int jiraIssueType;

	private List highlightTerms = null;

	private boolean renderJvmInfo = false;
	private boolean renderStackTrace = false;
	private boolean renderRequestInfo = false;
	private boolean renderRequestAttributes = false;
	private boolean renderEnvironmentVariables = true;


	public TwitterBootstrapRestFailurePageRenderer(RestFailure failure)
	{
		this.failure = failure;
	}


	public void enableJIRA(String endpoint, int pid, int issueType)
	{
		this.jiraEnabled = true;
		this.jiraEndpoint = endpoint;
		this.jiraPid = pid;
		this.jiraIssueType = issueType;
	}


	public void setHighlightTerms(List terms)
	{
		this.highlightTerms = terms;
	}


	@Override
	protected String getTitle()
	{
		if (failure.exception.detail == null || failure.exception.detail.length() < 1024)
			return failure.exception.shortName + ": " + failure.exception.detail;
		else
			return failure.exception.shortName; // Detail is very long, omit it from the page title
	}


	@Override
	protected void writeCustomHeadContent(StringBuilder sb)
	{
		super.writeCustomHeadContent(sb);

		sb.append("\n");
	}


	private void writeJIRA(StringBuilder sb)
	{
		String reportHref;
		if (jiraPid != 0)
		{
			final HttpCallContext ctx = HttpCallContext.get();
			final String url = ctx.getRequest().getRequestURL().toString();

			reportHref = "javascript:doJiraCreateIssue();";

			String summary = failure.exception.shortName + ": " + failure.exception.detail.replaceAll("[\r\n]", "");

			String environment = "URL: " + url + "\n";
			environment += "Log Id: " + ctx.getLogId() + "\n";
			environment += "Server addr: " + ctx.getRequest().getLocalAddr() + "\n";
			environment += "Request Info: " + ctx.getRequestInfo() + "\n";
			environment += "Referer: " + ctx.getRequest().getHeader("Referer") + "\n";
			environment += "Timestamp: " + failure.date + "\n";
			environment += "Source: " + failure.source + "\n";
			environment += "User agent: " + ctx.getRequest().getHeader("User-Agent") + "\n";

			String detail = "**PLEASE DESCRIBE WHAT YOU DID LEADING UP TO THIS ERROR**\n\n\n";

			detail += "Technical request details:\n--------------------------\n\nI was accessing " +
			          url +
			          " and got an HTTP " +
			          failure.httpCode +
			          ".\n";
			detail += "\nStack trace:\n{code}\n" + failure.exception.stackTrace + "\n{code}\n";

			sb.append("
\n"); sb.append("\n"); sb.append("\n"); sb.append("\n"); sb.append("\n"); sb.append("\n"); sb.append("\n"); sb.append("\n"); sb.append("
\n"); sb.append("\n"); } else { reportHref = jiraEndpoint + "/secure/CreateIssue!default.jspa"; } // String searchJiraHref = jiraEndpoint + "/secure/QuickSearch.jspa?searchString=" + escape(failure.exception.detail); // String searchWikiHref = jiraEndpoint + "/secure/QuickSearch.jspa?searchString=" + escape(failure.exception.detail); sb.append(" Create Issue\n"); } @Override protected void writeBodyContent(StringBuilder sb) { sb.append("\n"); sb.append("\n"); sb.append("
\n"); appendHeader(sb); sb.append("

There was a problem processing your request:
").append(failure.exception.shortName).append( " thrown ").append(failure.date).append(" with id ").append(failure.id).append( " and error code ").append(failure.errorCode).append(" returning HTTP Code ").append( failure.httpCode).append("."); if (failure.source != null && !failure.source.equals("unknown")) sb.append(" Source listed as ").append(failure.source); sb.append("

"); // Add the exception (and potentially the stack trace) appendException(sb, failure.exception); if (renderRequestInfo) { // Add the request info appendRequestDetails(sb); } if (renderJvmInfo) { // Add JV details appendJVMDetails(sb); } sb.append("
"); // div class=container } protected void appendHeader(StringBuilder sb) { sb.append("

A problem occurred

"); } @SuppressWarnings("unchecked") private void appendRequestDetails(StringBuilder sb) { final HttpCallContext ctx = HttpCallContext.get(); sb.append("

HTTP Request

\n\n"); final HttpServletRequest r = ctx.getRequest(); // HttpServletRequest information sb.append("

Properties:

\n"); sb.append("
\n"); { appendKeyValueListElement(sb, "Log Id", ctx.getLogId()); appendKeyValueListElement(sb, "Request", ctx.getRequestInfo()); appendAllSimpleGetters(sb, r); } sb.append("
\n"); if (renderRequestAttributes) { // Request attributes sb.append("

Request Attributes

\n"); sb.append("
\n"); { for (Object nameObj : ListUtility.iterate(r.getAttributeNames())) { final String name = (String) nameObj; appendKeyValueListElement(sb, name, r.getAttribute(name)); } } sb.append("
\n"); } // HTTP headers sb.append("

Headers

\n"); sb.append("
\n"); { for (Object headerObj : ListUtility.iterate(r.getHeaderNames())) { final String header = (String) headerObj; for (Object val : ListUtility.iterate(r.getHeaders(header))) { appendKeyValueListElement(sb, header, val); } } } sb.append("
\n"); // HTTP cookies sb.append("

Cookies

\n"); if (r.getCookies() != null && r.getCookies().length > 0) { sb.append("
\n"); for (Cookie cookie : r.getCookies()) { appendKeyValueListElement(sb, cookie.getName(), cookie.getValue()); } sb.append("
\n"); } else { sb.append("

No cookies

"); } } private void appendJVMDetails(StringBuilder sb) { // HTTP cookies sb.append("

Java Virtual Machine

\n"); sb.append("

Properties

\n"); sb.append("
\n"); for (String name : System.getProperties().stringPropertyNames()) { appendKeyValueListElement(sb, name, System.getProperty(name)); } sb.append("
\n"); if (renderEnvironmentVariables) { sb.append("

Environment Variables

\n"); sb.append("
\n"); for (Map.Entry entry : System.getenv().entrySet()) { appendKeyValueListElement(sb, entry.getKey(), entry.getValue()); } sb.append("
\n"); } } private void appendAllSimpleGetters(StringBuilder sb, Object o) { try { for (Method method : o.getClass().getMethods()) { if (method.getParameterTypes().length == 0 && method.getName().startsWith("get") && (method.getReturnType().isPrimitive() || method.getReturnType() == String.class || method.getReturnType() == URI.class || method.getReturnType() == StringBuffer.class)) { final String name = method.getName().substring(3); final Object result = method.invoke(o); appendKeyValueListElement(sb, name, result); } } } catch (Exception e) { // Take no action } } private void appendKeyValueListElement(StringBuilder sb, String key, Object value) { sb.append("
").append(escape(key)).append("
").append(escape(String.valueOf(value))).append("
\n"); } private void appendException(StringBuilder sb, ExceptionInfo info) { if (info != null) { sb.append("
"); sb.append("

").append(escape(info.shortName)).append("

"); // Maintain any whitespace in the exception detail (e.g. for guice CreationExceptions) sb.append("

").append(escape(info.detail)).append("

"); if (renderStackTrace) { appendStacktrace(sb, info); } } } private void appendStacktrace(StringBuilder sb, ExceptionInfo info) { if (!StringUtils.isEmpty(info.stackTrace)) { sb.append("
");
			if (this.highlightTerms != null)
			{
				String[] lines = info.stackTrace.split("\n");

				for (String line : lines)
				{
					appendStacktraceLine(sb, line);
				}
			}
			else
			{
				// Just append the stack trace
				sb.append(escape(info.stackTrace));
			}

			sb.append("
"); } } private void appendStacktraceLine(StringBuilder sb, String line) { // Only consider lines starting in whitespace (stack trace elements looking like " at com.company.x(MyClass.java:123)" if (!line.isEmpty() && Character.isWhitespace(line.charAt(0))) { for (String highlightTerm : highlightTerms) { if (line.contains(highlightTerm)) { // Highlight line (also, make sure the whitespace is outside the tag so things line up nicely) sb.append("\t"); sb.append(escape(line.substring(1))); sb.append(""); sb.append("\n"); return; } } // Line did not meet highlight criteria, mute it (also, make sure the whitespace is outside the tag so things line up nicely) sb.append("\t"); sb.append(escape(line.substring(1))); sb.append(""); sb.append("\n"); } else { // Line does not start with whitespace, do not highlight or mute sb.append(escape(line)).append("\n"); } } public void enableJVMInfo() { this.renderJvmInfo = true; } public void enableEnvironmentVariables() { this.renderEnvironmentVariables = true; } public void enableStackTrace() { this.renderStackTrace = true; } public void enableRequestInfo() { this.renderRequestInfo = true; } }