private void scanJar(JarURLConnection conn, List<String> tldNames,
                         boolean isLocal)
            throws JasperException {

        String resourcePath = conn.getJarFileURL().toString();
        TldInfo[] tldInfos = jarTldCacheLocal.get(resourcePath);

        // Optimize for most common cases: jars known to NOT have tlds
        if (tldInfos != null && tldInfos.length == 0) {
            try {
                conn.getJarFile().close();
            } catch (IOException ex) {
                //ignored
            }
            return;
        }

        // scan the tld if the jar has not been cached.
        if (tldInfos == null) {
            JarFile jarFile = null;
            ArrayList<TldInfo> tldInfoA = new ArrayList<TldInfo>();
            try {
                jarFile = conn.getJarFile();
                if (tldNames != null) {
                    for (String tldName : tldNames) {
                        JarEntry entry = jarFile.getJarEntry(tldName);
                        InputStream stream = jarFile.getInputStream(entry);
                        tldInfoA.add(scanTld(resourcePath, tldName, stream));
                    }
                } else {
                    Enumeration<JarEntry> entries = jarFile.entries();
                    while (entries.hasMoreElements()) {
                        JarEntry entry = entries.nextElement();
                        String name = entry.getName();
                        if (!name.startsWith("META-INF/")) continue;
                        if (!name.endsWith(".tld")) continue;
                        InputStream stream = jarFile.getInputStream(entry);
                        tldInfoA.add(scanTld(resourcePath, name, stream));
                    }
                }
            } catch (IOException ex) {
                if (resourcePath.startsWith(FILE_PROTOCOL) &&
                        !((new File(resourcePath)).exists())) {
                    if (log.isLoggable(Level.WARNING)) {
                        log.log(Level.WARNING,
                            Localizer.getMessage("jsp.warn.nojar",
                                                 resourcePath),
                            ex);
                    }
                } else {
                    throw new JasperException(
                        Localizer.getMessage("jsp.error.jar.io", resourcePath),
                        ex);
                }
            } finally {
                if (jarFile != null) {
                    try {
                        jarFile.close();
                    } catch (Throwable t) {
                        // ignore
                    }
                }
            }
            // Update the jar TLD cache
            tldInfos = tldInfoA.toArray(new TldInfo[tldInfoA.size()]);
            jarTldCacheLocal.put(resourcePath, tldInfos);
            if (!isLocal) {
                // Also update the global cache;
                jarTldCache.put(resourcePath, tldInfos);
            }
        }

        // Iterate over tldinfos to add listeners or to map tldlocations
        for (TldInfo tldInfo: tldInfos) {
            if (scanListeners) {
                addListener(tldInfo, isLocal);
            }
            mapTldLocation(resourcePath, tldInfo, isLocal);
        }
    }
private void scanJar ( JarURLConnection conn , List < String > tldNames , boolean isLocal ) throws JasperException { String resourcePath = conn . getJarFileURL ( ) . toString ( ) ; TldInfo [ ] tldInfos = jarTldCacheLocal . get ( resourcePath ) ; if ( tldInfos != null && tldInfos . length == 0 ) { try { conn . getJarFile ( ) . close ( ) ; } catch ( IOException ex ) { } return ; } if ( tldInfos == null ) { JarFile jarFile = null ; ArrayList < TldInfo > tldInfoA = new ArrayList < TldInfo > ( ) ; try { jarFile = conn . getJarFile ( ) ; if ( tldNames != null ) { for ( String tldName : tldNames ) { JarEntry entry = jarFile . getJarEntry ( tldName ) ; InputStream stream = jarFile . getInputStream ( entry ) ; tldInfoA . add ( scanTld ( resourcePath , tldName , stream ) ) ; } } else { Enumeration < JarEntry > entries = jarFile . entries ( ) ; while ( entries . hasMoreElements ( ) ) { JarEntry entry = entries . nextElement ( ) ; String name = entry . getName ( ) ; if ( ! name . startsWith ( "META-INF/" ) ) continue ; if ( ! name . endsWith ( ".tld" ) ) continue ; InputStream stream = jarFile . getInputStream ( entry ) ; tldInfoA . add ( scanTld ( resourcePath , name , stream ) ) ; } } } catch ( IOException ex ) { if ( resourcePath . startsWith ( FILE_PROTOCOL ) && ! ( ( new File ( resourcePath ) ) . exists ( ) ) ) { if ( log . isLoggable ( Level . WARNING ) ) { log . log ( Level . WARNING , Localizer . getMessage ( "jsp.warn.nojar" , resourcePath ) , ex ) ; } } else { throw new JasperException ( Localizer . getMessage ( "jsp.error.jar.io" , resourcePath ) , ex ) ; } } finally { if ( jarFile != null ) { try { jarFile . close ( ) ; } catch ( Throwable t ) { } } } tldInfos = tldInfoA . toArray ( new TldInfo [ tldInfoA . size ( ) ] ) ; jarTldCacheLocal . put ( resourcePath , tldInfos ) ; if ( ! isLocal ) { jarTldCache . put ( resourcePath , tldInfos ) ; } } for ( TldInfo tldInfo : tldInfos ) { if ( scanListeners ) { addListener ( tldInfo , isLocal ) ; } mapTldLocation ( resourcePath , tldInfo , isLocal ) ; } }
Scans the given JarURLConnection for TLD files located in META-INF
(or a subdirectory of it).  If the scanning in is done as part of the
ServletContextInitializer, the listeners in the tlds in this jar file
are added to the servlet context, and for any  TLD that has a <uri>
element, an implicit map entry is added to the taglib map.

@param conn The JarURLConnection to the JAR file to scan
@param tldNames the list of tld element to scan. The null value
indicates all the tlds in this case.
@param isLocal True if the jar file is under WEB-INF
false otherwise