/* * Copyright 2001-2008 Geert Bevin (gbevin[remove] at uwyn dot com) * Licensed under the Apache License, Version 2.0 (the "License") * $Id: EngineClassLoader.java 3918 2008-04-14 17:35:35Z gbevin $ */ package com.uwyn.rife.engine; import com.uwyn.rife.engine.instrument.ElementDetector; import com.uwyn.rife.instrument.ClassBytesProvider; import com.uwyn.rife.instrument.exceptions.ClassBytesNotFoundException; import com.uwyn.rife.resources.ModificationTimeClasspath; import com.uwyn.rife.site.instrument.ConstrainedDetector; import com.uwyn.rife.tools.ClassBytesLoader; import com.uwyn.rife.tools.FileUtils; import com.uwyn.rife.tools.InstrumentationUtils; import java.io.File; import java.io.UnsupportedEncodingException; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; import java.net.URLDecoder; import java.util.*; public class EngineClassLoader extends URLClassLoader implements ClassBytesProvider { public final static String DEFAULT_IMPLEMENTATIONS_PATH = "implementations/"; public final static String META_DATA_SUFFIX = "MetaData"; private static HashMap<String, Long> sModificationTimes = new HashMap<String, Long>(); private static List<String> sRifeWebappPath = null; private static boolean sRifeWebappPathProcessed = false; private Set<String> mModifiedClasses = null; private boolean mIsParentEngineclassloader = false; private EngineClassLoader mChild = null; private ClassLoader mInitiating = null; private Method mFindLoadedClassMethod = null; private ClassBytesLoader mByteLoader = null; private ElementDetector mElementDetector = null; private ConstrainedDetector mConstrainedDetector = null; private Class mMetaDataInstrumenterClass = null; private Method mMetaDataInstrumenterMethod = null; private Class mLazyLoadClass = null; private Method mLazyLoadMethod = null; private Object mEngineContinuationConfigInstrument = null; private Class mContinuationConfigInstrumentClass = null; private Class mResumerClass = null; private Method mResumerMethod = null; private String mClassLoaderName = "RIFE:EngineClassLoader"; public EngineClassLoader(ClassLoader parent) { super(new URL[0], parent); // check for the presence of Terracotta by loading its ClassProcessorHelper class try { Class classprocessorhelper_class = Class.forName("com.tc.object.bytecode.hook.impl.ClassProcessorHelper"); Class namedclassloader_class = Class.forName("com.tc.object.loaders.NamedClassLoader"); if (classprocessorhelper_class != null && namedclassloader_class != null) { if (namedclassloader_class.isAssignableFrom(parent.getClass())) { try { Method getclassloadername_method = namedclassloader_class.getDeclaredMethod("__tc_getClassLoaderName", new Class[0]); mClassLoaderName = "Rife:Engine:" + getclassloadername_method.invoke(parent, new Object[0]); Method method = classprocessorhelper_class.getDeclaredMethod("registerGlobalLoader", new Class[] {namedclassloader_class}); method.invoke(null, new Object[] {this}); } catch (Exception e) { throw new RuntimeException("Unable to register the engine classloader '"+mClassLoaderName+"' with Terracotta.", e); } } } } catch (ClassNotFoundException e) { // this is OK, Terracotta is not present in the classpath } mIsParentEngineclassloader = parent instanceof EngineClassLoader; if (mIsParentEngineclassloader) { mInitiating = ((EngineClassLoader)parent).mInitiating; } else { mInitiating = parent; } mByteLoader = new ClassBytesLoader(this); mByteLoader.setupSunByteLoading(); if (mByteLoader.isUsingSunByteLoading()) { addClassPathURLs(); } mElementDetector = new ElementDetector(this); mConstrainedDetector = new ConstrainedDetector(mByteLoader); } public String __tc_getClassLoaderName() { return mClassLoaderName; } public void __tc_setClassLoaderName(String name) { throw new UnsupportedOperationException("class loader name can not be modified for loader with name: " + mClassLoaderName); } private void addClassPathURLs() { try { Class classpathutils_class = loadClass("com.uwyn.rife.tools.ClasspathUtils"); Method classpathutils_method = classpathutils_class.getDeclaredMethod("getClassPathAsList", Class.class); List<String> classpath = (List<String>)classpathutils_method.invoke(null, getClass()); if (classpath != null) { for (String classpath_element : classpath) { addURL(new URL("file", null, classpath_element)); } } } catch (Throwable e) { throw new RuntimeException(e); } } private boolean containsModifiedClass(String classname) { if (null == mModifiedClasses) { return false; } if (mModifiedClasses.contains(classname)) { return true; } int innerclass_index = classname.indexOf("$"); if (innerclass_index != -1) { String containing_classname = classname.substring(0, innerclass_index); if (mModifiedClasses.contains(containing_classname)) { return true; } } return false; } protected Class loadClass(String classname, boolean resolve) throws ClassNotFoundException { return loadClass(classname, resolve, false); } synchronized public void markClassAsModified(String classname) { if (null == mModifiedClasses) { mModifiedClasses = new HashSet<String>(); } if (mChild != null && mModifiedClasses.contains(classname)) { mChild.markClassAsModified(classname); } else { if (null == mChild) { mChild = new EngineClassLoader(this); } mModifiedClasses.add(classname); } } public Class loadClass(String classname, boolean resolve, boolean loadElement) throws ClassNotFoundException { assert classname != null; // System.out.println(">>> "+classname); // get the auto reload preferences boolean auto_reload = doAutoReload(); // see if this classloader has cached the class with the provided name Class c = null; if (auto_reload && containsModifiedClass(classname)) { return mChild.loadClass(classname, resolve, loadElement); } if (null == c) { c = findLoadedClass(classname); } // if an already loaded version was found, check whether it's outdated or not if (c != null) { // if an already loaded version was found, check whether it's outdated or not // this can only be Element classes since those are the only ones that are // handled by this classloader if (auto_reload) { // if the element was modified, don't use the cached class // otherwise, just take the previous element class if (loadElement && isModified(classname)) { synchronized (this) { markClassAsModified(classname); Class klass = mChild.loadClass(classname, resolve, loadElement); clearSiteCaches(classname); return klass; } } } } // try to obtain the class in another way else { // try to load the core system classes first, these are sure to be // handled by the system classloader if (null == c) { if (classname.startsWith("java.")) { try { c = findSystemClass(classname); if (c != null) { if (resolve) { resolveClass(c); } // System.out.println("SYSTEM defined "+classname); return c; } } catch (ClassNotFoundException e) { c = null; } } } ClassLoader parent = getParent(); classname = classname.intern(); // Get classes already loaded by the servlet container's classloader, // to avoid loading them again. These will be classes loaded by other // filters and listeners inside the same web application, initialized // before RIFE. For RIFE these should only be the // EngineClassLoader-related classed and those of the continuations engine try { if (null == mFindLoadedClassMethod) { mFindLoadedClassMethod = ClassLoader.class.getDeclaredMethod("findLoadedClass", new Class[] {java.lang.String.class}); mFindLoadedClassMethod.setAccessible(true); } c = (Class)mFindLoadedClassMethod.invoke(mInitiating, (Object[])new String[] {classname}); // if (c != null) // { // System.out.println("PARENT defined "+classname+" (already loaded)"); // } } catch (Throwable e) { c = null; } // load the class through the initial EngineClassLoader, unless it // has been modified if (mIsParentEngineclassloader && !((EngineClassLoader)parent).containsModifiedClass(classname)) { // if (c != null) // { // System.out.println("PARENT loading "+classname); // } return ((EngineClassLoader)parent).loadClass(classname, resolve, loadElement); } // try to obtain the class in a RIFE-specific way if (null == c && !classname.startsWith("com.uwyn.rife.asm.") && !classname.startsWith("com.tc.object.loaders.")) { boolean webapp_class = false; boolean rife_class = false; if (classname == "com.uwyn.rife.engine.EngineClassLoaderRifeWebappPath") { webapp_class = true; } else { // This is not a problem, if several simultaneous threads // will access it, it will just be retrieved several times. // The calls will be cached for all subsequent threads // though. if (!sRifeWebappPathProcessed) { try { Class webapp_path_class = loadClass("com.uwyn.rife.engine.EngineClassLoaderRifeWebappPath"); Field webapp_path_field = webapp_path_class.getField("RIFE_WEBAPP_PATH"); sRifeWebappPath = (ArrayList<String>)webapp_path_field.get(null); sRifeWebappPathProcessed = true; } catch (Throwable e) { throw new ClassNotFoundException(classname, e); } } // check of the class is part of the web application, or if it should be loaded through // a parent classloader if (classname.startsWith("com.uwyn.rife.")) // classes are loaded by the EngineClassLoader { webapp_class = true; rife_class = true; } else { webapp_class = isWebAppClass(classname); } // only handle undefined classes, or check existing ones if // auto-reloading has been activated if (null == c || auto_reload) { String packagename = null; int packagename_index = classname.lastIndexOf('.'); if (packagename_index != -1) { packagename = classname.substring(0, packagename_index); } // first try to find the compiled bytecode, take inner classes // into account byte raw_bytes[] = null; int innerclass_index = classname.indexOf("$"); try { if (innerclass_index > -1) { raw_bytes = getClassBytes(classname.substring(0, innerclass_index), auto_reload, loadElement); } else { raw_bytes = getClassBytes(classname, auto_reload, loadElement); } } catch (ClassNotFoundException e) { raw_bytes = null; } if (raw_bytes != null) { // check if the bytes corresponds to an element class if (!isElement(classname, raw_bytes, auto_reload)) { // If it's not an element and the class hasn't been // defined yet, define it. If it has been found in the // parent, use the already existing instance. // Auto-reloading isn't supported for non-elements if (null == c) { if (!webapp_class) { try { // System.out.println("PARENT defined "+classname+" (not webapp class)"); if (!mIsParentEngineclassloader) { c = parent.loadClass(classname); } } catch (ClassNotFoundException e) { c = null; } } else { // System.out.println("ENGINE defined "+classname); if (packagename != null) { Package pkg = getPackage(packagename); if (null == pkg) { definePackage(packagename, null, null, null, null, null, null, null); } } // use the interned classname to get a synchronization lock monitor // that is specific for the current class that is loaded and // that will not lock up the classloading of all other classes // by for instance synchronizing on this classloader synchronized (classname) { // make sure that the class has not been defined in the // meantime, otherwise defining it again will trigger an // exception; // reuse the existing class if it has already been defined c = findLoadedClass(classname); if (null == c) { // if we are working with an inner class, get its // actual raw bytes, since we used the containing // class's bytes to determine if it's an element if (innerclass_index > -1) { raw_bytes = getClassBytes(classname, auto_reload, loadElement); } if (!rife_class) { // handle meta data sibling classes for non framework classes if (null == mMetaDataInstrumenterClass) { mMetaDataInstrumenterClass = loadClass("com.uwyn.rife.site.instrument.MetaDataInstrumenter"); } try { if (null == mMetaDataInstrumenterMethod) { mMetaDataInstrumenterMethod = mMetaDataInstrumenterClass.getDeclaredMethod("instrument", new Class[] {ClassLoader.class, String.class, byte[].class}); mMetaDataInstrumenterMethod.setAccessible(true); } raw_bytes = (byte[])mMetaDataInstrumenterMethod.invoke(null, new Object[] {this, classname, raw_bytes}); } catch (Exception e) { throw new ClassNotFoundException(classname, e); } try { if (isConstrained(classname, raw_bytes)) { // handle lazy loading for constrained non framework classes if (null == mLazyLoadClass) { mLazyLoadClass = loadClass("com.uwyn.rife.database.querymanagers.generic.instrument.LazyLoadAccessorsBytecodeTransformer"); } if (null == mLazyLoadMethod) { mLazyLoadMethod = mLazyLoadClass.getDeclaredMethod("addLazyLoadToBytes", new Class[] {byte[].class}); mLazyLoadMethod.setAccessible(true); } raw_bytes = (byte[])mLazyLoadMethod.invoke(null, new Object[] {raw_bytes}); } } catch (Exception e) { throw new ClassNotFoundException(classname, e); } } // define the class from its raw bytes InstrumentationUtils.dumpClassBytes("adapted", classname, raw_bytes); c = defineClass(classname, raw_bytes, 0, raw_bytes.length); if (null == c) { throw new ClassNotFoundException(classname); } } } } } } else { // if (null == c) // { // System.out.println("ENGINE defined "+classname); // } // else // { // System.out.println("ENGINE redefined "+classname); // } // if we are working with an inner class, get its // actual raw bytes, since we used the containing // class's bytes to determine if it's an element if (innerclass_index > -1) { raw_bytes = getClassBytes(classname, auto_reload, loadElement); } if (auto_reload) { // register the modification time of the source file long modification_time = getClassModificationTime(classname); sModificationTimes.put(classname, new Long(modification_time)); } // get an instance of the engine continuations config if (null == mEngineContinuationConfigInstrument) { Class config_class = loadClass("com.uwyn.rife.engine.EngineContinuationConfigInstrument"); try { Constructor config_constructor = config_class.getConstructor(new Class[0]); config_constructor.setAccessible(true); mEngineContinuationConfigInstrument = config_constructor.newInstance(new Object[0]); } catch (Exception e) { throw new ClassNotFoundException(classname, e); } } // get the continuation config instrument class if (null == mContinuationConfigInstrumentClass) { mContinuationConfigInstrumentClass = loadClass("com.uwyn.rife.continuations.ContinuationConfigInstrument"); } // transform bytes on-the-fly into resumable bytes byte[] resumable_bytes; if (null == mResumerClass) { mResumerClass = loadClass("com.uwyn.rife.continuations.instrument.ContinuationsBytecodeTransformer"); } try { if (null == mResumerMethod) { mResumerMethod = mResumerClass.getDeclaredMethod("transformIntoResumableBytes", new Class[] {mContinuationConfigInstrumentClass, byte[].class, String.class}); mResumerMethod.setAccessible(true); } resumable_bytes = (byte[])mResumerMethod.invoke(null, new Object[] {mEngineContinuationConfigInstrument, raw_bytes, classname}); } catch (Exception e) { throw new ClassNotFoundException(classname, e); } // define a package if needed if (packagename != null) { Package pkg = getPackage(packagename); if (null == pkg) { definePackage(packagename, null, null, null, null, null, null, null); } } // intern the classname to get a synchronization lock monitor // that is specific for the current class that is loaded and // that will not lock up the classloading of all other classes // by for instance synchronizing on this classloader classname = classname.intern(); synchronized (classname) { // make sure that the class has not been defined in the // meantime, otherwise defining it again will trigger an // exception; // reuse the existing class if it has already been defined c = findLoadedClass(classname); if (null == c) { // get the raw bytes of the class and define it for this classloader if (null == resumable_bytes) { InstrumentationUtils.dumpClassBytes("adapted", classname, raw_bytes); c = defineClass(classname, raw_bytes, 0, raw_bytes.length); } else { InstrumentationUtils.dumpClassBytes("adapted", classname, resumable_bytes); c = defineClass(classname, resumable_bytes, 0, resumable_bytes.length); } } } } } } } } } // the ultimate fallback class loading if (null == c && !mIsParentEngineclassloader) { try { c = getParent().loadClass(classname); // if (c != null) // { // System.out.println("FALLBACK PARENT defined "+classname+" (ultimate falback)"); // } } catch (ClassNotFoundException e) { c = null; } } if (null == c) { try { c = findSystemClass(classname); // System.out.println("FALLBACK SYSTEM defined "+classname); } catch (ClassNotFoundException e) { // System.out.println("!!!!!! not found "+classname); throw e; } } // resolve the class if it's needed if (resolve) { resolveClass(c); } assert c != null; return c; } private void clearSiteCaches(String classname) throws ClassNotFoundException { try { Class site_class = loadClass("com.uwyn.rife.engine.Site"); Method repinstance_method = site_class.getDeclaredMethod("getRepInstance", new Class[0]); Method clearcaches_method = site_class.getDeclaredMethod("clearCaches", new Class[0]); Object site = repinstance_method.invoke(null, new Object[0]); if (site != null) { clearcaches_method.invoke(site, new Object[0]); } } catch (Exception e) { e.printStackTrace(); throw new ClassNotFoundException(classname, e); } } private boolean isWebAppClass(String classname) { try { String class_file = classname.replace('.', '/') + ".class"; URL resource = getResource(class_file); if (resource != null) { // System.out.println("resource_path : " + resource.toExternalForm()); String resource_path = resource.getPath(); String resource_protocol = resource.getProtocol(); // if the resource lies in a WEB-INF dir, it's part // of a webapp if (resource_path.indexOf("WEB-INF") != -1) { return true; } // handle Orion's classloader resource protocol else if (resource_protocol != null && resource_protocol.equals("classloader")) { return true; } // if a specific rife webapp path collection has been // given, check against each entry else if (sRifeWebappPath != null) { if (resource_path.startsWith("jar:file:")) { resource_path = resource_path.substring("jar:file:".length()); } if (resource_path.startsWith("file:")) { resource_path = resource_path.substring("file:".length()); } int exclamation_index = resource_path.indexOf("!"); if (exclamation_index != -1) { resource_path = resource_path.substring(0, exclamation_index); } resource_path = URLDecoder.decode(resource_path, "ISO-8859-1"); File resource_file = new File(resource_path); if (resource_file.exists()) { resource_path = resource_file.getCanonicalPath(); for (String path : sRifeWebappPath) { if (resource_path.startsWith(path)) { return true; } } } } } } catch (Throwable e) { return false; } return false; } private boolean hasRepClass() { if (getParent() instanceof EngineClassLoader) { return ((EngineClassLoader)getParent()).hasRepClass(); } try { return findLoadedClass("com.uwyn.rife.rep.Rep") != null; } // fix to make it work with the IBM jvm catch (ClassCircularityError e) { return true; } } private boolean doAutoReload() { Object value = System.getProperties().get("ELEMENT_AUTO_RELOAD"); if (null == value) { return true; } if (value instanceof String) { String string_value = (String)value; if (string_value.equals("1") || string_value.equalsIgnoreCase("t") || string_value.equalsIgnoreCase("true") || string_value.equalsIgnoreCase("y") || string_value.equalsIgnoreCase("yes") || string_value.equalsIgnoreCase("on")) { return true; } } return false; } public static String constructSourcePath(String classname) { String source_location = null; int innerclass_index = classname.indexOf("$"); if (innerclass_index != -1) { String containing_classname = classname.substring(0, innerclass_index); source_location = containing_classname.replace('.', '/')+".java"; } else { source_location = classname.replace('.', '/')+".java"; } return source_location; } public byte[] getClassBytes(String className, boolean reloadAutomatically) throws ClassNotFoundException { return getClassBytes(className, reloadAutomatically, false); } public byte[] getClassBytes(String className, boolean doAutoReload, boolean performCompilation) throws ClassNotFoundException { byte[] raw_bytes = null; String class_filename = className.replace('.', '/')+".class"; URL class_resource = getResource(class_filename); try { // if it couldn't be found or if it's outdated when auto-reload is // activated, compile the element if ((null == class_resource || (doAutoReload && performCompilation && isModified(className))) && (-1 == className.indexOf('$') || !className.endsWith("BeanInfo"))) /// don't recompile for BeanInfo classes { try { if (!performCompilation && !hasRepClass()) { throw new ClassNotFoundException(className); } else { String source_location = constructSourcePath(className); File class_file = compileClass(className, source_location); raw_bytes = FileUtils.readBytes(class_file); } } catch (Throwable e) { Class elementcompilation_failed_class = loadClass("com.uwyn.rife.engine.exceptions.ElementCompilationFailedException"); if (e.getClass() == elementcompilation_failed_class) { throw (RuntimeException)e; } if (e instanceof ClassNotFoundException) { throw (ClassNotFoundException)e; } throw new ClassNotFoundException(className, e); } } // otherwise just get the bytes of the classfile else { raw_bytes = mByteLoader.getClassBytes(class_filename, class_resource); } } catch (ClassNotFoundException e) { throw e; } catch (Throwable e) { if (e instanceof RuntimeException) { throw (RuntimeException)e; } throw new ClassNotFoundException("Error while reading the contents of the element class file '"+className+"'.", e); } InstrumentationUtils.dumpClassBytes("initial", className, raw_bytes); return raw_bytes; } File compileClass(String classname, String sourceLocation) throws ClassNotFoundException { assert classname != null; assert sourceLocation != null; assert sourceLocation.endsWith(".java"); // try to find the script URL source_resource = getSourceResource(sourceLocation, true); if (null == source_resource) { throw new ClassNotFoundException("Couldn't find the source file '"+sourceLocation+"'."); } // get the package and the short classname of the element int classname_index = classname.lastIndexOf("."); String element_package = null; String element_classname = null; if (classname_index != -1) { element_package = classname.substring(0, classname_index); element_classname = classname.substring(classname_index+1); } else { element_classname = classname; } // setup everything to perform the conversion of the element to java sources // and to compile it into a java class Object generation_path_object = null; try { Class tests_class = loadClass("com.uwyn.rife.config.RifeConfig$Engine"); Method method = tests_class.getMethod("getElementGenerationPath", (Class[])null); generation_path_object = method.invoke(null, (Object[])null); } catch (Throwable e) { throw new ClassNotFoundException("Couldn't obtain the element bytecode generation path.", e); } String generation_path = ((String)generation_path_object)+File.separatorChar; String package_dir = ""; if (element_package != null) { package_dir = generation_path+element_package.replace('.', File.separatorChar)+File.separator; } else { package_dir = generation_path; } String filename_java = null; try { filename_java = URLDecoder.decode(source_resource.getPath(), "ISO-8859-1"); } catch (UnsupportedEncodingException e) { throw new ClassNotFoundException("Couldn't decode the resource path '"+source_resource.getPath()+"'.", e); } String filename_class = package_dir+element_classname+".class"; File file_packagedir = new File(package_dir); File file_class = new File(filename_class); // prepare the package directory if (!file_packagedir.exists()) { if (!file_packagedir.mkdirs()) { throw new ClassNotFoundException("Couldn't create the package directory : '"+package_dir+"'."); } } else if (!file_packagedir.isDirectory()) { throw new ClassNotFoundException("The package directory '"+package_dir+"' exists but is not a directory."); } else if (!file_packagedir.canWrite()) { throw new ClassNotFoundException("The package directory '"+package_dir+"' is not writable."); } // check if the class wasn't already compiled due to other classes // in the same source file boolean is_already_compiled = false; long source_modification_time = -1L; if (file_class.exists()) { long class_modification_time = file_class.lastModified(); source_modification_time = getSourceModificationTime(source_resource); if (class_modification_time >= source_modification_time) { is_already_compiled = true; } } if (!is_already_compiled) { try { Class classloader_classpath_class = loadClass("com.uwyn.rife.engine.EngineClassLoaderClasspath"); Field classloader_classpath_field = classloader_classpath_class.getField("CLASSPATH"); String classloader_classpath = (String)classloader_classpath_field.get(null); Class tests_class = loadClass("com.uwyn.rife.tools.CompilationUtils"); Method method = tests_class.getMethod("compile", new Class[] {String.class, File.class, String.class, String.class}); generation_path_object = method.invoke(null, new Object[] {filename_java, file_class, generation_path, classloader_classpath}); } catch (InvocationTargetException e) { Class compilation_failed_class = loadClass("com.uwyn.rife.tools.exceptions.CompilationFailedException"); Throwable target_exception = e.getTargetException(); if (compilation_failed_class == target_exception.getClass()) { String sourcefilename = null; String errors = null; Throwable cause = null; try { Method sourcefilename_method = compilation_failed_class.getMethod("getSourceFilename", (Class[])null); sourcefilename = (String)sourcefilename_method.invoke(target_exception, (Object[])null); Method errors_method = compilation_failed_class.getMethod("getErrors", (Class[])null); errors = (String)errors_method.invoke(target_exception, (Object[])null); Method cause_method = compilation_failed_class.getMethod("getCause", (Class[])null); cause = (Throwable)cause_method.invoke(target_exception, (Object[])null); } catch (Throwable e2) { throw new ClassNotFoundException("Unexpected error while compiling the element source '"+filename_java+"'+.", e); } Object elementcompilation_failed_instance = null; try { Class elementcompilation_failed_class = loadClass("com.uwyn.rife.engine.exceptions.ElementCompilationFailedException"); Constructor elementcompilation_failed_constructor = elementcompilation_failed_class.getConstructor(new Class[] {String.class, String.class, Throwable.class}); elementcompilation_failed_instance = elementcompilation_failed_constructor.newInstance(new Object[] {sourcefilename, errors, cause}); } catch (Throwable e2) { throw new ClassNotFoundException("Unexpected error while compiling the element source '"+filename_java+"'+.", e); } throw (RuntimeException)elementcompilation_failed_instance; } else { throw new ClassNotFoundException("Unexpected error while compiling the element source '"+filename_java+"'.", e); } } catch (Throwable e) { throw new ClassNotFoundException("Unexpected error while compiling the element source '"+filename_java+"'.", e); } } assert file_class != null; assert file_class.exists(); assert file_class.canRead(); return file_class; } private URL getSourceResource(String sourceLocation, boolean getElement) { URL source_resource = getResource(sourceLocation); if (null == source_resource && getElement) { source_resource = getResource(DEFAULT_IMPLEMENTATIONS_PATH+sourceLocation); } return source_resource; } private boolean isElement(String internedClassname, byte[] bytes, boolean doAutoReload) throws ClassNotFoundException { return mElementDetector.detect(internedClassname, bytes, doAutoReload); } private boolean isConstrained(String internedClassname, byte[] bytes) throws ClassBytesNotFoundException { return mConstrainedDetector.isConstrained(internedClassname, bytes); } private long getClassModificationTime(String classname) { return getSourceModificationTime(getSourceResource(constructSourcePath(classname), true)); } public static long getSourceModificationTime(URL sourceResource) { if (null == sourceResource) { return -1; } try { return ModificationTimeClasspath.getModificationTime(sourceResource); } catch (Throwable e) { return -1; } } private boolean isModified(String classname) { Long last_modification_time = sModificationTimes.get(classname); if (null == last_modification_time) { return false; } long current_modification_time = getClassModificationTime(classname); if (current_modification_time <= last_modification_time.longValue()) { return false; } return true; } }