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

Commit 9e97797

Browse files
author
Kin Man Chung
committed
- Cache TLD information on system jar files.
svn path=/trunk/; revision=1204
1 parent fdbda0e commit 9e97797

1 file changed

Lines changed: 175 additions & 90 deletions

File tree

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

Lines changed: 175 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@
6767
import java.net.URLConnection;
6868
import java.util.Enumeration;
6969
import java.util.HashMap;
70+
import java.util.ArrayList;
71+
import java.util.concurrent.ConcurrentHashMap;
7072
import java.util.HashSet;
7173
import java.util.Iterator;
7274
import java.util.List;
@@ -124,7 +126,7 @@
124126
*
125127
* @author Pierre Delisle
126128
* @author Jan Luehe
127-
* @author Kin-man Chung servlet 3.0 JSP plugin
129+
* @author Kin-man Chung servlet 3.0 JSP plugin, tld cache etc
128130
*/
129131

130132
public class TldScanner implements ServletContainerInitializer {
@@ -148,6 +150,12 @@ public class TldScanner implements ServletContainerInitializer {
148150
private static HashSet<String> systemUris = new HashSet<String>();
149151
private static HashSet<String> systemUrisJsf = new HashSet<String>();
150152

153+
// A Cache is used for system jar files.
154+
// The key is the name of the jar file, the value is an array of
155+
// TldInfo, one for each of the TLD in the jar file
156+
private static ConcurrentHashMap<String, TldInfo[]> jarTldCache =
157+
new ConcurrentHashMap<String, TldInfo[]>();
158+
151159
/**
152160
* The mapping of the 'global' tag library URI to the location (resource
153161
* path) of the TLD associated with that tag library. The location is
@@ -318,66 +326,146 @@ private void processWebDotXml() throws Exception {
318326

319327
/**
320328
* Scans the given JarURLConnection for TLD files located in META-INF
321-
* (or a subdirectory of it), adding an implicit map entry to the taglib
322-
* map for any TLD that has a <uri> element.
329+
* (or a subdirectory of it). If the scanning in is done as part of the
330+
* ServletContextInitializer, the listeners in the tlds in this jar file
331+
* are added to the servlet context, and for any TLD that has a <uri>
332+
* element, an implicit map entry is added to the taglib map.
323333
*
324334
* @param conn The JarURLConnection to the JAR file to scan
325335
* @param tldNames the list of tld element to scan. The null value
326336
* indicates all the tlds in this case.
327-
* @param isLocal True is the jar file is under WEB-INF
328-
* JAR should be ignored, false otherwise
337+
* @param isLocal True if the jar file is under WEB-INF
338+
* false otherwise
329339
*/
330340
private void scanJar(JarURLConnection conn, List<String> tldNames,
331341
boolean isLocal)
332342
throws JasperException {
333343

334-
JarFile jarFile = null;
335344
String resourcePath = conn.getJarFileURL().toString();
336-
try {
337-
conn.setUseCaches(false);
338-
jarFile = conn.getJarFile();
339-
if (tldNames != null) {
340-
for (String tldName : tldNames) {
341-
JarEntry entry = jarFile.getJarEntry(tldName);
342-
InputStream stream = jarFile.getInputStream(entry);
343-
scanTld(resourcePath, tldName, stream, isLocal);
344-
}
345-
} else {
346-
Enumeration<JarEntry> entries = jarFile.entries();
347-
while (entries.hasMoreElements()) {
348-
JarEntry entry = entries.nextElement();
349-
String name = entry.getName();
350-
if (!name.startsWith("META-INF/")) continue;
351-
if (!name.endsWith(".tld")) continue;
352-
InputStream stream = jarFile.getInputStream(entry);
353-
scanTld(resourcePath, name, stream, isLocal);
345+
TldInfo[] cachedTldInfos = jarTldCache.get(resourcePath);
346+
347+
// Optimize for most common cases
348+
if (cachedTldInfos != null && cachedTldInfos.length == 0) {
349+
return;
350+
}
351+
352+
// scan the tld if the jar is local, or if it has not been cached.
353+
ArrayList<TldInfo> tldInfoA = new ArrayList<TldInfo>();
354+
if (isLocal || cachedTldInfos == null) {
355+
JarFile jarFile = null;
356+
try {
357+
conn.setUseCaches(false);
358+
jarFile = conn.getJarFile();
359+
if (tldNames != null) {
360+
for (String tldName : tldNames) {
361+
JarEntry entry = jarFile.getJarEntry(tldName);
362+
InputStream stream = jarFile.getInputStream(entry);
363+
tldInfoA.add(scanTld(resourcePath, tldName, stream));
364+
}
365+
} else {
366+
Enumeration<JarEntry> entries = jarFile.entries();
367+
while (entries.hasMoreElements()) {
368+
JarEntry entry = entries.nextElement();
369+
String name = entry.getName();
370+
if (!name.startsWith("META-INF/")) continue;
371+
if (!name.endsWith(".tld")) continue;
372+
InputStream stream = jarFile.getInputStream(entry);
373+
tldInfoA.add(scanTld(resourcePath, name, stream));
374+
}
354375
}
355-
}
356-
} catch (IOException ex) {
357-
if (resourcePath.startsWith(FILE_PROTOCOL) &&
358-
!((new File(resourcePath)).exists())) {
359-
if (log.isLoggable(Level.WARNING)) {
360-
log.log(Level.WARNING,
376+
} catch (IOException ex) {
377+
if (resourcePath.startsWith(FILE_PROTOCOL) &&
378+
!((new File(resourcePath)).exists())) {
379+
if (log.isLoggable(Level.WARNING)) {
380+
log.log(Level.WARNING,
361381
Localizer.getMessage("jsp.warn.nojar",
362382
resourcePath),
363383
ex);
384+
}
385+
} else {
386+
throw new JasperException(
387+
Localizer.getMessage("jsp.error.jar.io", resourcePath),
388+
ex);
389+
}
390+
} finally {
391+
if (jarFile != null) {
392+
try {
393+
jarFile.close();
394+
} catch (Throwable t) {
395+
// ignore
396+
}
364397
}
398+
}
399+
}
400+
401+
// Update the jar TLD cache
402+
TldInfo[] tldInfos = tldInfoA.toArray(new TldInfo[tldInfoA.size()]);
403+
if (! isLocal) {
404+
if (cachedTldInfos == null) {
405+
jarTldCache.put(resourcePath, tldInfos);
365406
} else {
366-
throw new JasperException(
367-
Localizer.getMessage("jsp.error.jar.io", resourcePath),
368-
ex);
407+
tldInfos = cachedTldInfos;
369408
}
370-
} finally {
371-
if (jarFile != null) {
372-
try {
373-
jarFile.close();
374-
} catch (Throwable t) {
375-
// ignore
409+
}
410+
411+
// Iterate over tldinfos to add listeners or to map tldlocations
412+
for (TldInfo tldInfo: tldInfos) {
413+
if (scanListeners) {
414+
addListener(tldInfo, isLocal);
415+
}
416+
mapTldLocation(resourcePath, tldInfo, isLocal);
417+
}
418+
}
419+
420+
private void addListener(TldInfo tldInfo, boolean isLocal) {
421+
String uri = tldInfo.getUri();
422+
if (!systemUrisJsf.contains(uri)
423+
|| (isLocal && useMyFaces)
424+
|| (!isLocal && !useMyFaces)) {
425+
for (String listenerClassName: tldInfo.getListeners()) {
426+
if (log.isLoggable(Level.FINE)) {
427+
log.fine( "Add tld listener " + listenerClassName);
376428
}
429+
ctxt.addListener(listenerClassName);
377430
}
378431
}
379432
}
380433

434+
private void mapTldLocation(String resourcePath, TldInfo tldInfo,
435+
boolean isLocal) {
436+
437+
String uri = tldInfo.getUri();
438+
if (uri == null) {
439+
return;
440+
}
441+
442+
if ((isLocal
443+
// Local tld files override the tlds in the jar files,
444+
// unless it is in a system jar (except when using myfaces)
445+
&& mappings.get(uri) == null
446+
&& !systemUris.contains(uri)
447+
&& (!systemUrisJsf.contains(uri) || useMyFaces)
448+
) ||
449+
(!isLocal
450+
// Jars are scanned bottom up, so jars in WEB-INF override
451+
// thos in the system (except when using myfaces)
452+
&& (mappings.get(uri) == null
453+
|| systemUris.contains(uri)
454+
|| (systemUrisJsf.contains(uri) && !useMyFaces)
455+
)
456+
)
457+
) {
458+
String entryName = tldInfo.getEntryName();
459+
if (log.isLoggable(Level.FINE)) {
460+
log.fine("Add tld map from tld in " +
461+
(isLocal? "WEB-INF": "jar: ") + uri + "=>" +
462+
resourcePath + "," + entryName);
463+
}
464+
mappings.put(uri, new String[] {resourcePath, entryName});
465+
}
466+
}
467+
468+
381469
/*
382470
* Searches the filesystem under /WEB-INF for any TLD files, and scans
383471
* them for <uri> and <listener> elements.
@@ -404,7 +492,12 @@ private void processTldsInFileSystem(String startPath)
404492
path));
405493
}
406494
InputStream stream = ctxt.getResourceAsStream(path);
407-
scanTld(path, null, stream, true);
495+
TldInfo tldInfo = scanTld(path, null, stream);
496+
// Add listeners or to map tldlocations for this TLD
497+
if (scanListeners) {
498+
addListener(tldInfo, true);
499+
}
500+
mapTldLocation(path, tldInfo, true);
408501
}
409502
}
410503
}
@@ -414,13 +507,13 @@ private void processTldsInFileSystem(String startPath)
414507
* and register any listeners found.
415508
*
416509
* @param resourcePath the resource path for the jar file or the tld file.
417-
* @entryName If the resource path is a jar file, then the name of the tld
418-
* file in the jar, else should be null.
419-
* @stream The input stream for the tld
420-
* @isLocal True if the tld is a WEB-INF file, false if it is in a jar file.
510+
* @param entryName If the resource path is a jar file, then the name of
511+
* the tld file in the jar, else should be null.
512+
* @param stream The input stream for the tld
513+
* @return The TldInfo for this tld
421514
*/
422-
private void scanTld(String resourcePath, String entryName,
423-
InputStream stream, boolean isLocal)
515+
private TldInfo scanTld(String resourcePath, String entryName,
516+
InputStream stream)
424517
throws JasperException {
425518
try {
426519
// Parse the tag library descriptor at the specified resource path
@@ -433,55 +526,23 @@ private void scanTld(String resourcePath, String entryName,
433526
uri = uriNode.getBody();
434527
}
435528

436-
if (scanListeners) {
437-
Iterator<TreeNode>listeners = tld.findChildren("listener");
438-
while (listeners.hasNext()) {
439-
TreeNode listener = listeners.next();
440-
TreeNode listenerClass = listener.findChild("listener-class");
441-
if (listenerClass != null) {
442-
String listenerClassName = listenerClass.getBody();
443-
if (listenerClassName != null) {
444-
if (!systemUrisJsf.contains(uri)
445-
|| (isLocal && useMyFaces)
446-
|| (!isLocal && !useMyFaces)) {
447-
if (log.isLoggable(Level.FINE)) {
448-
log.fine( "Add tld listener " +
449-
listenerClassName);
450-
}
451-
ctxt.addListener(listenerClassName);
452-
}
453-
}
529+
ArrayList<String> listeners = new ArrayList<String>();
530+
531+
Iterator<TreeNode>listenerNodes = tld.findChildren("listener");
532+
while (listenerNodes.hasNext()) {
533+
TreeNode listener = listenerNodes.next();
534+
TreeNode listenerClass = listener.findChild("listener-class");
535+
if (listenerClass != null) {
536+
String listenerClassName = listenerClass.getBody();
537+
if (listenerClassName != null) {
538+
listeners.add(listenerClassName);
454539
}
455540
}
456541
}
457542

458-
if (uri == null) {
459-
return;
460-
}
543+
return new TldInfo(uri, entryName,
544+
listeners.toArray(new String[listeners.size()]));
461545

462-
if ((isLocal
463-
// Local tld files override the tlds in the jar files,
464-
// unless it is in a system jar (except when using myfaces)
465-
&& mappings.get(uri) == null
466-
&& !systemUris.contains(uri)
467-
&& (!systemUrisJsf.contains(uri) || useMyFaces)
468-
) ||
469-
(!isLocal
470-
// Jars are scanned bottom up, so jars in WEB-INF override
471-
// thos in the system (except when using myfaces)
472-
&& (mappings.get(uri) == null
473-
|| systemUris.contains(uri)
474-
|| (systemUrisJsf.contains(uri) && !useMyFaces)
475-
)
476-
)
477-
) {
478-
if (log.isLoggable(Level.FINE)) {
479-
log.fine("Add tld map from tld in " +
480-
(isLocal? "WEB-INF": "jar: ") + uri + "=>" +
481-
resourcePath + "," + entryName);
482-
}
483-
mappings.put(uri, new String[] {resourcePath, entryName});
484-
}
485546
} finally {
486547
if (stream != null) {
487548
try {
@@ -549,4 +610,28 @@ private void scanJars() throws Exception {
549610
}
550611
}
551612
}
613+
614+
static class TldInfo {
615+
private String entryName; // The name of the tld file
616+
private String uri; // The uri name for the tld
617+
private String[] listeners; // The listeners in the tld
618+
619+
public TldInfo(String uri, String entryName, String[] listeners) {
620+
this.uri = uri;
621+
this.entryName = entryName;
622+
this.listeners = listeners;
623+
}
624+
625+
public String getEntryName() {
626+
return entryName;
627+
}
628+
629+
public String getUri() {
630+
return uri;
631+
}
632+
633+
public String[] getListeners() {
634+
return listeners;
635+
}
636+
}
552637
}

0 commit comments

Comments
 (0)