/*
 * Copyright 2008-2010 by Emeric Vernat
 *
 *     This file is part of Java Melody.
 *
 * Java Melody is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Java Melody 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.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Java Melody.  If not, see <http://www.gnu.org/licenses/>.
 */
package net.bull.javamelody;

import java.io.Serializable;
import java.util.Date;

import javax.servlet.http.HttpServletRequest;

/**
 * Objet correspondant à une erreur dans filtre http ou dans logs à un instant t, avec son message, sa stackTrace
 * éventuelle et son utilisateur courant s'il est défini.
 * @author Emeric Vernat
 */
class CounterError implements Serializable {
	static final String REQUEST_KEY = "javamelody.request";
	private static final long serialVersionUID = 5690702786722045646L;
	@SuppressWarnings("all")
	private static final ThreadLocal<HttpServletRequest> HTTP_SERVLET_REQUEST_CONTEXT = new ThreadLocal<HttpServletRequest>();
	private final long time;
	private final String remoteUser;
	private final String httpRequest;
	private final String message;
	private final String stackTrace;

	CounterError(String message, String stackTrace) {
		super();
		assert message != null;
		this.time = System.currentTimeMillis();
		this.message = message;
		this.stackTrace = stackTrace;
		final HttpServletRequest currentRequest = getCurrentRequest();
		if (currentRequest == null) {
			this.remoteUser = null;
			this.httpRequest = null;
		} else {
			this.remoteUser = currentRequest.getRemoteUser();
			this.httpRequest = (String) currentRequest.getAttribute(REQUEST_KEY);
		}
	}

	/**
	 * Définit la requête http (peut être nulle) pour le thread courant.
	 * @param request HttpServletRequest
	 */
	static void bindRequest(HttpServletRequest request) {
		if (request != null) {
			HTTP_SERVLET_REQUEST_CONTEXT.set(request);
		}
	}

	/**
	 * Retourne la requête http pour le thread courant ou null si elle n'a pas été définie.
	 * @return HttpServletRequest
	 */
	private static HttpServletRequest getCurrentRequest() {
		return HTTP_SERVLET_REQUEST_CONTEXT.get();
	}

	/**
	 * Enlève le lien entre la requête http et le thread courant.
	 */
	static void unbindRequest() {
		HTTP_SERVLET_REQUEST_CONTEXT.remove();
	}

	long getTime() {
		return time;
	}

	Date getDate() {
		return new Date(time);
	}

	String getRemoteUser() {
		return remoteUser;
	}

	String getHttpRequest() {
		return httpRequest;
	}

	String getMessage() {
		return message;
	}

	String getStackTrace() {
		return stackTrace;
	}

	/** {@inheritDoc} */
	@Override
	public String toString() {
		return getClass().getSimpleName() + "[message=" + getMessage() + ']';
	}
}

@@ -1977,131 +1977,445 @@
 %0A%09%09%09
-this.remoteUser = currentRequest.getRemoteUser();%0D%0A%09%09%09this.httpRequest = (String) currentRequest.getAttribute(REQUEST_KEY);
+// unbindRequest pour %C3%A9viter StackOverflowError dans le cas o%C3%B9 getRemoteUser()%0D%0A%09%09%09// fait un log warn ou error. Par exemple, dans le cas d'un SSO comme%0D%0A%09%09%09// com.pixelpark.seraph.SSOAuthenticator.getUser (cf issue 24).%0D%0A%09%09%09unbindRequest();%0D%0A%09%09%09try %7B%0D%0A%09%09%09%09this.httpRequest = (String) currentRequest.getAttribute(REQUEST_KEY);%0D%0A%09%09%09%09this.remoteUser = currentRequest.getRemoteUser();%0D%0A%09%09%09%7D finally %7B%0D%0A%09%09%09%09bindRequest(currentRequest);%0D%0A%09%09%09%7D
 %0D%0A%09%09

fix issue 24: StackOverflowError in CounterError when com.pixelpark.seraph.SSOAuthenticator.getUser is called via Log4JAppender, CounterError and HttpServletRequest.getRemoteUser