/* * (C) Copyright 2006-2008 Nuxeo SAS (http://nuxeo.com/) and contributors. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Lesser General Public License * (LGPL) version 2.1 which accompanies this distribution, and is available at * http://www.gnu.org/licenses/lgpl.html * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * Contributors: * arussel */ package org.nuxeo.ecm.platform.ui.web.shield; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.util.Collection; import java.util.Enumeration; import java.util.Map; import javax.faces.component.UIViewRoot; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jboss.seam.Seam; import org.jboss.seam.contexts.Contexts; import org.jboss.seam.contexts.FacesLifecycle; import org.jboss.seam.core.ConversationPropagation; import org.jboss.seam.core.Manager; import org.jboss.seam.mock.MockApplication; import org.jboss.seam.mock.MockExternalContext; import org.jboss.seam.mock.MockFacesContext; import org.nuxeo.runtime.api.Framework; import org.nuxeo.runtime.model.RegistrationInfo; /** * @author arussel */ public class ErrorPageForwarder { private static final Log nuxeoErrorLog = LogFactory.getLog("nuxeo-error-log"); private static final Log log = LogFactory.getLog(ErrorPageForwarder.class); private static final String SEAM_MESSAGES = "org.jboss.seam.international.messages"; private ServletContext servletContext; public void forwardToErrorPage(HttpServletRequest request, HttpServletResponse response, Throwable t, String exceptionMessage, String userMessage, Boolean securityError, ServletContext servletContext) throws ServletException, IOException { forwardToErrorPage(request, response, getStackTraceAsString(t), exceptionMessage, userMessage, securityError, servletContext); } @SuppressWarnings("rawtypes") public void forwardToErrorPage(HttpServletRequest request, HttpServletResponse response, String stackTrace, String exceptionMessage, String userMessage, Boolean securityError, ServletContext servletContext) throws ServletException, IOException { log.error(stackTrace); this.servletContext = servletContext; // cut/paste from seam Exception filter. // we recreate the seam context to be able to use the messages. MockFacesContext facesContext = createFacesContext(request, response); facesContext.setCurrent(); // if the event context was cleaned up, fish the conversation id // directly out of the ServletRequest attributes, else get it from // the event context Manager manager = Contexts.isEventContextActive() ? (Manager) Contexts.getEventContext().get( Manager.class) : (Manager) request.getAttribute(Seam.getComponentName(Manager.class)); String conversationId = manager == null ? null : manager.getCurrentConversationId(); FacesLifecycle.beginExceptionRecovery(facesContext.getExternalContext()); // If there is an existing long-running conversation on // the failed request, propagate it if (conversationId == null) { Manager.instance().initializeTemporaryConversation(); } else { ConversationPropagation.instance().setConversationId(conversationId); Manager.instance().restoreConversation(); } // we get the message from the seam attribute as the EL won't work in // xhtml String user_message = request.getAttribute(SEAM_MESSAGES) == null ? "An unexpected error occurred." : (String) ((Map) request.getAttribute(SEAM_MESSAGES)).get(userMessage); FacesLifecycle.beginExceptionRecovery(facesContext.getExternalContext()); request.setAttribute("exception_message", exceptionMessage); request.setAttribute("user_message", user_message); request.setAttribute("stackTrace", stackTrace); request.setAttribute("securityError", securityError); request.setAttribute("request_dump", getRequestDump(request)); request.getRequestDispatcher("/nuxeo_error.jsp").forward(request, response); // FacesLifecycle.endRequest( facesContext.getExternalContext() ); // facesContext.release(); } private String getRequestDump(HttpServletRequest request) { StringBuilder builder = new StringBuilder(); builder.append("\nParameter:\n"); Map<String, String[]> m = request.getParameterMap(); for (Map.Entry<String, String[]> entry : m.entrySet()) { builder.append(entry.getKey()).append(":"); if (entry.getValue() == null) { continue; } for (String s : entry.getValue()) { builder.append(s).append(","); } builder.deleteCharAt(builder.length() - 1); builder.append("\n"); } builder.append("\n"); Enumeration<String> names = request.getAttributeNames(); builder.append("Attributes:\n"); while (names.hasMoreElements()) { String name = names.nextElement(); if (name.equals(SEAM_MESSAGES)) { continue; } Object obj = request.getAttribute(name); builder.append(name).append(": ").append(obj.toString()).append( "\n"); } builder.append("\n"); Collection<RegistrationInfo> infos = Framework.getRuntime().getComponentManager().getRegistrations(); builder.append("Components:\n"); for (RegistrationInfo info : infos) { builder.append(info.getComponent().getName()).append(",").append( info.isActivated() ? "activated" : "not activated").append( "\n"); } nuxeoErrorLog.trace("User Principal: " + request.getUserPrincipal() + "\n" + builder.toString()); return builder.toString(); } private MockFacesContext createFacesContext(HttpServletRequest request, HttpServletResponse response) { MockFacesContext mockFacesContext = new MockFacesContext( new MockExternalContext(servletContext, request, response), new MockApplication()); mockFacesContext.setViewRoot(new UIViewRoot()); return mockFacesContext; } public String getStackTraceAsString(Throwable t) { StringWriter swriter = new StringWriter(); PrintWriter pwriter = new PrintWriter(swriter); t.printStackTrace(pwriter); return swriter.getBuffer().toString(); } }