/**********************************************************************************
* $URL: https://source.sakaiproject.org/svn/portal/trunk/portal-util/util/src/java/org/sakaiproject/portal/util/ErrorReporter.java $
* $Id: ErrorReporter.java 129482 2013-09-10 13:22:40Z azeckoski@unicon.net $
***********************************************************************************
*
* Copyright (c) 2006, 2007, 2008 The Sakai Foundation
*
* Licensed under the Educational Community 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.opensource.org/licenses/ECL-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.sakaiproject.portal.util;
import java.io.IOException;
import java.io.PrintWriter;
import java.security.MessageDigest;
import java.text.DateFormat;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.sakaiproject.authz.cover.SecurityService;
import org.sakaiproject.component.cover.ServerConfigurationService;
import org.sakaiproject.email.cover.EmailService;
import org.sakaiproject.event.api.UsageSession;
import org.sakaiproject.event.cover.UsageSessionService;
import org.sakaiproject.id.cover.IdManager;
import org.sakaiproject.time.api.Time;
import org.sakaiproject.time.cover.TimeService;
import org.sakaiproject.tool.api.Placement;
import org.sakaiproject.tool.cover.SessionManager;
import org.sakaiproject.tool.cover.ToolManager;
import org.sakaiproject.user.api.User;
import org.sakaiproject.user.api.UserNotDefinedException;
import org.sakaiproject.user.cover.UserDirectoryService;
import org.sakaiproject.util.FormattedText;
import org.sakaiproject.util.ResourceLoader;
import org.sakaiproject.portal.util.BufferedServletResponse;
/**
* <p>
* ErrorReporter helps with end-user formatted error reporting, user feedback
* collection, logging and emailing for uncaught throwable based errors.
* This is a util class as it's used by both the CharronPortal and the SkinnableCharronPortal.
* </p>
*/
@SuppressWarnings("deprecation")
public class ErrorReporter
{
/** Our log (commons). */
private static Log M_log = LogFactory.getLog(ErrorReporter.class);
/** messages. */
private static ResourceLoader rb = new ResourceLoader("portal-util");
private Map<String, String> censoredHeaders = new HashMap<String, String>();
private Map<String, String> censoredParameters = new HashMap<String, String>();
private Map<String, String> censoredAttributes = new HashMap<String, String>();
public ErrorReporter()
{
censoredParameters.put("pw", "pw");
censoredParameters.put("eid", "eid");
censoredParameters.put("javax.faces.ViewState", "javax.faces.ViewState");
censoredHeaders.put("cookie","cookie");
censoredHeaders.put("authorization","authorization");
}
/** Following two methods borrowed from RWikiObjectImpl.java * */
private static MessageDigest shatemplate = null;
public static String computeSha1(String content)
{
String digest = "";
try
{
if (shatemplate == null)
{
shatemplate = MessageDigest.getInstance("SHA");
}
MessageDigest shadigest = (MessageDigest) shatemplate.clone();
byte[] bytedigest = shadigest.digest(content.getBytes("UTF8"));
digest = byteArrayToHexStr(bytedigest);
}
catch (Exception ex)
{
System.err.println("Unable to create SHA hash of content");
ex.printStackTrace();
}
return digest;
}
private static String byteArrayToHexStr(byte[] data)
{
StringBuffer output = new StringBuffer();
String tempStr = "";
int tempInt = 0;
for (int cnt = 0; cnt < data.length; cnt++)
{
// Deposit a byte into the 8 lsb of an int.
tempInt = data[cnt] & 0xFF;
// Get hex representation of the int as a
// string.
tempStr = Integer.toHexString(tempInt);
// Append a leading 0 if necessary so that
// each hex string will contain two
// characters.
if (tempStr.length() == 1) tempStr = "0" + tempStr;
// Concatenate the two characters to the
// output string.
output.append(tempStr);
}// end for loop
return output.toString().toUpperCase();
}// end byteArrayToHexStr
/**
* Format the full stack trace.
*
* @param t
* The throwable.
* @return A display of the full stack trace for the throwable.
*/
protected String getStackTrace(Throwable t)
{
StackTraceElement[] st = t.getStackTrace();
StringBuilder buf = new StringBuilder();
if (st != null)
{
for (int i = 0; i < st.length; i++)
{
buf.append("\n at "
+ st[i].getClassName()
+ "."
+ st[i].getMethodName()
+ "("
+ ((st[i].isNativeMethod()) ? "Native Method" : (st[i]
.getFileName()
+ ":" + st[i].getLineNumber())) + ")");
}
buf.append("\n");
}
return buf.toString();
}
/**
* Format a one-level stack trace, just showing the place where the
* exception occurred (the first entry in the stack trace).
*
* @param t
* The throwable.
* @return A display of the first stack trace entry for the throwable.
*/
protected String getOneTrace(Throwable t)
{
StackTraceElement[] st = t.getStackTrace();
StringBuilder buf = new StringBuilder();
if (st != null && st.length > 0)
{
buf.append("\n at "
+ st[1].getClassName()
+ "."
+ st[1].getMethodName()
+ "("
+ ((st[1].isNativeMethod()) ? "Native Method" : (st[1].getFileName()
+ ":" + st[1].getLineNumber())) + ")\n");
}
return buf.toString();
}
/**
* Compute the cause of a throwable, checking for the special
* ServletException case, and the points-to-self case.
*
* @param t
* The throwable.
* @return The cause of the throwable, or null if there is none.
*/
protected Throwable getCause(Throwable t)
{
Throwable rv = null;
// ServletException is non-standard
if (t instanceof ServletException)
{
rv = ((ServletException) t).getRootCause();
}
// try for the standard cause
if (rv == null) rv = t.getCause();
// clear it if the cause is pointing at the throwable
if ((rv != null) && (rv == t)) rv = null;
return rv;
}
/**
* Format a throwable for display: list the various throwables drilling down
* the cause, and full stacktrack for the final cause.
*
* @param t
* The throwable.
* @return The string display of the throwable.
*/
protected String throwableDisplay(Throwable t)
{
StringBuilder buf = new StringBuilder();
buf.append(t.toString()
+ ((getCause(t) == null) ? (getStackTrace(t)) : getOneTrace(t)));
while (getCause(t) != null)
{
t = getCause(t);
buf.append("caused by: ");
buf.append(t.toString()
+ ((getCause(t) == null) ? (getStackTrace(t)) : getOneTrace(t)));
}
return buf.toString();
}
/**
* Log and email the error report details.
*
* @param usageSessionId
* The end-user's usage session id.
* @param userId
* The end-user's user id.
* @param time
* The time of the error.
* @param problem
* The stacktrace of the error.
* @param problemdigest
* The sha1 digest of the stacktrace.
* @param requestURI
* The request URI.
* @param userReport
* The end user comments.
* @param object
* @param placementDisplay
*/
protected void logAndMail(String bugId, String usageSessionId, String userId, String time,
String problem, String problemdigest, String requestURI, String userReport)
{
logAndMail(bugId, usageSessionId, userId, time, problem, problemdigest, requestURI, "",
"", userReport);
}
protected void logAndMail(String bugId, String usageSessionId, String userId, String time,
String problem, String problemdigest, String requestURI,
String requestDisplay, String placementDisplay, String userReport)
{
// log
M_log.warn(rb.getString("bugreport.bugreport") + " "
+ rb.getString("bugreport.bugid") + ": " + bugId + " "
+ rb.getString("bugreport.user") + ": " + userId + " "
+ rb.getString("bugreport.usagesession") + ": " + usageSessionId + " "
+ rb.getString("bugreport.time") + ": " + time + " "
+ rb.getString("bugreport.usercomment") + ": " + userReport + " "
+ rb.getString("bugreport.stacktrace") + "\n" + problem + "\n"
+ placementDisplay + "\n" + requestDisplay);
// mail
String emailAddr = ServerConfigurationService.getString("portal.error.email");
if (emailAddr != null)
{
String uSessionInfo = "";
UsageSession usageSession = UsageSessionService.getSession();
if (usageSession != null)
{
uSessionInfo = rb.getString("bugreport.useragent") + ": "
+ usageSession.getUserAgent() + "\n"
+ rb.getString("bugreport.browserid") + ": "
+ usageSession.getBrowserId() + "\n"
+ rb.getString("bugreport.ip") + ": "
+ usageSession.getIpAddress() + "\n";
}
String pathInfo = "";
if (requestURI != null)
{
pathInfo = rb.getString("bugreport.path") + ": " + requestURI + "\n";
}
User user = null;
String userName = null;
String userMail = null;
String userEid = null;
if (userId != null)
{
try
{
user = UserDirectoryService.getUser(userId);
userName = user.getDisplayName();
userMail = user.getEmail();
userEid = user.getEid();
} catch (UserNotDefinedException e) {
M_log.warn("logAndMail: could not find userid: " + userId);
}
}
String subject = rb.getString("bugreport.bugreport") + ": " + problemdigest
+ " / " + usageSessionId;
String userComment = "";
if (userReport != null)
{
userComment = rb.getString("bugreport.usercomment") + ":\n\n"
+ userReport + "\n\n\n";
subject = subject + " " + rb.getString("bugreport.commentflag");
}
String from = "\""
+ ServerConfigurationService.getString("ui.service", "Sakai")
+ "\"<no-reply@" + ServerConfigurationService.getServerName() + ">";
String problemDisplay = "";
if (problem != null) {
problemDisplay = rb.getString("bugreport.stacktrace") + ":\n\n"
+ problem + "\n\n";
}
String body = rb.getString("bugreport.bugid") + ": " + bugId + "\n"
+ rb.getString("bugreport.user") + ": " + userEid + " ("
+ userName + ")\n" + rb.getString("bugreport.email") + ": "
+ userMail + "\n" + rb.getString("bugreport.usagesession") + ": "
+ usageSessionId + "\n" + rb.getString("bugreport.digest") + ": "
+ problemdigest + "\n" + rb.getString("bugreport.version-sakai")
+ ": " + ServerConfigurationService.getString("version.sakai") + "\n"
+ rb.getString("bugreport.version-service") + ": "
+ ServerConfigurationService.getString("version.service") + "\n"
+ rb.getString("bugreport.appserver") + ": "
+ ServerConfigurationService.getServerId() + "\n" + uSessionInfo
+ pathInfo + rb.getString("bugreport.time") + ": " + time + "\n\n\n"
+ userComment + problemDisplay + placementDisplay + "\n\n" + requestDisplay;
EmailService.send(from, emailAddr, subject, body, emailAddr, null, null);
}
}
/**
* Handle the inital report of an error, from an uncaught throwable, with a
* user display - but returning a string that contins a fragment.
*
* @param req
* The request.
* @param res
* The response.
* @param t
* The uncaught throwable.
*/
public String reportFragment(HttpServletRequest req, HttpServletResponse res, Throwable t)
{
BufferedServletResponse bufferedResponse = new BufferedServletResponse(res);
report(req,bufferedResponse,t,false);
String fragment = bufferedResponse.getInternalBuffer().getBuffer().toString();
return fragment;
}
/**
* Handle the inital report of an error, from an uncaught throwable, with a
* user display.
*
* @param req
* The request.
* @param res
* The response.
* @param t
* The uncaught throwable.
*/
public void report(HttpServletRequest req, HttpServletResponse res, Throwable t)
{
report(req,res,t,true);
}
public void report(HttpServletRequest req, HttpServletResponse res,
Throwable t, boolean fullPage)
{
boolean showStackTrace = SecurityService.isSuperUser() ||
ServerConfigurationService.getBoolean("portal.error.showdetail", false);
String bugId = IdManager.createUuid();
String headInclude = (String) req.getAttribute("sakai.html.head");
String bodyOnload = (String) req.getAttribute("sakai.html.body.onload");
Time reportTime = TimeService.newTime();
String time = reportTime.toStringLocalDate() + " "
+ reportTime.toStringLocalTime24();
String usageSessionId = UsageSessionService.getSessionId();
String userId = SessionManager.getCurrentSessionUserId();
String requestDisplay = requestDisplay(req);
String placementDisplay = placementDisplay();
String problem = throwableDisplay(t);
String problemdigest = computeSha1(problem);
String postAddr = ServerConfigurationService.getPortalUrl() + "/error-report";
String requestURI = req.getRequestURI();
if (bodyOnload == null)
{
bodyOnload = "";
}
else
{
bodyOnload = " onload=\"" + bodyOnload + "\"";
}
try
{
// headers
res.setStatus(javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
res.setContentType("text/html; charset=UTF-8");
res.addDateHeader("Expires", System.currentTimeMillis()
- (1000L * 60L * 60L * 24L * 365L));
res.addDateHeader("Last-Modified", System.currentTimeMillis());
res
.addHeader("Cache-Control",
"no-store, no-cache, must-revalidate, max-age=0, post-check=0, pre-check=0");
res.addHeader("Pragma", "no-cache");
PrintWriter out = null;
try {
out = res.getWriter();
} catch (Exception ex ) {
out = new PrintWriter(res.getOutputStream());
}
if ( fullPage )
{
out
.println("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">");
out
.println("<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"en\" xml:lang=\"en\">");
if (headInclude != null)
{
out.println("<head>");
out.println(headInclude);
out.println("</head>");
}
out.println("<body" + bodyOnload + ">");
out.println("<div class=\"portletBody\">");
}
out.println("<h3>" + rb.getString("bugreport.error") + "</h3>");
out.println("<p>" + rb.getString("bugreport.statement") + "<br /><br /></p>");
out.println("<h4>" + rb.getString("bugreport.sendtitle") + "</h4>");
out.println("<p>" + rb.getString("bugreport.sendinstructions") + "</p>");
out.println("<form action=\"" + postAddr + "\" method=\"POST\">");
if (showStackTrace) {
out.println("<input type=\"hidden\" name=\"problem\" value=\"");
out.println(FormattedText.escapeHtml(problem, false));
out.println("\">");
}
out.println("<input type=\"hidden\" name=\"problemRequest\" value=\"");
out.println(FormattedText.escapeHtml(requestDisplay, false));
out.println("\">");
out.println("<input type=\"hidden\" name=\"problemPlacement\" value=\"");
out.println(FormattedText.escapeHtml(placementDisplay, false));
out.println("\">");
out.println("<input type=\"hidden\" name=\"problemdigest\" value=\""
+ FormattedText.escapeHtml(problemdigest, false) + "\">");
out.println("<input type=\"hidden\" name=\"session\" value=\""
+ FormattedText.escapeHtml(usageSessionId, false) + "\">");
out.println("<input type=\"hidden\" name=\"bugid\" value=\""
+ FormattedText.escapeHtml(bugId, false) + "\">");
out.println("<input type=\"hidden\" name=\"user\" value=\""
+ FormattedText.escapeHtml(userId, false) + "\">");
out.println("<input type=\"hidden\" name=\"time\" value=\""
+ FormattedText.escapeHtml(time, false) + "\">");
out
.println("<table class=\"itemSummary\" cellspacing=\"5\" cellpadding=\"5\">");
out.println("<tbody>");
out.println("<tr>");
out
.println("<td><textarea rows=\"10\" cols=\"60\" name=\"comment\"></textarea></td>");
out.println("</tr>");
out.println("</tbody>");
out.println("</table>");
out.println("<div class=\"act\">");
out.println("<input type=\"submit\" value=\""
+ rb.getString("bugreport.sendsubmit") + "\">");
out.println("</div>");
out.println("</form><br />");
out.println("<h4>" + rb.getString("bugreport.recoverytitle") + "</h4>");
out.println("<p>" + rb.getString("bugreport.recoveryinstructions") + "");
out.println("<ul><li>" + rb.getString("bugreport.recoveryinstructions1")
+ "</li>");
out.println("<li>" + rb.getString("bugreport.recoveryinstructions2")
+ "</li>");
out.println("<li>" + rb.getString("bugreport.recoveryinstructions3")
+ "</li></ul><br /><br /></p>");
if (showStackTrace) {
out.println("<h4>" + rb.getString("bugreport.detailstitle") + "</h4>");
out.println("<p>" + rb.getString("bugreport.detailsnote") + "</p>");
out.println("<p><pre>");
out.println(FormattedText.escapeHtml(problem, false));
out.println();
out.println(rb.getString("bugreport.user") + ": "
+ FormattedText.escapeHtml(userId, false) + "\n");
out.println(rb.getString("bugreport.usagesession") + ": "
+ FormattedText.escapeHtml(usageSessionId, false) + "\n");
out.println(rb.getString("bugreport.time") + ": "
+ FormattedText.escapeHtml(time, false) + "\n");
out.println("</pre></p>");
}
if ( fullPage )
{
out.println("</body>");
out.println("</html>");
}
if (out != null)
{
out.close();
}
// log and send the preliminary email
logAndMail(bugId, usageSessionId, userId, time, problem, problemdigest, requestURI,
requestDisplay, placementDisplay, null);
}
catch (Throwable any)
{
M_log.warn(rb.getString("bugreport.troublereporting"), any);
}
}
private String placementDisplay()
{
StringBuilder sb = new StringBuilder();
try
{
Placement p = ToolManager.getCurrentPlacement();
if (p != null)
{
sb.append(rb.getString("bugreport.placement")).append("\n");
sb.append(rb.getString("bugreport.placement.id")).append(p.getToolId())
.append("\n");
sb.append(rb.getString("bugreport.placement.context")).append(
p.getContext()).append("\n");
sb.append(rb.getString("bugreport.placement.title")).append(p.getTitle())
.append("\n");
}
else
{
sb.append(rb.getString("bugreport.placement")).append("\n");
sb.append(rb.getString("bugreport.placement.none")).append("\n");
}
}
catch (Exception ex)
{
M_log.error("Failed to generate placement display", ex);
sb.append("Error " + ex.getMessage());
}
return sb.toString();
}
@SuppressWarnings("rawtypes")
private String requestDisplay(HttpServletRequest request)
{
StringBuilder sb = new StringBuilder();
try
{
sb.append(rb.getString("bugreport.request")).append("\n");
sb.append(rb.getString("bugreport.request.authtype")).append(
request.getAuthType()).append("\n");
sb.append(rb.getString("bugreport.request.charencoding")).append(
request.getCharacterEncoding()).append("\n");
sb.append(rb.getString("bugreport.request.contentlength")).append(
request.getContentLength()).append("\n");
sb.append(rb.getString("bugreport.request.contenttype")).append(
request.getContentType()).append("\n");
sb.append(rb.getString("bugreport.request.contextpath")).append(
request.getContextPath()).append("\n");
sb.append(rb.getString("bugreport.request.localaddr")).append(
request.getLocalAddr()).append("\n");
sb.append(rb.getString("bugreport.request.localname")).append(
request.getLocalName()).append("\n");
sb.append(rb.getString("bugreport.request.localport")).append(
request.getLocalPort()).append("\n");
sb.append(rb.getString("bugreport.request.method")).append(
request.getMethod()).append("\n");
sb.append(rb.getString("bugreport.request.pathinfo")).append(
request.getPathInfo()).append("\n");
sb.append(rb.getString("bugreport.request.protocol")).append(
request.getProtocol()).append("\n");
sb.append(rb.getString("bugreport.request.querystring")).append(
request.getQueryString()).append("\n");
sb.append(rb.getString("bugreport.request.remoteaddr")).append(
request.getRemoteAddr()).append("\n");
sb.append(rb.getString("bugreport.request.remotehost")).append(
request.getRemoteHost()).append("\n");
sb.append(rb.getString("bugreport.request.remoteport")).append(
request.getRemotePort()).append("\n");
sb.append(rb.getString("bugreport.request.requesturl")).append(
request.getRequestURL()).append("\n");
sb.append(rb.getString("bugreport.request.scheme")).append(
request.getScheme()).append("\n");
sb.append(rb.getString("bugreport.request.servername")).append(
request.getServerName()).append("\n");
sb.append(rb.getString("bugreport.request.headers")).append("\n");
for (Enumeration e = request.getHeaderNames(); e.hasMoreElements();)
{
String headerName = (String) e.nextElement();
boolean censor = ( censoredHeaders.get(headerName) != null );
for (Enumeration he = request.getHeaders(headerName); he
.hasMoreElements();)
{
String headerValue = (String) he.nextElement();
sb.append(rb.getString("bugreport.request.header"))
.append(headerName).append(":").append(censor?"---censored---":headerValue).append(
"\n");
}
}
sb.append(rb.getString("bugreport.request.parameters")).append("\n");
for (Enumeration e = request.getParameterNames(); e.hasMoreElements();)
{
String parameterName = (String) e.nextElement();
boolean censor = ( censoredParameters.get(parameterName) != null );
String[] paramvalues = request.getParameterValues(parameterName);
for (int i = 0; i < paramvalues.length; i++)
{
sb.append(rb.getString("bugreport.request.parameter")).append(
parameterName).append(":").append(i).append(":").append(
censor?"----censored----":paramvalues[i]).append("\n");
}
}
sb.append(rb.getString("bugreport.request.attributes")).append("\n");
for (Enumeration e = request.getAttributeNames(); e.hasMoreElements();)
{
String attributeName = (String) e.nextElement();
Object attribute = request.getAttribute(attributeName);
boolean censor = ( censoredAttributes.get(attributeName) != null );
sb.append(rb.getString("bugreport.request.attribute")).append(
attributeName).append(":").append(censor?"----censored----":attribute).append("\n");
}
HttpSession session = request.getSession(false);
if (session != null)
{
DateFormat serverLocaleDateFormat = DateFormat.getDateInstance(DateFormat.FULL, Locale.getDefault());
sb.append(rb.getString("bugreport.session")).append("\n");
sb.append(rb.getString("bugreport.session.creation")).append(
session.getCreationTime()).append("\n");
sb.append(rb.getString("bugreport.session.lastaccess")).append(
session.getLastAccessedTime()).append("\n");
sb.append(rb.getString("bugreport.session.creationdatetime")).append(
serverLocaleDateFormat.format(session.getCreationTime())).append("\n");
sb.append(rb.getString("bugreport.session.lastaccessdatetime")).append(
serverLocaleDateFormat.format(session.getLastAccessedTime())).append("\n");
sb.append(rb.getString("bugreport.session.maxinactive")).append(
session.getMaxInactiveInterval()).append("\n");
sb.append(rb.getString("bugreport.session.attributes")).append("\n");
for (Enumeration e = session.getAttributeNames(); e.hasMoreElements();)
{
String attributeName = (String) e.nextElement();
Object attribute = session.getAttribute(attributeName);
boolean censor = ( censoredAttributes.get(attributeName) != null );
sb.append(rb.getString("bugreport.session.attribute")).append(
attributeName).append(":").append(censor?"----censored----":attribute).append("\n");
}
}
}
catch (Exception ex)
{
M_log.error("Failed to generate request display", ex);
sb.append("Error " + ex.getMessage());
}
return sb.toString();
}
/**
* Accept the user feedback post.
*
* @param req
* The request.
* @param res
* The response.
*/
public void postResponse(HttpServletRequest req, HttpServletResponse res)
{
String bugId = req.getParameter("bugid");
String session = req.getParameter("session");
String user = req.getParameter("user");
String time = req.getParameter("time");
String comment = req.getParameter("comment");
String problem = req.getParameter("problem");
String problemdigest = req.getParameter("problemdigest");
String problemRequest = req.getParameter("problemRequest");
String problemPlacement = req.getParameter("problemPlacement");
// log and send the followup email
logAndMail(bugId, session, user, time, problem, problemdigest, null, problemRequest,
problemPlacement, comment);
// always redirect from a post
try
{
res.sendRedirect(res.encodeRedirectURL(ServerConfigurationService
.getPortalUrl()
+ "/error-reported"));
}
catch (IOException e)
{
M_log.warn(rb.getString("bugreport.troubleredirecting"), e);
}
}
/**
* Accept the user feedback post.
*
* @param req
* The request.
* @param res
* The response.
*/
public void thanksResponse(HttpServletRequest req, HttpServletResponse res)
{
String headInclude = (String) req.getAttribute("sakai.html.head");
String bodyOnload = (String) req.getAttribute("sakai.html.body.onload");
if (bodyOnload == null)
{
bodyOnload = "";
}
else
{
bodyOnload = " onload=\"" + bodyOnload + "\"";
}
try
{
// headers
res.setContentType("text/html; charset=UTF-8");
res.addDateHeader("Expires", System.currentTimeMillis()
- (1000L * 60L * 60L * 24L * 365L));
res.addDateHeader("Last-Modified", System.currentTimeMillis());
res
.addHeader("Cache-Control",
"no-store, no-cache, must-revalidate, max-age=0, post-check=0, pre-check=0");
res.addHeader("Pragma", "no-cache");
PrintWriter out = res.getWriter();
out
.println("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">");
out
.println("<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"en\" xml:lang=\"en\">");
if (headInclude != null)
{
out.println("<head>");
out.println(headInclude);
out.println("</head>");
}
out.println("<body" + bodyOnload + ">");
out.println("<div class=\"portletBody\">");
out.println("<h4>" + rb.getString("bugreport.senttitle") + "</h4>");
out.println("<p>" + rb.getString("bugreport.sentnote") + "<br /><br /></p>");
out.println("<h4>" + rb.getString("bugreport.recoverytitle") + "</h4>");
out.println("<p>" + rb.getString("bugreport.recoveryinstructions.reported") + "");
out.println("<ul><li>" + rb.getString("bugreport.recoveryinstructions1")
+ "</li>");
out.println("<li>" + rb.getString("bugreport.recoveryinstructions2")
+ "</li>");
out.println("<li>" + rb.getString("bugreport.recoveryinstructions3")
+ "</li></ul><br /><br /></p>");
out.println("</body>");
out.println("</html>");
}
catch (Throwable any)
{
M_log.warn(rb.getString("bugreport.troublethanks"), any);
}
}
}