/** * * Copyright (c) 2009-2016 Freedomotic team http://freedomotic.com * * This file is part of Freedomotic * * This Program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2, or (at your option) any later version. * * This Program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * Freedomotic; see the file COPYING. If not, see * <http://www.gnu.org/licenses/>. */ package com.freedomotic.plugins; import com.freedomotic.app.Freedomotic; import java.io.File; import java.io.FileFilter; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * THIS IS CURRENTLY NOT USED A parent-last classloader that will try the child * classloader first and then the parent. */ public class PluginIsolatedClassloader extends ClassLoader { private static final Logger LOG = LoggerFactory.getLogger(PluginIsolatedClassloader.class.getName()); private ChildURLClassLoader childClassLoader; /** * Accepts a folder containing a set of jar files to load * * @param jarDir */ public PluginIsolatedClassloader(String jarDir) { super(Thread.currentThread().getContextClassLoader()); // search for JAR files in the given directory FileFilter jarFilter = new FileFilter() { @Override public boolean accept(File pathname) { return pathname.getName().endsWith(".jar"); } }; // create URL for each JAR file found File[] jarFiles = new File(jarDir).listFiles(jarFilter); URL[] urls; if (null != jarFiles) { urls = new URL[jarFiles.length]; for (int i = 0; i < jarFiles.length; i++) { try { urls[i] = jarFiles[i].toURI().toURL(); } catch (MalformedURLException e) { throw new RuntimeException( "Could not get URL for JAR file: " + jarFiles[i], e); } } } else { // no JAR files found urls = new URL[0]; } childClassLoader = new ChildURLClassLoader(urls, this.getParent()); } @Override protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { try { LOG.info("Isolated classloader tries to load class \"{}\"", name); // first try to find a class inside the child classloader return childClassLoader.findClass(name); } catch (ClassNotFoundException e) { // didn't find it, try the parent LOG.error(Freedomotic.getStackTraceInfo(e)); return super.loadClass(name, resolve); } } /** * This class delegates (child then parent) for the findClass method for a * URLClassLoader. Need this because findClass is protected in * URLClassLoader */ private class ChildURLClassLoader extends URLClassLoader { private ClassLoader realParent; public ChildURLClassLoader(URL[] urls, ClassLoader realParent) { // pass null as parent so upward delegation disabled for first // findClass call super(urls, null); this.realParent = realParent; } @Override public Class<?> findClass(String name) throws ClassNotFoundException { try { // 1. is this class already loaded? Class cls = super.findLoadedClass(name); if (cls != null) { LOG.info("Class " + name + " is already loaded by " + cls.getClassLoader().toString()); return cls; } if (name.contains("org.slf4j")) { LOG.error("Cannot load logging libraries. Delegate to parent"); return realParent.loadClass(name); } // first try to use the URLClassLoader findClass return super.findClass(name); } catch (ClassNotFoundException e) { // if that fails, ask real parent classloader to load the // class (give up) LOG.error(Freedomotic.getStackTraceInfo(e)); return realParent.loadClass(name); } } } }