70
70
import org.apache.catalina.util.StringManager;
71
71
import org.apache.jasper.servlet.JasperLoader;
72
72
import org.apache.naming.JndiPermission;
73
import org.apache.naming.resources.ProxyDirContext;
73
74
import org.apache.naming.resources.Resource;
74
75
import org.apache.naming.resources.ResourceAttributes;
75
76
import org.apache.tomcat.util.IntrospectionUtils;
426
427
protected boolean hasExternalRepositories = false;
430
* Search external repositories first
432
protected boolean searchExternalFirst = false;
429
435
* need conversion for properties files
431
437
protected boolean needConvert = false;
444
450
* instability. As such, enabling this should be viewed as an option of last
445
451
* resort in a development environment and is not recommended in a
446
452
* production environment. If not specified, the default value of
447
* <code>false</code> will be used. Note that instances of
448
* java.util.TimerThread will always be terminate since a safe method exists
453
* <code>false</code> will be used.
451
455
private boolean clearReferencesStopThreads = false;
458
* Should Tomcat attempt to terminate any {@link java.util.TimerThread}s
459
* that have been started by the web application? If not specified, the
460
* default value of <code>false</code> will be used.
462
private boolean clearReferencesStopTimerThreads = false;
465
* Should Tomcat attempt to clear any ThreadLocal objects that are instances
466
* of classes loaded by this class loader. Failure to remove any such
467
* objects will result in a memory leak on web application stop, undeploy or
468
* reload. It is disabled by default since the clearing of the ThreadLocal
469
* objects is not performed in a thread-safe manner.
471
private boolean clearReferencesThreadLocals = false;
454
474
* Should Tomcat call {@link org.apache.juli.logging.LogFactory#release()}
455
475
* when the class loader is stopped? If not specified, the default value
456
476
* of <code>true</code> is used. Changing the default setting is likely to
459
479
private boolean clearReferencesLogFactoryRelease = true;
483
* Name of associated context used with logging and JMX to associate with
484
* the right web application. Particularly useful for the clear references
485
* messages. Defaults to unknown but if standard Tomcat components are used
486
* it will be updated during initialisation from the resources.
488
private String contextName = "unknown";
461
491
// ------------------------------------------------------------- Properties
479
509
this.resources = resources;
511
if (resources instanceof ProxyDirContext) {
512
contextName = ((ProxyDirContext) resources).getContextName();
518
* Return the context name for this class loader.
520
public String getContextName() {
522
return (this.contextName);
518
561
this.antiJARLocking = antiJARLocking;
565
* @return Returns the searchExternalFirst.
567
public boolean getSearchExternalFirst() {
568
return searchExternalFirst;
572
* @param searchExternalFirst Whether external repositories should be searched first
574
public void setSearchExternalFirst(boolean searchExternalFirst) {
575
this.searchExternalFirst = searchExternalFirst;
523
580
* If there is a Java SecurityManager create a read FilePermission
524
581
* or JndiPermission for the file directory path.
703
* Return the clearReferencesStopTimerThreads flag for this Context.
705
public boolean getClearReferencesStopTimerThreads() {
706
return (this.clearReferencesStopTimerThreads);
711
* Set the clearReferencesStopTimerThreads feature for this Context.
713
* @param clearReferencesStopTimerThreads The new flag value
715
public void setClearReferencesStopTimerThreads(
716
boolean clearReferencesStopTimerThreads) {
717
this.clearReferencesStopTimerThreads = clearReferencesStopTimerThreads;
646
722
* Return the clearReferencesLogFactoryRelease flag for this Context.
648
724
public boolean getClearReferencesLogFactoryRelease() {
742
* Return the clearReferencesThreadLocals flag for this Context.
744
public boolean getClearReferencesThreadLocals() {
745
return (this.clearReferencesThreadLocals);
750
* Set the clearReferencesThreadLocals feature for this Context.
752
* @param clearReferencesThreadLocals The new flag value
754
public void setClearReferencesThreadLocals(
755
boolean clearReferencesThreadLocals) {
756
this.clearReferencesThreadLocals = clearReferencesThreadLocals;
665
760
// ------------------------------------------------------- Reloader Methods
1007
1105
if (log.isTraceEnabled())
1008
1106
log.trace(" findClassInternal(" + name + ")");
1010
clazz = findClassInternal(name);
1011
} catch(ClassNotFoundException cnfe) {
1012
if (!hasExternalRepositories) {
1015
} catch(AccessControlException ace) {
1016
log.warn("WebappClassLoader.findClassInternal(" + name
1017
+ ") security exception: " + ace.getMessage(), ace);
1018
throw new ClassNotFoundException(name, ace);
1019
} catch (RuntimeException e) {
1020
if (log.isTraceEnabled())
1021
log.trace(" -->RuntimeException Rethrown", e);
1024
if ((clazz == null) && hasExternalRepositories) {
1107
if (hasExternalRepositories && searchExternalFirst) {
1109
clazz = super.findClass(name);
1110
} catch(ClassNotFoundException cnfe) {
1111
// Ignore - will search internal repositories next
1112
} catch(AccessControlException ace) {
1113
log.warn("WebappClassLoader.findClassInternal(" + name
1114
+ ") security exception: " + ace.getMessage(), ace);
1115
throw new ClassNotFoundException(name, ace);
1116
} catch (RuntimeException e) {
1117
if (log.isTraceEnabled())
1118
log.trace(" -->RuntimeException Rethrown", e);
1122
if ((clazz == null)) {
1124
clazz = findClassInternal(name);
1125
} catch(ClassNotFoundException cnfe) {
1126
if (!hasExternalRepositories || searchExternalFirst) {
1129
} catch(AccessControlException ace) {
1130
log.warn("WebappClassLoader.findClassInternal(" + name
1131
+ ") security exception: " + ace.getMessage(), ace);
1132
throw new ClassNotFoundException(name, ace);
1133
} catch (RuntimeException e) {
1134
if (log.isTraceEnabled())
1135
log.trace(" -->RuntimeException Rethrown", e);
1139
if ((clazz == null) && hasExternalRepositories && !searchExternalFirst) {
1026
1141
clazz = super.findClass(name);
1027
1142
} catch(AccessControlException ace) {
1079
1194
URL url = null;
1081
ResourceEntry entry = (ResourceEntry) resourceEntries.get(name);
1082
if (entry == null) {
1083
if (securityManager != null) {
1084
PrivilegedAction<ResourceEntry> dp =
1085
new PrivilegedFindResourceByName(name, name);
1086
entry = AccessController.doPrivileged(dp);
1088
entry = findResourceInternal(name, name);
1091
if (entry != null) {
1095
if ((url == null) && hasExternalRepositories)
1196
if (hasExternalRepositories && searchExternalFirst)
1197
url = super.findResource(name);
1200
ResourceEntry entry = (ResourceEntry) resourceEntries.get(name);
1201
if (entry == null) {
1202
if (securityManager != null) {
1203
PrivilegedAction<ResourceEntry> dp =
1204
new PrivilegedFindResourceByName(name, name);
1205
entry = AccessController.doPrivileged(dp);
1207
entry = findResourceInternal(name, name);
1210
if (entry != null) {
1215
if ((url == null) && hasExternalRepositories && !searchExternalFirst)
1096
1216
url = super.findResource(name);
1098
1218
if (log.isDebugEnabled()) {
1250
// Adding the results of a call to the superclass
1251
if (hasExternalRepositories && searchExternalFirst) {
1253
Enumeration<URL> otherResourcePaths = super.findResources(name);
1255
while (otherResourcePaths.hasMoreElements()) {
1256
result.addElement(otherResourcePaths.nextElement());
1130
1260
// Looking at the repositories
1131
1261
for (i = 0; i < repositoriesLength; i++) {
1819
1949
List<String> driverNames = (List<String>) obj.getClass().getMethod(
1820
1950
"clearJdbcDriverRegistrations").invoke(obj);
1821
1951
for (String name : driverNames) {
1822
log.error(sm.getString("webappClassLoader.clearJbdc", name));
1952
log.error(sm.getString("webappClassLoader.clearJbdc",
1953
contextName, name));
1824
1955
} catch (Exception e) {
1825
1956
// So many things to go wrong above...
1826
log.warn(sm.getString("webappClassLoader.jdbcRemoveFailed"), e);
1957
log.warn(sm.getString(
1958
"webappClassLoader.jdbcRemoveFailed", contextName), e);
1828
1960
if (is != null) {
1831
1963
} catch (IOException ioe) {
1832
1964
log.warn(sm.getString(
1833
"webappClassLoader.jdbcRemoveStreamError"), ioe);
1965
"webappClassLoader.jdbcRemoveStreamError",
1990
// TimerThread is not normally visible
2123
// TimerThread can be stopped safely so treat separately
1991
2124
if (thread.getClass().getName().equals(
1992
"java.util.TimerThread")) {
2125
"java.util.TimerThread") &&
2126
clearReferencesStopTimerThreads) {
1993
2127
clearReferencesStopTimerThread(thread);
1997
log.error(sm.getString("webappClassLoader.warnThread",
2131
if (isRequestThread(thread)) {
2132
log.error(sm.getString("webappClassLoader.warnRequestThread",
2133
contextName, thread.getName()));
2135
log.error(sm.getString("webappClassLoader.warnThread",
2136
contextName, thread.getName()));
2000
2139
// Don't try an stop the threads unless explicitly
2001
2140
// configured to do so
2025
2164
} catch (SecurityException e) {
2026
2165
log.warn(sm.getString(
2027
2166
"webappClassLoader.stopThreadFail",
2028
thread.getName()), e);
2167
thread.getName(), contextName), e);
2029
2168
} catch (NoSuchFieldException e) {
2030
2169
log.warn(sm.getString(
2031
2170
"webappClassLoader.stopThreadFail",
2032
thread.getName()), e);
2171
thread.getName(), contextName), e);
2033
2172
} catch (IllegalArgumentException e) {
2034
2173
log.warn(sm.getString(
2035
2174
"webappClassLoader.stopThreadFail",
2036
thread.getName()), e);
2175
thread.getName(), contextName), e);
2037
2176
} catch (IllegalAccessException e) {
2038
2177
log.warn(sm.getString(
2039
2178
"webappClassLoader.stopThreadFail",
2040
thread.getName()), e);
2179
thread.getName(), contextName), e);
2043
2182
// This method is deprecated and for good reason. This is
2194
* Look at a threads stack trace to see if it is a request thread or not. It
2195
* isn't perfect, but it should be good-enough for most cases.
2197
private boolean isRequestThread(Thread thread) {
2199
StackTraceElement[] elements = thread.getStackTrace();
2201
if (elements == null || elements.length == 0) {
2202
// Must have stopped already. Too late to ignore it. Assume not a
2203
// request processing thread.
2207
// Step through the methods in reverse order looking for calls to any
2208
// CoyoteAdapter method. All request threads will have this unless
2209
// Tomcat has been heavily modified - in which case there isn't much we
2211
for (int i = 0; i < elements.length; i++) {
2212
StackTraceElement element = elements[elements.length - (i+1)];
2213
if ("org.apache.catalina.connector.CoyoteAdapter".equals(
2214
element.getClassName())) {
2054
2222
private void clearReferencesStopTimerThread(Thread thread) {
2056
2224
// Need to get references to:
2079
2247
log.error(sm.getString("webappClassLoader.warnTimerThread",
2248
contextName, thread.getName()));
2082
2250
} catch (NoSuchFieldException e) {
2083
2251
log.warn(sm.getString(
2084
2252
"webappClassLoader.stopTimerThreadFail",
2085
thread.getName()), e);
2253
thread.getName(), contextName), e);
2086
2254
} catch (IllegalAccessException e) {
2087
2255
log.warn(sm.getString(
2088
2256
"webappClassLoader.stopTimerThreadFail",
2089
thread.getName()), e);
2257
thread.getName(), contextName), e);
2090
2258
} catch (NoSuchMethodException e) {
2091
2259
log.warn(sm.getString(
2092
2260
"webappClassLoader.stopTimerThreadFail",
2093
thread.getName()), e);
2261
thread.getName(), contextName), e);
2094
2262
} catch (InvocationTargetException e) {
2095
2263
log.warn(sm.getString(
2096
2264
"webappClassLoader.stopTimerThreadFail",
2097
thread.getName()), e);
2265
thread.getName(), contextName), e);
2132
2300
} catch (SecurityException e) {
2133
log.warn(sm.getString("webappClassLoader.clearThreadLocalFail"), e);
2301
log.warn(sm.getString("webappClassLoader.clearThreadLocalFail",
2134
2303
} catch (NoSuchFieldException e) {
2135
log.warn(sm.getString("webappClassLoader.clearThreadLocalFail"), e);
2304
log.warn(sm.getString("webappClassLoader.clearThreadLocalFail",
2136
2306
} catch (ClassNotFoundException e) {
2137
log.warn(sm.getString("webappClassLoader.clearThreadLocalFail"), e);
2307
log.warn(sm.getString("webappClassLoader.clearThreadLocalFail",
2138
2309
} catch (IllegalArgumentException e) {
2139
log.warn(sm.getString("webappClassLoader.clearThreadLocalFail"), e);
2310
log.warn(sm.getString("webappClassLoader.clearThreadLocalFail",
2140
2312
} catch (IllegalAccessException e) {
2141
log.warn(sm.getString("webappClassLoader.clearThreadLocalFail"), e);
2313
log.warn(sm.getString("webappClassLoader.clearThreadLocalFail",
2142
2315
} catch (NoSuchMethodException e) {
2143
log.warn(sm.getString("webappClassLoader.clearThreadLocalFail"), e);
2316
log.warn(sm.getString("webappClassLoader.clearThreadLocalFail",
2144
2318
} catch (InvocationTargetException e) {
2145
log.warn(sm.getString("webappClassLoader.clearThreadLocalFail"), e);
2319
log.warn(sm.getString("webappClassLoader.clearThreadLocalFail",
2185
Object[] args = new Object[4];
2360
Object[] args = new Object[5];
2361
args[0] = contextName;
2186
2362
if (key != null) {
2187
args[0] = key.getClass().getCanonicalName();
2188
args[1] = key.toString();
2363
args[1] = key.getClass().getCanonicalName();
2364
args[2] = key.toString();
2190
2366
if (value != null) {
2191
args[2] = value.getClass().getCanonicalName();
2192
args[3] = value.toString();
2367
args[3] = value.getClass().getCanonicalName();
2368
args[4] = value.toString();
2194
2370
if (value == null) {
2195
2371
if (log.isDebugEnabled()) {
2196
2372
log.debug(sm.getString(
2197
2373
"webappClassLoader.clearThreadLocalDebug",
2375
if (clearReferencesThreadLocals) {
2376
log.debug(sm.getString(
2377
"webappClassLoader.clearThreadLocalDebugClear"));
2201
2381
log.error(sm.getString(
2202
2382
"webappClassLoader.clearThreadLocal",
2384
if (clearReferencesThreadLocals) {
2385
log.info(sm.getString(
2386
"webappClassLoader.clearThreadLocalClear"));
2206
staleEntriesCount++;
2208
mapRemove.invoke(map, key);
2389
if (clearReferencesThreadLocals) {
2391
staleEntriesCount++;
2393
mapRemove.invoke(map, key);
2303
2489
} catch (ClassNotFoundException e) {
2304
log.info(sm.getString("webappClassLoader.clearRmiInfo"), e);
2490
log.info(sm.getString("webappClassLoader.clearRmiInfo",
2305
2492
} catch (SecurityException e) {
2306
log.warn(sm.getString("webappClassLoader.clearRmiFail"), e);
2493
log.warn(sm.getString("webappClassLoader.clearRmiFail",
2307
2495
} catch (NoSuchFieldException e) {
2308
log.warn(sm.getString("webappClassLoader.clearRmiFail"), e);
2496
log.warn(sm.getString("webappClassLoader.clearRmiFail",
2309
2498
} catch (IllegalArgumentException e) {
2310
log.warn(sm.getString("webappClassLoader.clearRmiFail"), e);
2499
log.warn(sm.getString("webappClassLoader.clearRmiFail",
2311
2501
} catch (IllegalAccessException e) {
2312
log.warn(sm.getString("webappClassLoader.clearRmiFail"), e);
2502
log.warn(sm.getString("webappClassLoader.clearRmiFail",
2373
2564
if (countRemoved > 0 && log.isDebugEnabled()) {
2374
2565
log.debug(sm.getString(
2375
2566
"webappClassLoader.clearReferencesResourceBundlesCount",
2376
Integer.valueOf(countRemoved)));
2567
Integer.valueOf(countRemoved), contextName));
2378
2569
} catch (SecurityException e) {
2379
2570
log.error(sm.getString(
2380
"webappClassLoader.clearReferencesResourceBundlesFail"), e);
2571
"webappClassLoader.clearReferencesResourceBundlesFail",
2381
2573
} catch (NoSuchFieldException e) {
2382
2574
if (System.getProperty("java.vendor").startsWith("Sun")) {
2383
2575
log.error(sm.getString(
2384
"webappClassLoader.clearReferencesResourceBundlesFail"), e);
2576
"webappClassLoader.clearReferencesResourceBundlesFail",
2386
2579
log.debug(sm.getString(
2387
"webappClassLoader.clearReferencesResourceBundlesFail"), e);
2580
"webappClassLoader.clearReferencesResourceBundlesFail",
2389
2583
} catch (IllegalArgumentException e) {
2390
2584
log.error(sm.getString(
2391
"webappClassLoader.clearReferencesResourceBundlesFail"), e);
2585
"webappClassLoader.clearReferencesResourceBundlesFail",
2392
2587
} catch (IllegalAccessException e) {
2393
2588
log.error(sm.getString(
2394
"webappClassLoader.clearReferencesResourceBundlesFail"), e);
2589
"webappClassLoader.clearReferencesResourceBundlesFail",