Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  package org.kantega.jexmec.devclp;
  
  /*
   * Copyright 2011 Kantega AS
   *
   * Licensed 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.
  */
 
 
 import java.io.File;
 import java.net.URL;
 import java.util.List;
 
 import static java.util.Collections.singleton;

PluginLoader for easy of development of plugins. On startup this PluginLoader will set up monitoring of a list of plugin directories provided through a system property given (by default DEFAULT_PLUGIN_HOMES_PROPERTY. For each of these directories the plugin loader will add a classloader that loads resources from the resourcesDirectory (default DEFAULT_RESOURCES_DIRECTORY) and classes from the classesDirectory (default DEFAULT_CLASSES_DIRECTORY). For each directory this plugin loader will monitor the classes directory for changes. When a changed file is detected the stratgy will remove the old classloader and add a new one. This allows for hot redeployment of single plugins.
 
 public class DevelopmentClassLoaderProvider implements ClassLoaderProvider {
 
     private static final String DEFAULT_PLUGIN_HOMES_PROPERTY = "jexmec.pluginHomes";
     private static final String DEFAULT_CLASSES_DIRECTORY = "target/classes";
     private static final String DEFAULT_RESOURCES_DIRECTORY = "src/main/resources";
     private Thread changeDetector;
     private long changeDetectorInterval = 5000;
     private volatile boolean changeDetectorStopFlag = false;
     private Registry registry;
     private boolean shouldScan = true;
     private ClassLoader parentClassLoader;
 
     public void setShouldScan(boolean shouldScan) {
         this. = shouldScan;
     }
 
     public void start(Registry registryClassLoader parentClassLoader) {
         this. = registry;
         this. = parentClassLoader;
         String homesProperty = System.getProperty();
 
         if (homesProperty != null) {
             for (String home : homesProperty.split(",;")) {
                 File homeDirectory = new File(home);
                 if (homeDirectory.exists()) {
                     File classes = new File(homeDirectory);
                     File resources = new File(homeDirectory);
                     if (classes.exists()) {
 
                         final DevelopmentPluginClassLoader loader = createClassLoader(classesresourcesparentClassLoader);
                         .add(loader);
                         registry.add(singleton(loader));
                     }
 
                 }
             }
 
         }
         if( && .size() > 0) {
              = new Thread(new ChangeDetector(), "Jexmec change detector ");
             .setDaemon(true);
             .start();
         }
 
     }
 
     Thread getChangeDetector() {
         return ;
     }
 
     public void setChangeDetectorInterval(long changeDetectorInterval) {
         this. = changeDetectorInterval;
     }
    private DevelopmentPluginClassLoader createClassLoader(File classesDirectoryFile resourcesDirectoryClassLoader parentClassLoader) {
        return new DevelopmentPluginClassLoader(classesDirectorycreateResourcesDirectory(resourcesDirectory), parentClassLoader);
    }

    
This method is only here for tests to subclass

Parameters:
resourcesDirectory the original resource directory
Returns:
normally the given directory
    File createResourcesDirectory(File resourcesDirectory) {
        return resourcesDirectory;
    }
    public void stop() {
         = true;
        .interrupt();
    }
    public void checkForChanges() {
            if (loader.getLastModified() > loader.getLastCheck()) {
                final DevelopmentPluginClassLoader newLoader = createClassLoader(loader.getClassesDirectory(), loader.getResourcesDirectory(), );
                .replace(singleton(loader), singleton(newLoader));
                .remove(loader);
                .add(newLoader);
            } else {
                loader.setLastCheck(System.currentTimeMillis());
            }
        }
    }
    private class ChangeDetector implements Runnable {
        public void run() {
            while (true) {
                if() {
                    return;
                }
                checkForChanges();
                try {
                    Thread.sleep();
                } catch (InterruptedException e) {
                }
            }
        }
    }
    public void setPluginHomesProperty(String pluginHomesProperty) {
        this. = pluginHomesProperty;
    }
    private class DevelopmentPluginClassLoader extends URLClassLoader {
        private URLClassLoader resourcesLoader;
        private long lastCheck = 0;
        private File classesDirectory;
        private File resourcesDirectory;
        private DevelopmentPluginClassLoader(File classesDirectoryFile resourcesDirectoryClassLoader parentClassLoader) {
            super(getUrls(classesDirectory), parentClassLoader);
            this. = classesDirectory;
            this. = resourcesDirectory;
            final List<URLresourceUrls = new ArrayList<URL>();
            try {
                resourceUrls.add(resourcesDirectory.toURI().toURL());
            } catch (MalformedURLException e) {
                throw new RuntimeException(e);
            }
            for(int i = 1; i < getURLs().lengthi++) {
                resourceUrls.add(getURLs()[i]);
            }
             = new URLClassLoader(resourceUrls.toArray(new URL[resourceUrls.size()]), parentClassLoader);
            setLastCheck(getLastModified());
        }
        @Override
        public URL getResource(String name) {
            return .getResource(name);
        }
        @Override
        public Enumeration<URLgetResources(String namethrows IOException {
            return .getResources(name);
        }
        @Override
        public InputStream getResourceAsStream(String name) {
            return .getResourceAsStream(name);
        }
        public void setLastCheck(long lastCheck) {
            this. = lastCheck;
        }
        public long getLastCheck() {
            return ;
        }
        public long getLastModified() {
            return getLastModified();
        }
        private long getLastModified(File file) {
            if (file.isFile()) {
                return file.lastModified();
            } else {
                long max = 0;
                for (File child : file.listFiles()) {
                    max = Math.max(maxgetLastModified(child));
                }
                return max;
            }
        }
        public File getClassesDirectory() {
            return ;
        }
        public File getResourcesDirectory() {
            return ;
        }
    }
    private static URL[] getUrls(File location) {
        try {
            List<URLurls = new ArrayList<URL>();
            urls.add(location.toURI().toURL());
            File libDir = new File(location"META-INF/lib");
            if (libDir.exists()) {
                File[] libs = libDir.listFiles();
                if(libs != null) {
                    for (File lib : libs) {
                        urls.add(lib.toURI().toURL());
                    }
                }
            }
            return urls.toArray(new URL[urls.size()]);
        } catch (MalformedURLException e) {
            throw new RuntimeException(e);
        }
    }
New to GrepCode? Check out our FAQ X