All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.geode.classloader.internal.LegacyClasspathServiceImpl Maven / Gradle / Ivy

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements. See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.geode.classloader.internal;

import static java.util.stream.Collectors.joining;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Proxy;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;

import org.apache.logging.log4j.Logger;

import org.apache.geode.internal.classloader.ClassPathLoader;
import org.apache.geode.internal.classloader.ClasspathService;
import org.apache.geode.internal.classloader.DeployJarChildFirstClassLoader;
import org.apache.geode.internal.deployment.DeploymentServiceFactory;
import org.apache.geode.internal.deployment.JarDeploymentService;
import org.apache.geode.internal.util.CollectionUtils;
import org.apache.geode.logging.internal.log4j.api.LogService;
import org.apache.geode.management.configuration.Deployment;
import org.apache.geode.management.internal.utils.JarFileUtils;

/**
 * This implementation of {@link ClasspathService} will be used by {@link ClassPathLoader} when the
 * system is started in a non-modular fashion. An instance can be retrieved from
 * {@link DeploymentServiceFactory}
 */
public class LegacyClasspathServiceImpl implements ClasspathService {

  private static final Logger logger = LogService.getLogger();

  private final Map artifactIdsToClassLoader =
      new HashMap<>();

  private volatile DeployJarChildFirstClassLoader leafLoader;

  private boolean excludeTCCL;

  private JarDeploymentService jarDeploymentService;

  public void init(boolean excludeTCCL, JarDeploymentService jarDeploymentService) {
    this.excludeTCCL = excludeTCCL;
    this.jarDeploymentService = jarDeploymentService;
    rebuildClassLoaderForDeployedJars();
  }

  public synchronized void chainClassloader(File jar) {
    try {
      leafLoader = new DeployJarChildFirstClassLoader(artifactIdsToClassLoader,
          new URL[] {jar.toURI().toURL()}, JarFileUtils.toArtifactId(jar.getName()),
          getLeafLoader());
    } catch (MalformedURLException e) {
      e.printStackTrace();
    }
  }

  public synchronized void unloadClassloaderForArtifact(String artifactId) {
    artifactIdsToClassLoader.put(artifactId, null);
  }

  @Override
  public void close() {
    leafLoader = null;
    artifactIdsToClassLoader.clear();
  }

  /**
   * Finds the resource with the given name. This method will first search the class loader of the
   * context class for the resource. That failing, this method will invoke
   * {@link #getResource(String)} to find the resource.
   *
   * @param contextClass The class whose class loader will first be searched
   * @param name The resource name
   * @return A URL object for reading the resource, or null if the resource could
   *         not be found or the invoker doesn't have adequate privileges to get the resource.
   */
  public URL getResource(final Class contextClass, final String name) {
    if (contextClass != null) {
      URL url = contextClass.getResource(name);
      if (url != null) {
        return url;
      }
    }
    return getResource(name);
  }

  /**
   * Returns an input stream for reading the specified resource.
   * 

* The search order is described in the documentation for {@link #getResource(String)}. * * @param name The resource name * @return An input stream for reading the resource, or null if the resource could not be * found */ public InputStream getResourceAsStream(final String name) { URL url = getResource(name); try { return url != null ? url.openStream() : null; } catch (IOException e) { return null; } } /** * Returns an input stream for reading the specified resource. *

* The search order is described in the documentation for {@link #getResource(Class, String)}. * * @param contextClass The class whose class loader will first be searched * @param name The resource name * @return An input stream for reading the resource, or null if the resource could not be * found */ public InputStream getResourceAsStream(final Class contextClass, final String name) { if (contextClass != null) { InputStream is = contextClass.getResourceAsStream(name); if (is != null) { return is; } } return getResourceAsStream(name); } public Enumeration getResources(final String name) throws IOException { final LinkedHashSet urls = new LinkedHashSet<>(); for (ClassLoader classLoader : getClassLoaders()) { Enumeration resources = classLoader.getResources(name); if (resources != null && resources.hasMoreElements()) { CollectionUtils.addAll(urls, resources); } } return Collections.enumeration(urls); } public URL getResource(final String name) { final boolean isTraceEnabled = logger.isTraceEnabled(); if (isTraceEnabled) { logger.trace("getResource({})", name); } for (ClassLoader classLoader : getClassLoaders()) { if (isTraceEnabled) { logger.trace("getResource trying: {}", classLoader); } try { URL url = classLoader.getResource(name); if (url != null) { if (isTraceEnabled) { logger.trace("getResource found by: {}", classLoader); } return url; } } catch (SecurityException e) { // try next classLoader } } return null; } public Class forName(final String name) throws ClassNotFoundException { final boolean isTraceEnabled = logger.isTraceEnabled(); if (isTraceEnabled) { logger.trace("forName({})", name); } Class clazz = forName(name, isTraceEnabled); if (clazz != null) { return clazz; } throw new ClassNotFoundException(name); } private Class forName(String name, boolean isTraceEnabled) { for (ClassLoader classLoader : getClassLoaders()) { if (isTraceEnabled) { logger.trace("forName trying: {}", classLoader); } try { // Do not look up class definitions in jars that have been unloaded or are old if (classLoader instanceof DeployJarChildFirstClassLoader) { if (((DeployJarChildFirstClassLoader) classLoader).thisIsOld()) { return null; } } Class clazz = Class.forName(name, true, classLoader); if (isTraceEnabled) { logger.trace("forName found by: {}", classLoader); } return clazz; } catch (SecurityException | ClassNotFoundException e) { // try next classLoader } } return null; } /** * See {@link Proxy#getProxyClass(ClassLoader, Class...)} */ public Class getProxyClass(final Class... classObjs) { IllegalArgumentException ex = null; for (ClassLoader classLoader : getClassLoaders()) { try { return Proxy.getProxyClass(classLoader, classObjs); } catch (SecurityException sex) { // Continue to next classloader } catch (IllegalArgumentException iaex) { ex = iaex; // Continue to next classloader } } if (ex != null) { throw ex; } return null; } private synchronized void rebuildClassLoaderForDeployedJars() { leafLoader = null; List deployments = jarDeploymentService.listDeployed(); for (Deployment deployment : deployments) { chainClassloader(deployment.getFile()); } } private ClassLoader getLeafLoader() { if (leafLoader == null) { return ClassPathLoader.class.getClassLoader(); } return leafLoader; } private List getClassLoaders() { ArrayList classLoaders = new ArrayList<>(); if (!excludeTCCL) { ClassLoader tccl = Thread.currentThread().getContextClassLoader(); if (tccl != null) { classLoaders.add(tccl); } } classLoaders.add(getLeafLoader()); return classLoaders; } @Override public String toString() { return getClass().getName() + "@" + System.identityHashCode(this) + "{" + "excludeTCCL=" + excludeTCCL + ", jarDeployer=" + jarDeploymentService + ", classLoaders=[" + getClassLoaders().stream().map(ClassLoader::toString).collect(joining(", ")) + "]}"; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy