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 int reqCount = 0;
164 int 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 reqCount += sw.getRequestCount();
174 errCount += sw.getErrorCount();
175 procTime += sw.getProcessingTime();
176 if (sw.getRequestCount() > 0) {
177 minTime = Math.min(minTime, sw.getMinTime());
178 }
179 maxTime = Math.max(maxTime, sw.getMaxTime());
180 }
181 }
182 app.setServletCount(svltCount);
183 app.setRequestCount(reqCount);
184 app.setErrorCount(errCount);
185 app.setProcessingTime(procTime);
186 app.setMinTime(minTime == Long.MAX_VALUE ? 0 : minTime);
187 app.setMaxTime(maxTime);
188 }
189
190
191
192
193
194
195
196
197
198
199 public static int[] getApplicationDataSourceUsageScores(Context context,
200 ResourceResolver resolver, ContainerWrapperBean containerWrapper) {
201
202 logger.debug("Calculating datasource usage score");
203
204 int[] scores = {0, 0};
205 List<ApplicationResource> appResources;
206 try {
207 appResources = resolver.getApplicationResources(context, containerWrapper);
208 } catch (NamingException e) {
209 throw new RuntimeException(e);
210 }
211 for (ApplicationResource appResource : appResources) {
212 if (appResource.getDataSourceInfo() != null) {
213 scores[0] = Math.max(scores[0], appResource.getDataSourceInfo().getBusyScore());
214 scores[1] = Math.max(scores[1], appResource.getDataSourceInfo().getEstablishedScore());
215 }
216 }
217 return scores;
218 }
219
220
221
222
223
224
225
226
227
228
229 public static ApplicationSession getApplicationSession(Session session, boolean calcSize,
230 boolean addAttributes) {
231
232 ApplicationSession sbean = null;
233 if (session != null && session.isValid()) {
234 sbean = new ApplicationSession();
235
236 sbean.setId(session.getId());
237 sbean.setCreationTime(new Date(session.getCreationTime()));
238 sbean.setLastAccessTime(new Date(session.getLastAccessedTime()));
239 sbean.setMaxIdleTime(session.getMaxInactiveInterval() * 1000);
240 sbean.setManagerType(session.getManager().getClass().getName());
241
242
243
244 try {
245 Object info = MethodUtils.invokeMethod(session, "getInfo");
246 sbean.setInfo(String.valueOf(info));
247 } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
248 sbean.setInfo(session.getClass().getSimpleName());
249 logger.trace("Cannot determine session info for tomcat 8+", e);
250 }
251
252 boolean sessionSerializable = true;
253 int attributeCount = 0;
254 long size = 0;
255
256 HttpSession httpSession = session.getSession();
257 Set<Object> processedObjects = new HashSet<>(1000);
258
259
260 processedObjects.add(httpSession);
261 try {
262 for (String name : Collections.list(httpSession.getAttributeNames())) {
263 Object obj = httpSession.getAttribute(name);
264 sessionSerializable = sessionSerializable && obj instanceof Serializable;
265
266 long objSize = 0;
267 if (calcSize) {
268 try {
269 objSize += Instruments.sizeOf(name, processedObjects);
270 objSize += Instruments.sizeOf(obj, processedObjects);
271 } catch (Exception ex) {
272 logger.error("Cannot estimate size of attribute '{}'", name, ex);
273 }
274 }
275
276 if (addAttributes) {
277 Attribute saBean = new Attribute();
278 saBean.setName(name);
279 saBean.setType(ClassUtils.getQualifiedName(obj.getClass()));
280 saBean.setValue(obj);
281 saBean.setSize(objSize);
282 saBean.setSerializable(obj instanceof Serializable);
283 sbean.addAttribute(saBean);
284 }
285 attributeCount++;
286 size += objSize;
287 }
288 String lastAccessedIp =
289 (String) httpSession.getAttribute(ApplicationSession.LAST_ACCESSED_BY_IP);
290 if (lastAccessedIp != null) {
291 sbean.setLastAccessedIp(lastAccessedIp);
292 sbean.setLastAccessedIpLocale(
293 (Locale) httpSession.getAttribute(ApplicationSession.LAST_ACCESSED_LOCALE));
294 }
295
296 } catch (IllegalStateException e) {
297 logger.info("Session appears to be invalidated, ignore");
298 logger.trace("", e);
299 }
300
301 sbean.setObjectCount(attributeCount);
302 sbean.setSize(size);
303 sbean.setSerializable(sessionSerializable);
304 }
305
306 return sbean;
307 }
308
309
310
311
312
313
314
315
316 public static List<Attribute> getApplicationAttributes(Context context) {
317 List<Attribute> attrs = new ArrayList<>();
318 ServletContext servletCtx = context.getServletContext();
319 for (String attrName : Collections.list(servletCtx.getAttributeNames())) {
320 Object attrValue = servletCtx.getAttribute(attrName);
321
322 Attribute attr = new Attribute();
323 attr.setName(attrName);
324 attr.setValue(attrValue);
325 attr.setType(ClassUtils.getQualifiedName(attrValue.getClass()));
326 attrs.add(attr);
327 }
328 return attrs;
329 }
330
331
332
333
334
335
336
337
338
339 public static List<ApplicationParam> getApplicationInitParams(Context context,
340 ContainerWrapperBean containerWrapper) {
341
342 return containerWrapper.getTomcatContainer().getApplicationInitParams(context);
343 }
344
345
346
347
348
349
350
351
352
353 public static ServletInfo getApplicationServlet(Context context, String servletName) {
354 Container container = context.findChild(servletName);
355
356 if (container instanceof Wrapper) {
357 Wrapper wrapper = (Wrapper) container;
358 return getServletInfo(wrapper, context.getName());
359 }
360 return null;
361 }
362
363
364
365
366
367
368
369
370
371 private static ServletInfo getServletInfo(Wrapper wrapper, String contextName) {
372 ServletInfo si = new ServletInfo();
373 si.setApplicationName(contextName.length() > 0 ? contextName : "/");
374 si.setServletName(wrapper.getName());
375 si.setServletClass(wrapper.getServletClass());
376 si.setAvailable(!wrapper.isUnavailable());
377 si.setLoadOnStartup(wrapper.getLoadOnStartup());
378 si.setRunAs(wrapper.getRunAs());
379 si.getMappings().addAll(Arrays.asList(wrapper.findMappings()));
380 if (wrapper instanceof StandardWrapper) {
381 StandardWrapper sw = (StandardWrapper) wrapper;
382 si.setAllocationCount(sw.getCountAllocated());
383 si.setErrorCount(sw.getErrorCount());
384 si.setLoadTime(sw.getLoadTime());
385 si.setMaxTime(sw.getMaxTime());
386 si.setMinTime(sw.getMinTime() == Long.MAX_VALUE ? 0 : sw.getMinTime());
387 si.setProcessingTime(sw.getProcessingTime());
388 si.setRequestCount(sw.getRequestCount());
389 }
390 return si;
391 }
392
393
394
395
396
397
398
399
400 public static List<ServletInfo> getApplicationServlets(Context context) {
401 Container[] cns = context.findChildren();
402 List<ServletInfo> servlets = new ArrayList<>(cns.length);
403 for (Container container : cns) {
404 if (container instanceof Wrapper) {
405 Wrapper wrapper = (Wrapper) container;
406 servlets.add(getServletInfo(wrapper, context.getName()));
407 }
408 }
409 return servlets;
410 }
411
412
413
414
415
416
417
418
419 public static List<ServletMapping> getApplicationServletMaps(Context context) {
420 String[] sms = context.findServletMappings();
421 List<ServletMapping> servletMaps = new ArrayList<>(sms.length);
422 for (String servletMapping : sms) {
423 if (servletMapping != null) {
424 String sn = context.findServletMapping(servletMapping);
425 if (sn != null) {
426 ServletMapping sm = new ServletMapping();
427 sm.setApplicationName(context.getName().length() > 0 ? context.getName() : "/");
428 sm.setUrl(servletMapping);
429 sm.setServletName(sn);
430 Container container = context.findChild(sn);
431 if (container instanceof Wrapper) {
432 Wrapper wrapper = (Wrapper) container;
433 sm.setServletClass(wrapper.getServletClass());
434 sm.setAvailable(!wrapper.isUnavailable());
435 }
436 servletMaps.add(sm);
437 }
438 }
439 }
440 return servletMaps;
441 }
442
443
444
445
446
447
448
449
450
451 public static List<FilterInfo> getApplicationFilters(Context context,
452 ContainerWrapperBean containerWrapper) {
453 return containerWrapper.getTomcatContainer().getApplicationFilters(context);
454 }
455
456 }