1
2
3
4
5
6
7
8
9
10
11 package psiprobe.tools;
12
13 import jakarta.servlet.ServletContext;
14 import jakarta.servlet.http.HttpSession;
15
16 import java.io.Serializable;
17 import java.lang.reflect.InvocationTargetException;
18 import java.util.ArrayList;
19 import java.util.Arrays;
20 import java.util.Collections;
21 import java.util.Date;
22 import java.util.HashSet;
23 import java.util.List;
24 import java.util.Locale;
25 import java.util.Set;
26
27 import javax.naming.NamingException;
28
29 import org.apache.catalina.Container;
30 import org.apache.catalina.Context;
31 import org.apache.catalina.Session;
32 import org.apache.catalina.Wrapper;
33 import org.apache.catalina.core.StandardWrapper;
34 import org.apache.commons.lang3.reflect.MethodUtils;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37 import org.springframework.util.ClassUtils;
38
39 import psiprobe.beans.ContainerWrapperBean;
40 import psiprobe.beans.ResourceResolver;
41 import psiprobe.model.Application;
42 import psiprobe.model.ApplicationParam;
43 import psiprobe.model.ApplicationResource;
44 import psiprobe.model.ApplicationSession;
45 import psiprobe.model.Attribute;
46 import psiprobe.model.FilterInfo;
47 import psiprobe.model.ServletInfo;
48 import psiprobe.model.ServletMapping;
49
50
51
52
53 public final class ApplicationUtils {
54
55
56 private static final Logger logger = LoggerFactory.getLogger(ApplicationUtils.class);
57
58
59
60
61 private ApplicationUtils() {
62
63 }
64
65
66
67
68
69
70
71
72
73 public static Application getApplication(Context context, ContainerWrapperBean containerWrapper) {
74 return getApplication(context, null, false, containerWrapper);
75 }
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93 public static Application getApplication(Context context, ResourceResolver resourceResolver,
94 boolean calcSize, ContainerWrapperBean containerWrapper) {
95
96
97 logger.debug("Querying webapp: {}", context.getName());
98
99 Application app = new Application();
100 app.setName(context.getName().length() > 0 ? context.getName() : "/");
101 app.setDocBase(context.getDocBase());
102 app.setDisplayName(context.getDisplayName());
103
104 app.setAvailable(containerWrapper.getTomcatContainer().getAvailable(context));
105 app.setDistributable(context.getDistributable());
106 app.setSessionTimeout(context.getSessionTimeout());
107 app.setServletVersion(context.getServletContext().getMajorVersion() + "."
108 + context.getServletContext().getMinorVersion());
109
110 if (resourceResolver != null) {
111 logger.debug("counting servlet attributes");
112
113 app.setContextAttributeCount(
114 Collections.list(context.getServletContext().getAttributeNames()).size());
115
116 if (app.isAvailable()) {
117 logger.debug("collecting session information");
118
119 app.setSessionCount(context.getManager().findSessions().length);
120
121 boolean serializable = true;
122 long sessionAttributeCount = 0;
123 long size = 0;
124
125 for (Session session : context.getManager().findSessions()) {
126 ApplicationSession appSession = getApplicationSession(session, calcSize, false);
127 if (appSession != null) {
128 sessionAttributeCount += appSession.getObjectCount();
129 serializable = serializable && appSession.isSerializable();
130 size += appSession.getSize();
131 }
132 }
133 app.setSerializable(serializable);
134 app.setSessionAttributeCount(sessionAttributeCount);
135 app.setSize(size);
136 }
137
138 logger.debug("aggregating servlet stats");
139
140 collectApplicationServletStats(context, app);
141
142 if (resourceResolver.supportsPrivateResources() && app.isAvailable()) {
143 int[] scores =
144 getApplicationDataSourceUsageScores(context, resourceResolver, containerWrapper);
145 app.setDataSourceBusyScore(scores[0]);
146 app.setDataSourceEstablishedScore(scores[1]);
147 }
148 }
149
150 return app;
151 }
152
153
154
155
156
157
158
159
160
161 public static void collectApplicationServletStats(Context context, Application app) {
162 int svltCount = 0;
163 long reqCount = 0;
164 long errCount = 0;
165 long procTime = 0;
166 long minTime = Long.MAX_VALUE;
167 long maxTime = 0;
168
169 for (Container container : context.findChildren()) {
170 if (container instanceof StandardWrapper) {
171 StandardWrapper sw = (StandardWrapper) container;
172 svltCount++;
173
174
175 Object requestCount = null;
176 try {
177 requestCount = MethodUtils.invokeMethod(sw, "getRequestCount");
178 if (requestCount instanceof Long) {
179
180 reqCount += (long) requestCount;
181 } else {
182
183 reqCount += (int) requestCount;
184 }
185 } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
186 logger.error("Unable to find getRequestCount", e);
187 }
188
189
190 try {
191 Object errorCount = MethodUtils.invokeMethod(sw, "getErrorCount");
192 if (errorCount instanceof Long) {
193
194 errCount += (long) errorCount;
195 } else {
196
197 errCount += (int) errorCount;
198 }
199 } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
200 logger.error("Unable to find getErrorCount", e);
201 }
202
203 procTime += sw.getProcessingTime();
204 if (requestCount != null) {
205 if (requestCount instanceof Long && (long) requestCount > 0) {
206
207 minTime = Math.min(minTime, sw.getMinTime());
208 } else if (requestCount instanceof Integer && (int) requestCount > 0) {
209
210 minTime = Math.min(minTime, sw.getMinTime());
211 }
212 }
213 maxTime = Math.max(maxTime, sw.getMaxTime());
214 }
215 }
216 app.setServletCount(svltCount);
217 app.setRequestCount(reqCount);
218 app.setErrorCount(errCount);
219 app.setProcessingTime(procTime);
220 app.setMinTime(minTime == Long.MAX_VALUE ? 0 : minTime);
221 app.setMaxTime(maxTime);
222 }
223
224
225
226
227
228
229
230
231
232
233 public static int[] getApplicationDataSourceUsageScores(Context context,
234 ResourceResolver resolver, ContainerWrapperBean containerWrapper) {
235
236 logger.debug("Calculating datasource usage score");
237
238 int[] scores = {0, 0};
239 List<ApplicationResource> appResources;
240 try {
241 appResources = resolver.getApplicationResources(context, containerWrapper);
242 } catch (NamingException e) {
243 throw new RuntimeException(e);
244 }
245 for (ApplicationResource appResource : appResources) {
246 if (appResource.getDataSourceInfo() != null) {
247 scores[0] = Math.max(scores[0], appResource.getDataSourceInfo().getBusyScore());
248 scores[1] = Math.max(scores[1], appResource.getDataSourceInfo().getEstablishedScore());
249 }
250 }
251 return scores;
252 }
253
254
255
256
257
258
259
260
261
262
263 public static ApplicationSession getApplicationSession(Session session, boolean calcSize,
264 boolean addAttributes) {
265
266 ApplicationSession sbean = null;
267 if (session != null && session.isValid()) {
268 sbean = new ApplicationSession();
269
270 sbean.setId(session.getId());
271 sbean.setCreationTime(new Date(session.getCreationTime()));
272 sbean.setLastAccessTime(new Date(session.getLastAccessedTime()));
273 sbean.setMaxIdleTime(session.getMaxInactiveInterval() * 1000);
274 sbean.setManagerType(session.getManager().getClass().getName());
275 sbean.setInfo(session.getClass().getSimpleName());
276
277 boolean sessionSerializable = true;
278 int attributeCount = 0;
279 long size = 0;
280
281 HttpSession httpSession = session.getSession();
282 Set<Object> processedObjects = new HashSet<>(1000);
283
284
285 processedObjects.add(httpSession);
286 try {
287 for (String name : Collections.list(httpSession.getAttributeNames())) {
288 Object obj = httpSession.getAttribute(name);
289 sessionSerializable = sessionSerializable && obj instanceof Serializable;
290
291 long objSize = 0;
292 if (calcSize) {
293 try {
294 objSize += Instruments.sizeOf(name, processedObjects);
295 objSize += Instruments.sizeOf(obj, processedObjects);
296 } catch (Exception ex) {
297 logger.error("Cannot estimate size of attribute '{}'", name, ex);
298 }
299 }
300
301 if (addAttributes) {
302 Attribute saBean = new Attribute();
303 saBean.setName(name);
304 saBean.setType(ClassUtils.getQualifiedName(obj.getClass()));
305 saBean.setValue(obj);
306 saBean.setSize(objSize);
307 saBean.setSerializable(obj instanceof Serializable);
308 sbean.addAttribute(saBean);
309 }
310 attributeCount++;
311 size += objSize;
312 }
313 String lastAccessedIp =
314 (String) httpSession.getAttribute(ApplicationSession.LAST_ACCESSED_BY_IP);
315 if (lastAccessedIp != null) {
316 sbean.setLastAccessedIp(lastAccessedIp);
317 sbean.setLastAccessedIpLocale(
318 (Locale) httpSession.getAttribute(ApplicationSession.LAST_ACCESSED_LOCALE));
319 }
320
321 } catch (IllegalStateException e) {
322 logger.info("Session appears to be invalidated, ignore");
323 logger.trace("", e);
324 }
325
326 sbean.setObjectCount(attributeCount);
327 sbean.setSize(size);
328 sbean.setSerializable(sessionSerializable);
329 }
330
331 return sbean;
332 }
333
334
335
336
337
338
339
340
341 public static List<Attribute> getApplicationAttributes(Context context) {
342 List<Attribute> attrs = new ArrayList<>();
343 ServletContext servletCtx = context.getServletContext();
344 for (String attrName : Collections.list(servletCtx.getAttributeNames())) {
345 Object attrValue = servletCtx.getAttribute(attrName);
346
347 Attribute attr = new Attribute();
348 attr.setName(attrName);
349 attr.setValue(attrValue);
350 attr.setType(ClassUtils.getQualifiedName(attrValue.getClass()));
351 attrs.add(attr);
352 }
353 return attrs;
354 }
355
356
357
358
359
360
361
362
363
364 public static List<ApplicationParam> getApplicationInitParams(Context context,
365 ContainerWrapperBean containerWrapper) {
366
367 return containerWrapper.getTomcatContainer().getApplicationInitParams(context);
368 }
369
370
371
372
373
374
375
376
377
378 public static ServletInfo getApplicationServlet(Context context, String servletName) {
379 Container container = context.findChild(servletName);
380
381 if (container instanceof Wrapper) {
382 Wrapper wrapper = (Wrapper) container;
383 return getServletInfo(wrapper, context.getName());
384 }
385 return null;
386 }
387
388
389
390
391
392
393
394
395
396 private static ServletInfo getServletInfo(Wrapper wrapper, String contextName) {
397 ServletInfo si = new ServletInfo();
398 si.setApplicationName(contextName.length() > 0 ? contextName : "/");
399 si.setServletName(wrapper.getName());
400 si.setServletClass(wrapper.getServletClass());
401 si.setAvailable(!wrapper.isUnavailable());
402 si.setLoadOnStartup(wrapper.getLoadOnStartup());
403 si.setRunAs(wrapper.getRunAs());
404 si.getMappings().addAll(Arrays.asList(wrapper.findMappings()));
405 if (wrapper instanceof StandardWrapper) {
406 StandardWrapper sw = (StandardWrapper) wrapper;
407 si.setAllocationCount(sw.getCountAllocated());
408
409
410 try {
411 Object errorCount = MethodUtils.invokeMethod(sw, "getErrorCount");
412 if (errorCount instanceof Long) {
413
414 si.setErrorCount((long) errorCount);
415 } else {
416
417 si.setErrorCount((int) errorCount);
418 }
419 } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
420 logger.error("Unable to find getErrorCount", e);
421 }
422
423 si.setLoadTime(sw.getLoadTime());
424 si.setMaxTime(sw.getMaxTime());
425 si.setMinTime(sw.getMinTime() == Long.MAX_VALUE ? 0 : sw.getMinTime());
426 si.setProcessingTime(sw.getProcessingTime());
427
428
429 try {
430 Object requestCount = MethodUtils.invokeMethod(sw, "getRequestCount");
431 if (requestCount instanceof Long) {
432
433 si.setRequestCount((long) requestCount);
434 } else {
435
436 si.setRequestCount((int) requestCount);
437 }
438 } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
439 logger.error("Unable to find getRequestCount", e);
440 }
441
442 }
443 return si;
444 }
445
446
447
448
449
450
451
452
453 public static List<ServletInfo> getApplicationServlets(Context context) {
454 Container[] cns = context.findChildren();
455 List<ServletInfo> servlets = new ArrayList<>(cns.length);
456 for (Container container : cns) {
457 if (container instanceof Wrapper) {
458 Wrapper wrapper = (Wrapper) container;
459 servlets.add(getServletInfo(wrapper, context.getName()));
460 }
461 }
462 return servlets;
463 }
464
465
466
467
468
469
470
471
472 public static List<ServletMapping> getApplicationServletMaps(Context context) {
473 String[] sms = context.findServletMappings();
474 List<ServletMapping> servletMaps = new ArrayList<>(sms.length);
475 for (String servletMapping : sms) {
476 if (servletMapping != null) {
477 String sn = context.findServletMapping(servletMapping);
478 if (sn != null) {
479 ServletMapping sm = new ServletMapping();
480 sm.setApplicationName(context.getName().length() > 0 ? context.getName() : "/");
481 sm.setUrl(servletMapping);
482 sm.setServletName(sn);
483 Container container = context.findChild(sn);
484 if (container instanceof Wrapper) {
485 Wrapper wrapper = (Wrapper) container;
486 sm.setServletClass(wrapper.getServletClass());
487 sm.setAvailable(!wrapper.isUnavailable());
488 }
489 servletMaps.add(sm);
490 }
491 }
492 }
493 return servletMaps;
494 }
495
496
497
498
499
500
501
502
503
504 public static List<FilterInfo> getApplicationFilters(Context context,
505 ContainerWrapperBean containerWrapper) {
506 return containerWrapper.getTomcatContainer().getApplicationFilters(context);
507 }
508
509 }