package net.sourceforge.pain.logic; import net.sourceforge.pain.*; import net.sourceforge.pain.data.*; import net.sourceforge.pain.util.*; import java.io.*; import java.util.*; /** * Class responsible for logic loading */ public class LogicLoader { private String EVENTS_PACKAGE; private String classesDir; private String logicPackages[] = new String[0]; private int counter = 0;//for debug use /** * classloaders by classname */ private LogicClassLoader loader = new LogicClassLoader(); private Set reloadListeners = new HashSet(); public LogicLoader(String cd) { File dir = new File(cd); if (!dir.isDirectory()) { throw new IllegalArgumentException("not a directory:" + dir.getAbsolutePath()); } classesDir = cd; } /** * Knowledge of default event package allows to instantiate events by name * without indication of package prefix * * @param eventPackagePrefix - package name with dot on it's end. (example: net.sourceforge.pain.tinylib.logic.) */ public void setEventsPackagePrefix(String eventPackagePrefix) { assert EVENTS_PACKAGE == null; if (!eventPackagePrefix.endsWith(".")) { throw new IllegalArgumentException("events package prefix should ends with '.' "); } EVENTS_PACKAGE = eventPackagePrefix; _addLogicPackage(EVENTS_PACKAGE); } /** * @param packagePrefix - package name with dot on it's end. (example: net.sourceforge.pain.tinylib.logic.) */ public void addLogicPackage(String packagePrefix) { if (packagePrefix.endsWith(".")) { throw new IllegalArgumentException("logic package prefix should ends with '.' "); } _addLogicPackage(packagePrefix); } public synchronized Class provideClass(String className) throws ClassNotFoundException { Class c = loader._findLoadedClass(className); if (c != null) { Log.debug("LL:findLoadedClass works!:" + className); return c; } // net.sourceforge.pain.logic.Event is not reloadable system class! if (!isInLogicPackages(className)) { if (Codebase.getPluginManager().isInPluginPackages(className)) { Log.debug("LL:Asking plugin from LOGIC LOADER:" + className); return Codebase.getPluginManager().loadClassByPluginClassloader(null, className); } try { c = Class.forName(className); } catch (LinkageError error) { if (error instanceof NoClassDefFoundError && error.getMessage().indexOf("wrong name:") > 0) { // case insensitive filesystem -> we will hide this errors } else { // this will not stop server but will panic! Log.error("PANIC!!!", error); } throw new ClassNotFoundException("Error during systen class loading!", error); } Log.debug("findSystemClass works!:" + className); return c; } Log.debug("LL:asking logic class:" + className); c = loader.defineClassFromFile(className); return c; } private boolean isInLogicPackages(String fullClassName) { for (int i = 0; i < logicPackages.length; i++) { if (fullClassName.startsWith(logicPackages[i])) { return true; } } return false; } public synchronized void reload() { try { Codebase.processEvent("LogicReloadingEvent", null); } catch (Exception e) { Log.error(e); } for (Iterator iterator = reloadListeners.iterator(); iterator.hasNext();) { LogicReloadListener logicReloadListener = (LogicReloadListener) iterator.next(); try { logicReloadListener.onLogicReloading(); } catch (Exception e) { Log.error(e); } } ObjectFactory.__cleanCaches(); TriggersLogicFactory.__cleanCaches(); loader = new LogicClassLoader(); System.gc(); } public void addLogicReloadListener(LogicReloadListener l) { reloadListeners.add(l); } public void removeReloadLogicListener(LogicReloadListener l) { reloadListeners.remove(l); } public ClassLoader getActiveClassLoader() { return loader; } public Class provideEventClass(String eventClassSuffix) throws ClassNotFoundException { if (EVENTS_PACKAGE != null) { return provideClass(EVENTS_PACKAGE + eventClassSuffix); } throw new IllegalStateException("event package was not initialized!"); } private synchronized void _addLogicPackage(String packageStr) { for (int i = logicPackages.length; --i >= 0;) { if (logicPackages[i].equals(packageStr)) { return; } } String[] tmp = new String[logicPackages.length + 1]; System.arraycopy(logicPackages, 0, tmp, 0, logicPackages.length); tmp[logicPackages.length] = packageStr; logicPackages = tmp; } class LogicClassLoader extends ClassLoader { int number = counter; protected LogicClassLoader() { } public synchronized Class loadClass(String className) throws ClassNotFoundException { Log.debug("LOGIC LOADER[" + number + "]: ask load:" + className); return provideClass(className); } protected Class defineClassFromFile(String className) throws ClassNotFoundException { try { byte[] data = IOUtils.getFileData(classesDir + "/" + className.replace('.', '/') + ".class"); return super.defineClass(className, data, 0, data.length); } catch (IOException e) { Log.warn("Can't load class file! " + e.getMessage()); throw new ClassNotFoundException("Class File Not Found:" + classesDir + "/" + className + ".class"); } } protected Class _findLoadedClass(String className) { return super.findLoadedClass(className); } protected void finalize() { Log.debug("LOGIC LOADER[" + number + "]:finalizing"); } } }