1 /*
2  * Copyright 2008-2019 by Emeric Vernat
3  *
4  *     This file is part of Java Melody.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */

18 package net.bull.javamelody.internal.model;
19
20 import java.io.Serializable;
21 import java.util.Date;
22
23 import javax.servlet.http.HttpServletRequest;
24
25 /**
26  * Objet correspondant à une erreur dans filtre http ou dans logs à un instant t, avec son message, sa stackTrace
27  * éventuelle et son utilisateur courant s'il est défini.
28  * @author Emeric Vernat
29  */

30 public class CounterError implements Serializable {
31     public static final String REQUEST_KEY = "javamelody.request";
32     private static final long serialVersionUID = 5690702786722045646L;
33     @SuppressWarnings("all")
34     private static final ThreadLocal<HttpServletRequest> HTTP_SERVLET_REQUEST_CONTEXT = new ThreadLocal<>();
35
36     /**
37      * Max size of error message.
38      */

39     private static final int MESSAGE_MAX_LENGTH = 1000;
40     /**
41      * Max size of error stack-trace.
42      */

43     private static final int STACKTRACE_MAX_LENGTH = 50000;
44
45     private final long time;
46     private final String remoteUser;
47     private final String httpRequest;
48     private final String message;
49     private final String stackTrace;
50
51     public CounterError(String message, String stackTrace) {
52         super();
53         assert message != null;
54         this.time = System.currentTimeMillis();
55
56         if (message.length() > MESSAGE_MAX_LENGTH) {
57             // avoid possible memory errors as javamelody store 100 errors in memory
58             this.message = message.substring(0, MESSAGE_MAX_LENGTH);
59         } else {
60             this.message = message;
61         }
62
63         if (stackTrace != null && stackTrace.length() > STACKTRACE_MAX_LENGTH) {
64             this.stackTrace = stackTrace.substring(0, STACKTRACE_MAX_LENGTH);
65         } else {
66             this.stackTrace = stackTrace;
67         }
68         final HttpServletRequest currentRequest = getCurrentRequest();
69         if (currentRequest == null) {
70             this.remoteUser = null;
71             this.httpRequest = null;
72         } else {
73             // unbindRequest pour éviter StackOverflowError dans le cas où getRemoteUser()
74             // fait un log warn ou error. Par exemple, dans le cas d'un SSO comme
75             // com.pixelpark.seraph.SSOAuthenticator.getUser (cf issue 24).
76             unbindRequest();
77             try {
78                 this.httpRequest = (String) currentRequest.getAttribute(REQUEST_KEY);
79                 this.remoteUser = currentRequest.getRemoteUser();
80             } finally {
81                 bindRequest(currentRequest);
82             }
83         }
84     }
85
86     /**
87      * Définit la requête http (peut être nulle) pour le thread courant.
88      * @param request HttpServletRequest
89      */

90     public static void bindRequest(HttpServletRequest request) {
91         if (request != null) {
92             HTTP_SERVLET_REQUEST_CONTEXT.set(request);
93         }
94     }
95
96     /**
97      * Retourne la requête http pour le thread courant ou null si elle n'a pas été définie.
98      * @return HttpServletRequest
99      */

100     private static HttpServletRequest getCurrentRequest() {
101         return HTTP_SERVLET_REQUEST_CONTEXT.get();
102     }
103
104     /**
105      * Enlève le lien entre la requête http et le thread courant.
106      */

107     public static void unbindRequest() {
108         HTTP_SERVLET_REQUEST_CONTEXT.remove();
109     }
110
111     long getTime() {
112         return time;
113     }
114
115     public Date getDate() {
116         return new Date(time);
117     }
118
119     public String getRemoteUser() {
120         return remoteUser;
121     }
122
123     public String getHttpRequest() {
124         return httpRequest;
125     }
126
127     public String getMessage() {
128         return message;
129     }
130
131     public String getStackTrace() {
132         return stackTrace;
133     }
134
135     /** {@inheritDoc} */
136     @Override
137     public String toString() {
138         return getClass().getSimpleName() + "[message=" + getMessage() + ']';
139     }
140 }
141