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

com.manydesigns.portofino.code.AbstractCodeBase Maven / Gradle / Ivy

The newest version!
package com.manydesigns.portofino.code;

import io.reactivex.disposables.Disposable;
import io.reactivex.subjects.PublishSubject;
import io.reactivex.subjects.Subject;
import org.apache.commons.vfs2.FileObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.lang.ref.WeakReference;
import java.net.URL;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

public abstract class AbstractCodeBase implements CodeBase {

    private static final Logger logger = LoggerFactory.getLogger(AbstractCodeBase.class);
    protected CodeBase parent;
    protected final ConcurrentMap> knownClasses = new ConcurrentHashMap<>();
    protected final Subject reloads = PublishSubject.create();
    protected FileObject root;
    protected ClassLoader classLoader;
    private Disposable parentSubscription;

    public AbstractCodeBase(FileObject root) {
        this.root = root;
    }

    public AbstractCodeBase(FileObject root, CodeBase parent, ClassLoader classLoader) {
        this(root);
        this.classLoader = classLoader;
        installParent(parent);
    }

    @Override
    public void setParent(CodeBase parent) throws Exception {
        this.clear(false);
        if(parentSubscription != null) {
            parentSubscription.dispose();
        }
        installParent(parent);
    }

    protected void installParent(CodeBase parent) {
        this.parent = parent;
        if(parent != null) {
            parentSubscription = parent.getReloads().subscribe(c -> {
                parentClassReloaded(c);
                reloads.onNext(c);
            });
        }
    }

    protected void parentClassReloaded(Class c) throws Exception {
        logger.debug("Parent class {} reloaded, clearing codebase", c.getName());
        clear(false);
    }

    @Override
    public Class loadClass(String className, SearchScope searchScope) throws IOException, ClassNotFoundException {
        Class localClass = loadLocalClass(className);
        if(localClass != null) {
            WeakReference oldClass = knownClasses.get(className);
            boolean shouldSignalReload = oldClass != null && oldClass.get() != localClass;
            knownClasses.put(className, new WeakReference<>(localClass));
            if(shouldSignalReload) {
                reloads.onNext(localClass);
            }
            return localClass;
        }
        if(searchScope == SearchScope.LOCAL) {
            throw new ClassNotFoundException(className);
        }
        if(parent != null) {
            return parent.loadClass(className, searchScope);
        }
        if(searchScope == SearchScope.LOCAL_PARENT) {
            throw new ClassNotFoundException(className);
        }
        return getClassLoader().loadClass(className);
    }

    protected abstract Class loadLocalClass(String className) throws IOException, ClassNotFoundException;

    @Override
    public URL findResource(String name) throws IOException {
        FileObject fileObject = getRoot().resolveFile(name);
        if(fileObject.exists()) {
            return fileObject.getURL();
        } else if(parent != null) {
            return parent.findResource(name);
        } else {
            return null;
        }
    }

    @Override
    public CodeBase getParent() {
        return parent;
    }

    @Override
    public Subject getReloads() {
        return reloads;
    }

    @Override
    public ClassLoader getClassLoader() {
        return classLoader != null ? classLoader : Thread.currentThread().getContextClassLoader();
    }

    @Override
    public void clear(boolean recursively) throws Exception {
        if(recursively && parent != null) {
            parent.clear(recursively);
        }
    }

    @Override
    public void close() {
        try {
            if(parent != null) {
                parent.close();
            }
        } finally {
            reloads.onComplete();
        }
    }

    @Override
    public FileObject getRoot() {
        return root;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy