package no.kantega.publishing.spring;

import org.apache.log4j.Logger;
import org.kantega.jexmec.PluginClassLoaderProvider;
import org.kantega.jexmec.jarfiles.EmbeddedLibraryPluginClassLoader;
import org.springframework.beans.factory.BeanClassLoaderAware;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.Map;

import static java.util.Collections.singleton;

/**
 *
 */
public class PluginHotDepoyProvider implements PluginClassLoaderProvider, BeanClassLoaderAware {

    private Registry registry;
    private ClassLoader classLoader;
    private File pluginWorkDirectory;
    private Map<String, ClassLoader> loaders = new HashMap<String, ClassLoader>();
    private Logger logger = Logger.getLogger(getClass());

    public void deploy(File jarFile, File resourceDirectory) throws IOException {
        if(loaders.containsKey(jarFile.getAbsolutePath())) {
            logger.info("Removing already present classloader for plugin " + jarFile.getAbsolutePath());
            registry.remove(singleton(loaders.get(jarFile.getAbsolutePath())));
        }
        logger.info("Adding classloader for plugin " + jarFile.getAbsolutePath());

        URLConnection connection = getClass().getResource(getClass().getSimpleName() + ".class").openConnection();
        connection.setDefaultUseCaches(false);


        ClassLoader loader = new EmbeddedLibraryPluginClassLoader(jarFile, classLoader, pluginWorkDirectory);
        if (resourceDirectory != null && resourceDirectory.exists() && resourceDirectory.isDirectory()) {
            loader = new ResourceDirectoryPreferringClassLoader(loader, resourceDirectory);
        }
        registry.add(singleton(loader));
        loaders.put(jarFile.getAbsolutePath(), loader);
    }
    public void start(Registry registry, ClassLoader parentClassLoader) {
        this.registry = registry;
    }

    public void stop() {
        registry.remove(loaders.values());
        loaders.clear();
    }

    public void setBeanClassLoader(ClassLoader classLoader) {
        this.classLoader = classLoader;
    }

    public void setPluginWorkDirectory(File pluginWorkDirectory) {
        this.pluginWorkDirectory = pluginWorkDirectory;
    }

    private class ResourceDirectoryPreferringClassLoader extends ClassLoader {
        private final File resourceDirectory;

        public ResourceDirectoryPreferringClassLoader(ClassLoader parentClassLoader, File resourceDirectory) {
            super(parentClassLoader);
            this.resourceDirectory = resourceDirectory;
        }

        @Override
        public URL getResource(String path) {
            File local = new File(resourceDirectory, path);
            if(local.exists()) {
                try {
                    return local.toURI().toURL();
                } catch (MalformedURLException e) {
                    throw new RuntimeException(e);
                }
            }
            return super.getResource(path);
        }

        @Override
        public InputStream getResourceAsStream(String path) {
            File local = new File(resourceDirectory, path);
            if(local.exists()) {
                try {
                    return local.toURI().toURL().openStream();
                } catch (MalformedURLException e) {
                    throw new RuntimeException(e);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return super.getResourceAsStream(path);
        }

    }
}

@@ -189,71 +189,8 @@
 der;
-%0Aimport org.springframework.beans.factory.BeanClassLoaderAware;
 %0A%0Aim
@@ -539,30 +539,8 @@
 ider
-, BeanClassLoaderAware
  %7B%0A%0A
@@ -574,45 +574,8 @@
 ry;%0A
-    private ClassLoader classLoader;%0A
     
@@ -744,24 +744,67 @@
 getClass());
+%0A    private ClassLoader parentClassLoader;
 %0A%0A    public
@@ -1454,17 +1454,23 @@
 arFile, 
-c
+parentC
 lassLoad
@@ -1910,24 +1910,76 @@
 = registry;%0A
+        this.parentClassLoader = parentClassLoader;%0A
     %7D%0A%0A    p
@@ -2076,118 +2076,8 @@
   %7D%0A
-%0A    public void setBeanClassLoader(ClassLoader classLoader) %7B%0A        this.classLoader = classLoader;%0A    %7D%0A%0A
     

Support for deploying plugins into a running OA instance: