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