bundles/org.apache.jasper.glassfish/src/org/apache/jasper/runtime/TldScanner.java
private void scanJars() throws Exception {

        ClassLoader webappLoader =
            Thread.currentThread().getContextClassLoader();
        ClassLoader loader = webappLoader;

        Map<URI, List<String>> tldMap;
        if (scanListeners) {
            tldMap = getTldListenerMap();
        } else {
            tldMap= getTldMap();
        }

        Boolean isStandalone = (Boolean)
            ctxt.getAttribute(IS_STANDALONE_ATTRIBUTE_NAME);

        while (loader != null) {
            if (loader instanceof URLClassLoader) {
                boolean isLocal = (loader == webappLoader);
                URL[] urls = ((URLClassLoader) loader).getURLs();
                List<String> extraJars = new ArrayList<String>();

                for (int i=0; i<urls.length; i++) {
                    URLConnection conn = urls[i].openConnection();
                    JarURLConnection jconn = null;
                    if (conn instanceof JarURLConnection) {
                        jconn = (JarURLConnection) conn;
                    } else {
                        String urlStr = urls[i].toString();
                        if (urlStr.startsWith(FILE_PROTOCOL)
                                && urlStr.endsWith(JAR_FILE_SUFFIX)) {
                            URL jarURL = new URL("jar:" + urlStr + "!/");
                            jconn = (JarURLConnection) jarURL.openConnection();
                        }
                    }
                    if (jconn != null) {
                        jconn.setUseCaches(false);
                        if (isLocal) {
                            // For local jars, collect the jar files in the
                            // Manifest Class-Path, to be scanned later.
                            addManifestClassPath(null, extraJars, jconn);
                        }
                        scanJar(jconn, null, isLocal);
                    }
                }

                // Scan the jars collected from manifest class-path.  Expand
                // the list to include jar files from their manifest classpath.
                if (extraJars.size() > 0) {
                    List<String> newJars;
                    do {
                        newJars = new ArrayList<String>();
                        for (String jar: extraJars) {
                            URL jarURL = new URL("jar:" + jar + "!/");
                            JarURLConnection jconn =
                                    (JarURLConnection) jarURL.openConnection();
                            jconn.setUseCaches(false);
                            if (addManifestClassPath(extraJars,newJars,jconn)){
                                scanJar(jconn, null, true);
                            }
                        }
                        extraJars.addAll(newJars);
                    } while (newJars.size() != 0);
                }
            }

            if (tldMap != null && isStandalone != null) {
                if (isStandalone.booleanValue()) {
                    break;
                } else {
                    if (EAR_LIB_CLASSLOADER.equals(
                            loader.getClass().getName())) {
                        // Do not walk up classloader delegation chain beyond
                        // EarLibClassLoader
                        break;
                    }
                }
            }

            loader = loader.getParent();
        }

        if (tldMap != null) {
            for (URI uri : tldMap.keySet()) {
                URL jarURL = new URL("jar:" + uri.toString() + "!/");
                scanJar((JarURLConnection)jarURL.openConnection(),
                        tldMap.get(uri), false);
            }
        }
    }
private void scanJars() throws Exception {

        ClassLoader webappLoader =
            Thread.currentThread().getContextClassLoader();
        ClassLoader loader = webappLoader;

        Map<URI, List<String>> tldMap;
        if (scanListeners) {
            tldMap = getTldListenerMap();
        } else {
            tldMap= getTldMap();
        }

        Boolean isStandalone = (Boolean)
            ctxt.getAttribute(IS_STANDALONE_ATTRIBUTE_NAME);

        while (loader != null) {
            if (loader instanceof URLClassLoader) {
                boolean isLocal = (loader == webappLoader);
                URL[] urls = ((URLClassLoader) loader).getURLs();
                List<String> extraJars = new ArrayList<String>();

                for (int i=0; i<urls.length; i++) {
                    URLConnection conn = urls[i].openConnection();
                    JarURLConnection jconn = null;
                    if (conn instanceof JarURLConnection) {
                        jconn = (JarURLConnection) conn;
                    } else {
                        String urlStr = urls[i].toString();
                        if (urlStr.startsWith(FILE_PROTOCOL)
                                && urlStr.endsWith(JAR_FILE_SUFFIX)) {
                            URL jarURL = new URL("jar:" + urlStr + "!/");
                            jconn = (JarURLConnection) jarURL.openConnection();
                        }
                    }
                    if (jconn != null) {
                        jconn.setUseCaches(false);
                        if (isLocal) {
                            // For local jars, collect the jar files in the
                            // Manifest Class-Path, to be scanned later.
                            addManifestClassPath(null, extraJars, jconn);
                        }
                        scanJar(jconn, null, isLocal);
                    }
                }

                // Scan the jars collected from manifest class-path.  Expand
                // the list to include jar files from their manifest classpath.
                if (extraJars.size() > 0) {
                    List<String> newJars;
                    do {
                        newJars = new ArrayList<String>();
                        for (String jar: extraJars) {
                            URL jarURL = new URL("jar:" + jar + "!/");
                            JarURLConnection jconn =
                                    (JarURLConnection) jarURL.openConnection();
                            jconn.setUseCaches(false);
                            if (addManifestClassPath(extraJars,newJars,jconn)){
                                scanJar(jconn, null, true);
                            }
                        }
                        extraJars.addAll(newJars);
                    } while (newJars.size() != 0);
                }
            }

            if (tldMap != null && isStandalone != null) {
                if (isStandalone.booleanValue()) {
                    break;
                } else {
                    if (EAR_LIB_CLASSLOADER.equals(
                            loader.getClass().getName())) {
                        // Do not walk up classloader delegation chain beyond
                        // EarLibClassLoader
                        break;
                    }
                }
            }

            loader = loader.getParent();
        }

        if (tldMap != null) {
            for (URI uri : tldMap.keySet()) {
                URL jarURL = new URL("jar:" + uri.toString() + "!/");
                scanJar((JarURLConnection)jarURL.openConnection(),
                        tldMap.get(uri), false);
            }
        }
    }
/*
Scans all JARs accessible to the webapp's classloader and its
parent classloaders for TLDs.

The list of JARs always includes the JARs under WEB-INF/lib, as well as
all shared JARs in the classloader delegation chain of the webapp's
classloader.

Considering JARs in the classloader delegation chain constitutes a
Tomcat-specific extension to the TLD search
order defined in the JSP spec. It allows tag libraries packaged as JAR
files to be shared by web applications by simply dropping them in a
location that all web applications have access to (e.g.,
<CATALINA_HOME>/common/lib).