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

enkan.config.ConfigurationLoader Maven / Gradle / Ivy

There is a newer version: 0.10.0
Show newest version
package enkan.config;

import enkan.exception.UnreachableException;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * A reloadable classloader.
 *
 * @author kawasima
 */
public class ConfigurationLoader extends ClassLoader {
    List dirs;

    public ConfigurationLoader(ClassLoader parent) {
        super(parent);
        URL[] urls = ((URLClassLoader) parent).getURLs();

        dirs = Arrays.stream(urls)
                .filter(this::isDirectory)
                .filter(d -> {
                    try {
                        return new URLClassLoader(new URL[]{ d }, null).getResource("META-INF/reload.xml") != null;
                    } catch (NoClassDefFoundError e) {
                        return false;
                    }
                })
                .map(url -> {
                    try {
                        return new File(url.toURI());
                    } catch(URISyntaxException e) {
                        throw new UnreachableException(e);
                    }
                })
                .collect(Collectors.toList());
    }

    protected boolean contains(File dir, String path) {
        return Files.exists(dir.toPath().resolve(path.replace('.', '/') + ".class"));
    }

    protected boolean isDirectory(URL url) {
        try {
            return url.getProtocol().equals("file") && new File(url.toURI()).isDirectory();
        } catch (URISyntaxException e) {
            return false;
        }
    }

    protected boolean isTarget(String name) {
        return dirs.stream()
                .anyMatch(d -> contains(d, name));
    }

    private void definePackage(String name) {
        int idx = name.lastIndexOf('.');
        if (idx > 0) {
            String pkgName = name.substring(0, idx);
            Package pkg = getPackage(pkgName);
            if (pkg == null) {
                definePackage(pkgName, null, null, null, null, null, null, null);
            }
        }
    }

    private Class defineClass(String name, boolean resolve) {
        try (InputStream in = getResourceAsStream(name.replaceAll("\\.", "/") + ".class");
             ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
            if (in == null) return null;
            int len;
            final byte[] buffer = new byte[1024];
            while ((len = in.read(buffer)) > 0) {
                baos.write(buffer, 0, len);
            }
            byte[] classBinary = baos.toByteArray();

            Class c = defineClass(name, classBinary, 0, classBinary.length);
            definePackage(name);
            if (resolve)
                resolveClass(c);
            return c;
        } catch (IOException e) {
            return null;
        }
    }

    @Override
    protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException {
        Class c = findLoadedClass(name);
        if (c != null) return c;

        try {
            Method findLoadedClassMethod = ClassLoader.class.getDeclaredMethod("findLoadedClass", String.class);
            findLoadedClassMethod.setAccessible(true);
            c = (Class) findLoadedClassMethod.invoke(getParent(), name);
            if (c != null){
                return c;
            }
        } catch (Exception e) {
            throw new ClassNotFoundException(name, e);
        }


        if (isTarget(name)) {
            c = defineClass(name, resolve);
            if (c != null)
                return c;
        }

        return super.loadClass(name, resolve);
    }

    public List reloadableFiles() {
        return dirs;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy