1
18 package net.bull.javamelody.internal.model;
19
20 import java.io.Serializable;
21 import java.util.ArrayList;
22 import java.util.Collections;
23 import java.util.HashMap;
24 import java.util.LinkedHashMap;
25 import java.util.List;
26 import java.util.Map;
27
28 import javax.servlet.http.HttpServletRequest;
29
30 import net.bull.javamelody.internal.model.CounterRequest.ICounterRequestContext;
31
32
38 public class CounterRequestContext implements ICounterRequestContext, Cloneable, Serializable {
39 private static final long serialVersionUID = 1L;
40 private static final Long ONE = 1L;
41 private static final String SPRING_BEST_MATCHING_PATTERN_ATTRIBUTE = "org.springframework.web.servlet.HandlerMapping.bestMatchingPattern";
42
43 private Counter parentCounter;
44 private final CounterRequestContext parentContext;
45 private CounterRequestContext currentChildContext;
46 private final String requestName;
47 private final String completeRequestName;
48 private final transient HttpServletRequest httpRequest;
49 private final String remoteUser;
50 private final long threadId;
51
52 private final long startTime;
53 private final long startCpuTime;
54 private final long startAllocatedBytes;
55 private final String sessionId;
56
57 private int childHits;
58 private int childDurationsSum;
59 @SuppressWarnings("all")
60 private Map<String, Long> childRequestsExecutionsByRequestId;
61
62
63 public CounterRequestContext(Counter parentCounter, CounterRequestContext parentContext,
64 String requestName, String completeRequestName, HttpServletRequest httpRequest,
65 String remoteUser, long startCpuTime, long startAllocatedBytes, String sessionId) {
66
67 this(parentCounter, parentContext, requestName, completeRequestName, httpRequest,
68 remoteUser, Thread.currentThread().getId(), System.currentTimeMillis(),
69 startCpuTime, startAllocatedBytes, sessionId);
70 if (parentContext != null) {
71 parentContext.setCurrentChildContext(this);
72 }
73 }
74
75
76
77 private CounterRequestContext(Counter parentCounter, CounterRequestContext parentContext,
78 String requestName, String completeRequestName, HttpServletRequest httpRequest,
79 String remoteUser, long threadId, long startTime, long startCpuTime,
80 long startAllocatedBytes, String sessionId) {
81
82 super();
83 assert parentCounter != null;
84 assert requestName != null;
85 assert completeRequestName != null;
86 this.parentCounter = parentCounter;
87
88
89 this.parentContext = parentContext;
90 this.requestName = requestName;
91 this.completeRequestName = completeRequestName;
92 this.httpRequest = httpRequest;
93 this.remoteUser = remoteUser;
94 this.threadId = threadId;
95 this.startTime = startTime;
96 this.startCpuTime = startCpuTime;
97 this.startAllocatedBytes = startAllocatedBytes;
98 this.sessionId = sessionId;
99 }
100
101 public Counter getParentCounter() {
102 return parentCounter;
103 }
104
105 void setParentCounter(Counter parentCounter) {
106 assert parentCounter != null
107 && this.parentCounter.getName().equals(parentCounter.getName());
108 this.parentCounter = parentCounter;
109 }
110
111 public static void replaceParentCounters(List<CounterRequestContext> rootCurrentContexts,
112 List<Counter> newParentCounters) {
113 final Map<String, Counter> newParentCountersByName = new HashMap<>(
114 newParentCounters.size());
115 for (final Counter counter : newParentCounters) {
116 newParentCountersByName.put(counter.getName(), counter);
117 }
118 replaceParentCounters(rootCurrentContexts, newParentCountersByName);
119 }
120
121 private static void replaceParentCounters(List<CounterRequestContext> rootCurrentContexts,
122 Map<String, Counter> newParentCountersByName) {
123 for (final CounterRequestContext context : rootCurrentContexts) {
124 final Counter newParentCounter = newParentCountersByName
125 .get(context.getParentCounter().getName());
126 if (newParentCounter != null) {
127
128 context.setParentCounter(newParentCounter);
129 }
130 final List<CounterRequestContext> childContexts = context.getChildContexts();
131 if (!childContexts.isEmpty()) {
132 replaceParentCounters(childContexts, newParentCountersByName);
133 }
134 }
135 }
136
137 public CounterRequestContext getParentContext() {
138 return parentContext;
139 }
140
141 public static String getHttpRequestName(HttpServletRequest httpRequest, String requestName) {
142 if (httpRequest == null) {
143 return requestName;
144 }
145 final String bestMatchingPattern = (String) httpRequest
146 .getAttribute(SPRING_BEST_MATCHING_PATTERN_ATTRIBUTE);
147 if (bestMatchingPattern != null) {
148 final int indexOfSpace = requestName.indexOf(' ');
149 if (indexOfSpace != -1) {
150
151 return bestMatchingPattern + requestName.substring(indexOfSpace);
152 }
153 return bestMatchingPattern;
154 }
155 return requestName;
156 }
157
158 public String getRequestName() {
159 return getHttpRequestName(httpRequest, requestName);
160 }
161
162 public String getCompleteRequestName() {
163 return completeRequestName;
164 }
165
166 public String getRemoteUser() {
167 return remoteUser;
168 }
169
170 public long getThreadId() {
171 return threadId;
172 }
173
174 public int getDuration(long timeOfSnapshot) {
175
176 return (int) Math.max(timeOfSnapshot - startTime, 0);
177 }
178
179 public int getCpuTime() {
180 if (startCpuTime < 0) {
181 return -1;
182 }
183 final int cpuTime = (int) ((ThreadInformations.getThreadCpuTime(getThreadId())
184 - startCpuTime) / 1000000L);
185
186 return Math.max(cpuTime, 0);
187 }
188
189 public int getAllocatedKBytes() {
190 if (startAllocatedBytes < 0) {
191 return -1;
192 }
193 final int allocatedKBytes = (int) ((ThreadInformations
194 .getThreadAllocatedBytes(getThreadId()) - startAllocatedBytes) / 1024L);
195 return Math.max(allocatedKBytes, 0);
196 }
197
198
199 @Override
200 public int getChildHits() {
201 return childHits;
202 }
203
204
205 @Override
206 public int getChildDurationsSum() {
207 return childDurationsSum;
208 }
209
210 public Map<String, Long> getChildRequestsExecutionsByRequestId() {
211 if (childRequestsExecutionsByRequestId == null) {
212 return Collections.emptyMap();
213 }
214
215
216 return childRequestsExecutionsByRequestId;
217 }
218
219 public int getTotalChildHits() {
220
221
222
223 int result = getChildHits();
224 CounterRequestContext childContext = getCurrentChildContext();
225 while (childContext != null) {
226 result += childContext.getChildHits();
227 childContext = childContext.getCurrentChildContext();
228 }
229 return result;
230 }
231
232 public int getTotalChildDurationsSum() {
233
234
235
236 int result = getChildDurationsSum();
237 CounterRequestContext childContext = getCurrentChildContext();
238 while (childContext != null) {
239 result += childContext.getChildDurationsSum();
240 childContext = childContext.getCurrentChildContext();
241 }
242 return result;
243 }
244
245 public boolean hasChildHits() {
246 return parentCounter.getChildCounterName() != null
247 && (getTotalChildHits() > 0 || parentCounter.hasChildHits());
248 }
249
250 public List<CounterRequestContext> getChildContexts() {
251
252
253 final List<CounterRequestContext> childContexts;
254 CounterRequestContext childContext = getCurrentChildContext();
255 if (childContext == null) {
256 childContexts = Collections.emptyList();
257 } else {
258 childContexts = new ArrayList<>(2);
259 }
260 while (childContext != null) {
261 childContexts.add(childContext);
262 childContext = childContext.getCurrentChildContext();
263 }
264 return Collections.unmodifiableList(childContexts);
265 }
266
267 private CounterRequestContext getCurrentChildContext() {
268 return currentChildContext;
269 }
270
271 private void setCurrentChildContext(CounterRequestContext currentChildContext) {
272 this.currentChildContext = currentChildContext;
273 }
274
275 @SuppressWarnings("unused")
276 void addChildRequest(Counter childCounter, String request, String requestId, long duration,
277 boolean systemError, long responseSize) {
278
279
280 if (parentContext != null && parentCounter.getName()
281 .equals(parentContext.getParentCounter().getChildCounterName())) {
282 childHits++;
283 childDurationsSum += (int) duration;
284 }
285
286
287
288 if (parentContext == null) {
289 addChildRequestForDrillDown(requestId);
290 } else {
291 parentContext.addChildRequestForDrillDown(requestId);
292 }
293 }
294
295 private void addChildRequestForDrillDown(String requestId) {
296 if (childRequestsExecutionsByRequestId == null) {
297 childRequestsExecutionsByRequestId = new LinkedHashMap<>();
298 }
299 Long nbExecutions = childRequestsExecutionsByRequestId.get(requestId);
300 if (nbExecutions == null) {
301 nbExecutions = ONE;
302 } else {
303 nbExecutions += 1;
304 }
305 childRequestsExecutionsByRequestId.put(requestId, nbExecutions);
306 }
307
308 void closeChildContext() {
309 final CounterRequestContext childContext = getCurrentChildContext();
310 childHits += childContext.getChildHits();
311 childDurationsSum += childContext.getChildDurationsSum();
312
313 setCurrentChildContext(null);
314 }
315
316
317 @Override
318
319 public CounterRequestContext clone() {
320
321
322 assert getParentContext() == null;
323 return clone(null);
324 }
325
326 private CounterRequestContext clone(CounterRequestContext parentContextClone) {
327 final Counter counter = getParentCounter();
328
329
330
331 final CounterRequestContext clone = new CounterRequestContext(counter, parentContextClone,
332 getRequestName(), getCompleteRequestName(), httpRequest, getRemoteUser(),
333 getThreadId(), startTime, startCpuTime, startAllocatedBytes, sessionId);
334 clone.childHits = getChildHits();
335 clone.childDurationsSum = getChildDurationsSum();
336 final CounterRequestContext childContext = getCurrentChildContext();
337 if (childContext != null) {
338 clone.currentChildContext = childContext.clone(clone);
339 }
340 if (childRequestsExecutionsByRequestId != null) {
341 clone.childRequestsExecutionsByRequestId = new LinkedHashMap<>(
342 childRequestsExecutionsByRequestId);
343 }
344 return clone;
345 }
346
347
348 @Override
349 public String toString() {
350 return getClass().getSimpleName() + "[parentCounter=" + getParentCounter().getName()
351 + ", completeRequestName=" + getCompleteRequestName() + ", threadId="
352 + getThreadId() + ", startTime=" + startTime + ", childHits=" + getChildHits()
353 + ", childDurationsSum=" + getChildDurationsSum() + ", childContexts="
354 + getChildContexts() + ']';
355 }
356 }
357