Skip to content
This repository was archived by the owner on Aug 17, 2018. It is now read-only.

Commit 31624b3

Browse files
author
Kin Man Chung
committed
Issue 13783: Web container startup performance regresses due to slow TLD
scanner. At Onstartup, the system jars are restricted to those with TLDs that have listeners. svn path=/trunk/; revision=1306
1 parent 2626341 commit 31624b3

1 file changed

Lines changed: 87 additions & 27 deletions

File tree

impl/src/main/java/org/apache/jasper/runtime/TldScanner.java

Lines changed: 87 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ public class TldScanner implements ServletContainerInitializer {
157157
// A Cache is used for system jar files.
158158
// The key is the name of the jar file, the value is an array of
159159
// TldInfo, one for each of the TLD in the jar file
160-
private static ConcurrentHashMap<String, TldInfo[]> jarTldCache =
160+
private static Map<String, TldInfo[]> jarTldCache =
161161
new ConcurrentHashMap<String, TldInfo[]>();
162162

163163
private static final String EAR_LIB_CLASSLOADER =
@@ -167,18 +167,25 @@ public class TldScanner implements ServletContainerInitializer {
167167
"org.glassfish.jsp.isStandaloneWebapp";
168168

169169
/**
170-
* The mapping of the 'global' tag library URI to the location (resource
171-
* path) of the TLD associated with that tag library. The location is
172-
* returned as a String array:
173-
* [0] The location
170+
* The mapping of the 'global' tag library URI (as defined in the tld) to
171+
* the location (resource path) of the TLD associated with that tag library.
172+
* The location is returned as a String array:
173+
* [0] The location of the tld file or the jar file that contains the tld
174174
* [1] If the location is a jar file, this is the location of the tld.
175175
*/
176176
private HashMap<String, String[]> mappings;
177177

178+
/**
179+
* A local cache for keeping track which jars have been scanned.
180+
*/
181+
private Map<String, TldInfo[]> jarTldCacheLocal =
182+
new HashMap<String, TldInfo[]>();
183+
178184
private ServletContext ctxt;
179185
private boolean isValidationEnabled;
180186
private boolean useMyFaces = false;
181-
private boolean scanListeners; // true if need to scan listeners in tld
187+
private boolean scanListeners; // true if scan tlds for listeners
188+
private boolean doneScanning; // true if all tld scanning done
182189

183190

184191
//*********************************************************************
@@ -249,17 +256,36 @@ public void onStartup(java.util.Set<java.lang.Class<?>> c,
249256
* second element denotes the name of the TLD entry in the jar file.
250257
* Returns null if the uri is not associated with any tag library 'exposed'
251258
* in the web application.
259+
*
260+
* This method may be called when the scanning is in one of states:
261+
* 1. Called from jspc script, then a full tld scan is required.
262+
* 2. The is the first call after servlet initialization, then system jars
263+
* that are knwon to have tlds but not listeners need to be scanned.
264+
* 3. Sebsequent calls, no need to scans.
252265
*/
253266

254267
@SuppressWarnings("unchecked")
255268
public String[] getLocation(String uri) throws JasperException {
269+
256270
if (mappings == null) {
271+
// Recovering the map done in onStart.
257272
mappings = (HashMap<String, String[]>) ctxt.getAttribute(
258273
Constants.JSP_TLD_URI_TO_LOCATION_MAP);
259-
if (mappings == null) {
260-
scanListeners = false;
261-
scanTlds();
262-
}
274+
}
275+
276+
if (mappings != null && mappings.get(uri) != null) {
277+
// if the uri is in, return that, and dont bother to do full scan
278+
return mappings.get(uri);
279+
}
280+
281+
if (! doneScanning) {
282+
scanListeners = false;
283+
scanTlds();
284+
doneScanning = true;
285+
}
286+
if (mappings == null) {
287+
// Should never happend
288+
return null;
263289
}
264290
return mappings.get(uri);
265291
}
@@ -269,11 +295,25 @@ Map<URI, List<String>> getTldMap() {
269295
/*
270296
* System jars with tlds may be passed as a special
271297
* ServletContext attribute
298+
* Map key: a JarURI
299+
* Map value: list of tlds in the jar file
272300
*/
273301
return (Map<URI, List<String>>)
274302
ctxt.getAttribute("com.sun.appserv.tld.map");
275303
}
276304

305+
@SuppressWarnings("unchecked")
306+
Map<URI, List<String>> getTldListenerMap() {
307+
/*
308+
* System jars with tlds that are known to contain a listener, and
309+
* may be passed as a special ServletContext attribute
310+
* Map key: a JarURI
311+
* Map value: list of tlds in the jar file
312+
*/
313+
return (Map<URI, List<String>>)
314+
ctxt.getAttribute("com.sun.appserv.tldlistener.map");
315+
}
316+
277317
/**
278318
* Returns the type of a URI:
279319
* ABS_URI
@@ -290,9 +330,21 @@ public static int uriType(String uri) {
290330
}
291331
}
292332

333+
/**
334+
* Scan the all the tlds accessible in the web app.
335+
* For performance reasons, this is done in two stages. At servlet
336+
* initialization time, we only scan the jar files for listeners. The
337+
* container passes a list of system jar files that are known to contain
338+
* tlds with listeners. The rest of the jar files will be scanned when
339+
* a JSP page with a tld referenced is compiled.
340+
*/
293341
private void scanTlds() throws JasperException {
294342

295343
mappings = new HashMap<String, String[]>();
344+
345+
// Make a local copy of the system jar cache
346+
jarTldCacheLocal.putAll(jarTldCache);
347+
296348
try {
297349
processWebDotXml();
298350
scanJars();
@@ -311,6 +363,12 @@ private void scanTlds() throws JasperException {
311363
*/
312364
private void processWebDotXml() throws Exception {
313365

366+
367+
// Skip if we are only looking for listeners
368+
if (scanListeners) {
369+
return;
370+
}
371+
314372
JspConfigDescriptor jspConfig = ctxt.getJspConfigDescriptor();
315373
if (jspConfig == null) {
316374
return;
@@ -364,17 +422,17 @@ private void scanJar(JarURLConnection conn, List<String> tldNames,
364422
throws JasperException {
365423

366424
String resourcePath = conn.getJarFileURL().toString();
367-
TldInfo[] cachedTldInfos = jarTldCache.get(resourcePath);
425+
TldInfo[] tldInfos = jarTldCacheLocal.get(resourcePath);
368426

369-
// Optimize for most common cases
370-
if (cachedTldInfos != null && cachedTldInfos.length == 0) {
427+
// Optimize for most common cases: jars known to NOT have tlds
428+
if (tldInfos != null && tldInfos.length == 0) {
371429
return;
372430
}
373431

374-
// scan the tld if the jar is local, or if it has not been cached.
375-
ArrayList<TldInfo> tldInfoA = new ArrayList<TldInfo>();
376-
if (isLocal || cachedTldInfos == null) {
432+
// scan the tld if the jar has not been cached.
433+
if (tldInfos == null) {
377434
JarFile jarFile = null;
435+
ArrayList<TldInfo> tldInfoA = new ArrayList<TldInfo>();
378436
try {
379437
conn.setUseCaches(false);
380438
jarFile = conn.getJarFile();
@@ -418,15 +476,12 @@ private void scanJar(JarURLConnection conn, List<String> tldNames,
418476
}
419477
}
420478
}
421-
}
422-
423-
// Update the jar TLD cache
424-
TldInfo[] tldInfos = tldInfoA.toArray(new TldInfo[tldInfoA.size()]);
425-
if (! isLocal) {
426-
if (cachedTldInfos == null) {
479+
// Update the jar TLD cache
480+
tldInfos = tldInfoA.toArray(new TldInfo[tldInfoA.size()]);
481+
jarTldCacheLocal.put(resourcePath, tldInfos);
482+
if (!isLocal) {
483+
// Also update the global cache;
427484
jarTldCache.put(resourcePath, tldInfos);
428-
} else {
429-
tldInfos = cachedTldInfos;
430485
}
431486
}
432487

@@ -525,8 +580,7 @@ private void processTldsInFileSystem(String startPath)
525580
}
526581

527582
/**
528-
* Scan the given TLD for uri and listeners elements. Update the tld map
529-
* and register any listeners found.
583+
* Scan the given TLD for uri and listeners elements.
530584
*
531585
* @param resourcePath the resource path for the jar file or the tld file.
532586
* @param entryName If the resource path is a jar file, then the name of
@@ -597,7 +651,13 @@ private void scanJars() throws Exception {
597651
Thread.currentThread().getContextClassLoader();
598652
ClassLoader loader = webappLoader;
599653

600-
Map<URI, List<String>> tldMap = getTldMap();
654+
Map<URI, List<String>> tldMap;
655+
if (scanListeners) {
656+
tldMap = getTldListenerMap();
657+
} else {
658+
tldMap= getTldMap();
659+
}
660+
601661
Boolean isStandalone = (Boolean)
602662
ctxt.getAttribute(IS_STANDALONE_ATTRIBUTE_NAME);
603663

0 commit comments

Comments
 (0)