Handle a resource loader.

@param resourceLoader
the resource loader
@param classLoader
the classloader
@param classpathOrderOut
the classpath order
@param scanSpec
the scan spec
@param log
the log
11451
private static void handleResourceLoader(final Object resourceLoader, final ClassLoader classLoader,
            final ClasspathOrder classpathOrderOut, final ScanSpec scanSpec, final LogNode log) {
        if (resourceLoader == null) {
            return;
        }
        // PathResourceLoader has root field, which is a Path object
        final Object root = ReflectionUtils.getFieldVal(resourceLoader, "root", false);
        // type VirtualFile
        final File physicalFile = (File) ReflectionUtils.invokeMethod(root, "getPhysicalFile", false);
        String path = null;
        if (physicalFile != null) {
            final String name = (String) ReflectionUtils.invokeMethod(root, "getName", false);
            if (name != null) {
                // getParentFile() removes "contents" directory
                final File file = new File(physicalFile.getParentFile(), name);
                if (FileUtils.canRead(file)) {
                    path = file.getAbsolutePath();
                } else {
                    // This is an exploded jar or classpath directory
                    path = physicalFile.getAbsolutePath();
                }
            } else {
                path = physicalFile.getAbsolutePath();
            }
        } else {
            path = (String) ReflectionUtils.invokeMethod(root, "getPathName", false);
            if (path == null) {
                // Try Path or File
                final File file = root instanceof Path ? ((Path) root).toFile()
                        : root instanceof File ? (File) root : null;
                if (file != null) {
                    path = file.getAbsolutePath();
                }
            }
        }
        if (path == null) {
            final File file = (File) ReflectionUtils.getFieldVal(resourceLoader, "fileOfJar", false);
            if (file != null) {
                path = file.getAbsolutePath();
            }
        }
        if (path != null) {
            classpathOrderOut.addClasspathEntry(path, classLoader, scanSpec, log);
        } else {
            if (log != null) {
                log.log("Could not determine classpath for ResourceLoader: " + resourceLoader);
            }
        }
    }
875203
public static void preload(@NonNull ClassLoader classLoader) {
      Resource r = new ClasspathResource("META-INF/preload.classes", classLoader);
      if (r.exists()) {
         try {
            r.readLines().forEach(ReflectionUtils::getClassForNameQuietly);
         } catch (IOException e) {
            e.printStackTrace();
         }
      }
   }
735836
protected void processClass (File source)
    {
        // load up the file and determine it's package and classname
        String name = null;
        try {
            name = GenUtil.readClassName(source);
        } catch (Exception e) {
            System.err.println("Failed to parse " + source + ": " + e.getMessage());
            return;
        }

        System.err.println("Considering " + name + "...");

        try {
            // in order for annotations to work, this task and all the classes it uses must be
            // loaded from the same class loader as the classes on which we are going to
            // introspect; this is non-ideal but unavoidable
            processClass(source, getClass().getClassLoader().loadClass(name));
        } catch (ClassNotFoundException cnfe) {
            System.err.println("Failed to load " + name + ".\nMissing class: " + cnfe.getMessage());
            System.err.println("Be sure to set the 'classpathref' attribute to a classpath\n" +
                               "that contains your projects invocation service classes.");
        } catch (Exception e) {
            e.printStackTrace(System.err);
        }
    }
953240
protected void doLoadFromClasspath(String policyImpl, IAsyncResultHandler<IPolicy> handler) {
        IPolicy rval;
        String classname = policyImpl.substring(6);
        Class<?> c = null;

        // First try a simple Class.forName()
        try { c = Class.forName(classname); } catch (ClassNotFoundException e) { }
        // Didn't work?  Try using this class's classloader.
        if (c == null) {
            try { c = getClass().getClassLoader().loadClass(classname); } catch (ClassNotFoundException e) { }
        }
        // Still didn't work?  Try the thread's context classloader.
        if (c == null) {
            try { c = Thread.currentThread().getContextClassLoader().loadClass(classname); } catch (ClassNotFoundException e) { }
        }

        if (c == null) {
            handler.handle(AsyncResultImpl.<IPolicy>create(new PolicyNotFoundException(classname)));
            return;
        }

        try {
            rval = (IPolicy) c.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            handler.handle(AsyncResultImpl.<IPolicy>create(new PolicyNotFoundException(policyImpl, e)));
            return;
        }
        policyCache.put(policyImpl, rval);
        handler.handle(AsyncResultImpl.create(rval));
        return;
    }
921851
public static void init(ClassLoader loader)
  {
    for (; loader != null; loader = loader.getParent()) {
      if (loader instanceof EnvironmentClassLoader) {
        ((EnvironmentClassLoader) loader).init();
        return;
      }
    }

    for (int i = 0; i < _globalLoaderListeners.size(); i++) {
      EnvLoaderListener listener = _globalLoaderListeners.get(i);

      listener.classLoaderInit(null);
    }
  }
1336766
public void scan(String classNamePattern, final Map<String, Class<?>> scannedClasses) throws IOException {
        scan(classNamePattern, scannedClasses::put);
    }
663055
public static void load(Class<?> parent, ClassLoader cl) {
    char[] buf = new char[0x4000];
    try {
      String fullName = RESOURCE_PREFIX + parent.getName();
      Enumeration<URL> configfiles = cl.getResources(fullName);
      while(configfiles.hasMoreElements()) {
        URL nextElement = configfiles.nextElement();
        URLConnection conn = nextElement.openConnection();
        conn.setUseCaches(false);
        try (
            InputStreamReader is = new InputStreamReader(conn.getInputStream(), "UTF-8");) {
          int start = 0, cur = 0, valid = is.read(buf, 0, buf.length);
          char c;
          while(cur < valid) {
            // Find newline or end
            while(cur < valid && (c = buf[cur]) != '\n' && c != '\r') {
              cur++;
            }
            if(cur == valid && is.ready()) {
              // Move consumed buffer contents:
              if(start > 0) {
                System.arraycopy(buf, start, buf, 0, valid - start);
                valid -= start;
                cur -= start;
                start = 0;
              }
              else if(valid == buf.length) {
                throw new IOException("Buffer size exceeded. Maximum line length in service files is: " + buf.length + " in file: " + fullName);
              }
              valid = is.read(buf, valid, buf.length - valid);
              continue;
            }
            parseLine(parent, buf, start, cur);
            while(cur < valid && ((c = buf[cur]) == '\n' || c == '\r')) {
              cur++;
            }
            start = cur;
          }
        }
        catch(IOException x) {
          throw new AbortException("Error reading configuration file", x);
        }
      }
    }
    catch(IOException x) {
      throw new AbortException("Could not load service configuration files.", x);
    }
  }
680031
public void setClassLoader (ClassLoader loader)
    {
        _loader = loader;
        PresentsConnection conn = getConnection();
        if (conn != null) {
            conn.setClassLoader(loader);
        }
    }
434933
@FFDCIgnore({ AnnotationTargetsVisitor.VisitEnded.class, ArrayIndexOutOfBoundsException.class })
    protected boolean scanClass(String classSourceName,
                                String className,
                                InputStream inputStream,
                                ScanPolicy scanPolicy) {

        Object[] logParms;
        if (tc.isDebugEnabled()) {
            logParms = new Object[] { getHashText(), className, null };
            Tr.debug(tc, MessageFormat.format("[ {0} ] ENTER class [ {1} ]", logParms));
        } else {
            logParms = null;
        }

        AnnotationTargetsVisitor useVisitor = getVisitor();

        useVisitor.i_setClassSourceName(internClassSourceName(classSourceName));

        // For non-seed scans, tell the visitor to only process the
        // class relationship information.  Skip class annotations and
        // and class contents (fields and methods).

        useVisitor.setScanPolicy(scanPolicy);
        useVisitor.setExternalName(className);

        boolean failedScan;

        try {
            // Both IOException and Exception have been seen;
            // in particular ArrayindexOutOfBoundsException for a non-valid class.

            ClassReader classReader = new ClassReader(inputStream); // throws IOException, Exception

            classReader.accept(getVisitor(),
                               (ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG | ClassReader.SKIP_CODE));
            // 'accept' throws IOException, VisitEnded, Exception

            failedScan = false;

            if (logParms != null) {
                logParms[2] = "Success";
            }

        } catch (IOException e) {
            failedScan = true;

            // String eMsg = "[ " + getHashText() + " ] Class [ " + className + " ] Exception creating reader";
            Tr.warning(tc, "ANNO_TARGETS_FAILED_TO_CREATE_READER", className); // CWWKC0049W

        } catch (AnnotationTargetsVisitor.VisitEnded e) {
            // 'VisitEnded' is used both for a normal flow control for
            // skipping detailed scan data (which is not a failed scan)
            // and for other cases, such as duplicate scan requests
            // and name mismatch cases, which are failures.

            failedScan = !e.isDetailCase();

            if (logParms != null) {
                logParms[2] = "Halted: " + e.getEndCase();
            }

        } catch (ArrayIndexOutOfBoundsException e) {
            Tr.info(tc, "ANNO_TARGETS_CORRUPT_CLASS", className, classSourceName);
            failedScan = true;

        } catch (Exception e) {
            // String eMsg = "[ " + getHashText() + " ] Visit failure [ " + className + " ]";
            // CWWKC0044W: An exception occurred while scanning class and annotation data.
            Tr.warning(tc, "ANNO_TARGETS_SCAN_EXCEPTION", e);

            if (logParms != null) {
                logParms[2] = "Exception: " + e.getMessage();
            }

            failedScan = true;
        }

        if (logParms != null) {
            Tr.debug(tc, MessageFormat.format("[ {0} ] RETURN From class [ {1} ]: [ {2} ]", logParms));
        }

        return (!failedScan);
    }
202804
private static <T> Collection<String> loadClasses(final ClassLoader classLoader, final Class<? extends T> service) {
		String name = SERVICE_PREFIX + service.getName();
		Enumeration<URL> urls;
		try {
			urls = classLoader.getResources(name);
		} catch (IOException ex) {
			InternalLogger.log(Level.ERROR, "Failed loading services from '" + name + "'");
			return Collections.emptyList();
		}

		Collection<String> classes = new ArrayList<String>();

		while (urls.hasMoreElements()) {
			URL url = urls.nextElement();
			BufferedReader reader = null;

			try {
				reader = new BufferedReader(new InputStreamReader(url.openStream(), "utf-8"));
				for (String line = reader.readLine(); line != null; line = reader.readLine()) {
					line = line.trim();
					if (line.length() > 0 && line.charAt(0) != '#' && !classes.contains(line)) {
						classes.add(line);
					}
				}
			} catch (IOException ex) {
				InternalLogger.log(Level.ERROR, "Failed reading service resource '" + url + "'");
			} finally {
				if (reader != null) {
					try {
						reader.close();
					} catch (IOException ex) {
						// Ignore
					}
				}
			}
		}

		return classes;
	}
875435
public void scanLibraries(
		String rootPackage, boolean includeSubPackages,
		Filter<String> packageFilter, Filter<String> classFilter, Listener<Class<?>> classScanner
	) {
		for (AbstractClassLoader cl : libs)
			cl.scan(rootPackage, includeSubPackages, packageFilter, classFilter, classScanner);
	}
132652
@Override
    public boolean process(String classSourceName, String className, InputStream inputStream, ScanPolicy scanPolicy) {
        return getTargets().scanClass(classSourceName, className, inputStream, scanPolicy);
    }
1107007
protected void addClassPathes(final GroovyClassLoader classLoader) {
        if (classpath != null) {
            for (int i = 0; i < classpath.list().length; i++) {
                classLoader.addClasspath(classpath.list()[i]);
            }
        }
    }
530588
public static void setClassLoader( ServletContext context, ClassLoader classLoader ) {
        WebApp.get(context).setClassLoader(classLoader);
    }
92897
public void setNewResourceOrder(String newResourceOrder) {

        try {
            m_newResourceOrder = Integer.valueOf(newResourceOrder);
            if (LOG.isDebugEnabled()) {
                LOG.debug(Messages.get().getBundle().key(Messages.LOG_SET_NEW_RESOURCE_ORDER_1, newResourceOrder));
            }
        } catch (Exception e) {
            // can usually be ignored
            if (LOG.isInfoEnabled()) {
                LOG.info(e);
            }
            m_newResourceOrder = new Integer(0);
        }
    }
105480
@Override
    void scanPaths(final LogNode log) {
        if (logicalZipFile == null) {
            skipClasspathElement = true;
        }
        if (skipClasspathElement) {
            return;
        }
        if (scanned.getAndSet(true)) {
            // Should not happen
            throw new IllegalArgumentException("Already scanned classpath element " + getZipFilePath());
        }

        final LogNode subLog = log == null ? null
                : log.log(getZipFilePath(), "Scanning jarfile classpath element " + getZipFilePath());

        Set<String> loggedNestedClasspathRootPrefixes = null;
        String prevParentRelativePath = null;
        ScanSpecPathMatch prevParentMatchStatus = null;
        for (final FastZipEntry zipEntry : logicalZipFile.entries) {
            String relativePath = zipEntry.entryNameUnversioned;

            // Check if the relative path is within a nested classpath root
            if (nestedClasspathRootPrefixes != null) {
                // This is O(mn), which is inefficient, but the number of nested classpath roots should be small
                boolean reachedNestedRoot = false;
                for (final String nestedClasspathRoot : nestedClasspathRootPrefixes) {
                    if (relativePath.startsWith(nestedClasspathRoot)) {
                        // relativePath has a prefix of nestedClasspathRoot
                        if (subLog != null) {
                            if (loggedNestedClasspathRootPrefixes == null) {
                                loggedNestedClasspathRootPrefixes = new HashSet<>();
                            }
                            if (loggedNestedClasspathRootPrefixes.add(nestedClasspathRoot)) {
                                subLog.log("Reached nested classpath root, stopping recursion to avoid duplicate "
                                        + "scanning: " + nestedClasspathRoot);
                            }
                        }
                        reachedNestedRoot = true;
                        break;
                    }
                }
                if (reachedNestedRoot) {
                    continue;
                }
            }

            // Ignore entries without the correct classpath root prefix
            if (!packageRootPrefix.isEmpty() && !relativePath.startsWith(packageRootPrefix)) {
                continue;
            }

            // Strip the package root prefix from the relative path
            // N.B. these semantics should mirror those in getResource()
            if (!packageRootPrefix.isEmpty()) {
                relativePath = relativePath.substring(packageRootPrefix.length());
            } else {
                // Strip any package root prefix from the relative path
                for (int i = 0; i < ClassLoaderHandlerRegistry.AUTOMATIC_PACKAGE_ROOT_PREFIXES.length; i++) {
                    if (relativePath.startsWith(ClassLoaderHandlerRegistry.AUTOMATIC_PACKAGE_ROOT_PREFIXES[i])) {
                        relativePath = relativePath
                                .substring(ClassLoaderHandlerRegistry.AUTOMATIC_PACKAGE_ROOT_PREFIXES[i].length());
                    }
                }
            }

            // Whitelist/blacklist classpath elements based on file resource paths
            checkResourcePathWhiteBlackList(relativePath, log);
            if (skipClasspathElement) {
                return;
            }

            // Get match status of the parent directory of this ZipEntry file's relative path (or reuse the last
            // match status for speed, if the directory name hasn't changed).
            final int lastSlashIdx = relativePath.lastIndexOf('/');
            final String parentRelativePath = lastSlashIdx < 0 ? "/" : relativePath.substring(0, lastSlashIdx + 1);
            final boolean parentRelativePathChanged = !parentRelativePath.equals(prevParentRelativePath);
            final ScanSpecPathMatch parentMatchStatus = //
                    parentRelativePathChanged ? scanSpec.dirWhitelistMatchStatus(parentRelativePath)
                            : prevParentMatchStatus;
            prevParentRelativePath = parentRelativePath;
            prevParentMatchStatus = parentMatchStatus;

            if (parentMatchStatus == ScanSpecPathMatch.HAS_BLACKLISTED_PATH_PREFIX) {
                // The parent dir or one of its ancestral dirs is blacklisted
                if (subLog != null) {
                    subLog.log("Skipping blacklisted path: " + relativePath);
                }
                continue;
            }

            // Add the ZipEntry path as a Resource
            final Resource resource = newResource(zipEntry, relativePath);
            if (relativePathToResource.putIfAbsent(relativePath, resource) == null
                    // If resource is whitelisted
                    && (parentMatchStatus == ScanSpecPathMatch.HAS_WHITELISTED_PATH_PREFIX
                            || parentMatchStatus == ScanSpecPathMatch.AT_WHITELISTED_PATH
                            || (parentMatchStatus == ScanSpecPathMatch.AT_WHITELISTED_CLASS_PACKAGE
                                    && scanSpec.classfileIsSpecificallyWhitelisted(relativePath))
                            || (scanSpec.enableClassInfo && relativePath.equals("module-info.class")))) {
                // Resource is whitelisted
                addWhitelistedResource(resource, parentMatchStatus, subLog);
            }
        }

        // Save the last modified time for the zipfile
        final File zipfile = getFile();
        fileToLastModified.put(zipfile, zipfile.lastModified());

        finishScanPaths(subLog);
    }
1060144
@Override
    void scanPaths(final LogNode log) {
        if (skipClasspathElement) {
            return;
        }
        if (scanned.getAndSet(true)) {
            // Should not happen
            throw new IllegalArgumentException("Already scanned classpath element " + toString());
        }

        final String moduleLocationStr = moduleRef.getLocationStr();
        final LogNode subLog = log == null ? null
                : log.log(moduleLocationStr, "Scanning module " + moduleRef.getName());

        try (RecycleOnClose<ModuleReaderProxy, IOException> moduleReaderProxyRecycleOnClose //
                = moduleReaderProxyRecycler.acquireRecycleOnClose()) {
            // Look for whitelisted files in the module.
            List<String> resourceRelativePaths;
            try {
                resourceRelativePaths = moduleReaderProxyRecycleOnClose.get().list();
            } catch (final SecurityException e) {
                if (subLog != null) {
                    subLog.log("Could not get resource list for module " + moduleRef.getName(), e);
                }
                return;
            }
            CollectionUtils.sortIfNotEmpty(resourceRelativePaths);

            String prevParentRelativePath = null;
            ScanSpecPathMatch prevParentMatchStatus = null;
            for (final String relativePath : resourceRelativePaths) {
                // From ModuleReader#find(): "If the module reader can determine that the name locates a
                // directory then the resulting URI will end with a slash ('/')."  But from the documentation
                // for ModuleReader#list(): "Whether the stream of elements includes names corresponding to
                // directories in the module is module reader specific."  We don't have a way of checking if
                // a resource is a directory without trying to open it, unless ModuleReader#list() also decides
                // to put a "/" on the end of resource paths corresponding to directories. Skip directories if
                // they are found, but if they are not able to be skipped, we will have to settle for having
                // some IOExceptions thrown when directories are mistaken for resource files.
                if (relativePath.endsWith("/")) {
                    continue;
                }

                // Whitelist/blacklist classpath elements based on file resource paths
                checkResourcePathWhiteBlackList(relativePath, log);
                if (skipClasspathElement) {
                    return;
                }

                // Get match status of the parent directory of this resource's relative path (or reuse the last
                // match status for speed, if the directory name hasn't changed).
                final int lastSlashIdx = relativePath.lastIndexOf('/');
                final String parentRelativePath = lastSlashIdx < 0 ? "/"
                        : relativePath.substring(0, lastSlashIdx + 1);
                final boolean parentRelativePathChanged = !parentRelativePath.equals(prevParentRelativePath);
                final ScanSpecPathMatch parentMatchStatus = //
                        prevParentRelativePath == null || parentRelativePathChanged
                                ? scanSpec.dirWhitelistMatchStatus(parentRelativePath)
                                : prevParentMatchStatus;
                prevParentRelativePath = parentRelativePath;
                prevParentMatchStatus = parentMatchStatus;

                if (parentMatchStatus == ScanSpecPathMatch.HAS_BLACKLISTED_PATH_PREFIX) {
                    // The parent dir or one of its ancestral dirs is blacklisted
                    if (subLog != null) {
                        subLog.log("Skipping blacklisted path: " + relativePath);
                    }
                    continue;
                }

                // Found non-blacklisted relative path
                if (allResourcePaths.add(relativePath)
                        // If resource is whitelisted
                        && (parentMatchStatus == ScanSpecPathMatch.HAS_WHITELISTED_PATH_PREFIX
                                || parentMatchStatus == ScanSpecPathMatch.AT_WHITELISTED_PATH
                                || (parentMatchStatus == ScanSpecPathMatch.AT_WHITELISTED_CLASS_PACKAGE
                                        && scanSpec.classfileIsSpecificallyWhitelisted(relativePath))
                                || (scanSpec.enableClassInfo && relativePath.equals("module-info.class")))) {
                    // Add whitelisted resource
                    final Resource resource = newResource(relativePath);
                    addWhitelistedResource(resource, parentMatchStatus, subLog);
                }
            }

            // Save last modified time for the module file
            final File moduleFile = moduleRef.getLocationFile();
            if (moduleFile != null && moduleFile.exists()) {
                fileToLastModified.put(moduleFile, moduleFile.lastModified());
            }

        } catch (final IOException e) {
            if (subLog != null) {
                subLog.log("Exception opening module " + moduleRef.getName(), e);
            }
            skipClasspathElement = true;
        }

        finishScanPaths(subLog);
    }