]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/runtime/ExpressionClassLoader.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / runtime / ExpressionClassLoader.java
diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/runtime/ExpressionClassLoader.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/runtime/ExpressionClassLoader.java
new file mode 100644 (file)
index 0000000..bb2e5ef
--- /dev/null
@@ -0,0 +1,119 @@
+package org.simantics.scl.compiler.runtime;
+
+import gnu.trove.map.hash.THashMap;
+
+import java.util.Map;
+
+import org.simantics.scl.compiler.constants.Constant;
+
+public class ExpressionClassLoader extends ClassLoader implements MutableClassLoader {
+    public static final boolean VALIDATE_CLASS_NAMES = true;
+    public static final boolean TRACE_CLASS_CREATION = false;
+    
+    String basePackageName;
+    THashMap<String, byte[]> localClasses = new THashMap<String, byte[]>(); 
+    THashMap<String, RuntimeModule> runtimeModuleMap;
+    int transientPackageId = 0;
+    THashMap<Constant,Object> valueCache = new THashMap<Constant,Object>(); 
+    
+    public ExpressionClassLoader(ClassLoader parent, THashMap<String, RuntimeModule> runtimeModuleMap, String basePackageName) {
+        super(parent);
+        this.basePackageName = basePackageName;
+        this.runtimeModuleMap = runtimeModuleMap;
+    }
+    
+    public synchronized void addClass(String name, byte[] class_) {
+        if(TRACE_CLASS_CREATION)
+            System.out.println("addClass " + name + " (" + class_.length + " bytes)");
+        if(VALIDATE_CLASS_NAMES)
+            validateClassName(name);
+        localClasses.put(name, class_);
+    }
+    
+    public synchronized void addClasses(Map<String, byte[]> classes) {
+        if(TRACE_CLASS_CREATION)
+            for(String name : classes.keySet())
+                System.out.println("addClass " + name + " (" + classes.get(name).length + " bytes)");
+        if(VALIDATE_CLASS_NAMES)
+            for(String name : classes.keySet())
+                validateClassName(name);
+        localClasses.putAll(classes);
+    }
+    
+    private void validateClassName(String name) {
+        /*if(!name.startsWith(SCL_PACKAGE_PREFIX) || !extractClassLoaderId(name).equals(basePackageName))
+            throw new IllegalArgumentException("Class name " + name + " does not start with '" +
+                    SCL_PACKAGE_PREFIX + basePackageName + "$'.");*/
+    }
+    
+    private synchronized Class<?> getLocalClass(String name) throws ClassNotFoundException {
+        // Is class already loaded
+        Class<?> clazz = findLoadedClass(name);
+        if(clazz != null)
+            return clazz;
+
+        // If we have bytecode for it, let's define the class
+        byte[] bytes = localClasses.get(name.replace('.', '/'));
+        if(bytes == null)
+            throw new ClassNotFoundException(name);
+
+        return defineClass(name, bytes, 0, bytes.length);
+    }
+    
+    private Class<?> getClass(String name) throws ClassNotFoundException {
+        //System.out.println("getClass " + name);
+        
+        // If the class is not generated from SCL, use parent class loader
+        if(!name.startsWith(SCL_PACKAGE_PREFIX)) {
+            try {
+                return getParent().loadClass(name);
+            } catch(ClassNotFoundException e) {
+                for(RuntimeModule module : runtimeModuleMap.values())
+                    try {
+                        return module.classLoader.getParent().loadClass(name);
+                    } catch(ClassNotFoundException e2) {
+                    }
+            }
+            throw new ClassNotFoundException(name);
+        }
+        
+        // Determine the id of the class loader which is responsible of the class
+        String requestedModuleName = RuntimeModule.extractClassLoaderId(name);
+        
+        // Is class defined locally in this class loader?
+        if(requestedModuleName.equals(basePackageName))
+            return getLocalClass(name);
+
+        // Find suitable class loader that has this class locally
+        else {
+            RuntimeModule parentModule = runtimeModuleMap.get(requestedModuleName);
+            if(parentModule == null)
+                throw new ClassNotFoundException(name);
+
+            // Find the class from the ancestor class loader
+            return parentModule.classLoader.getLocalClass(name);
+        }
+    }
+    
+    @Override
+    public synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+        Class<?> clazz = getClass(name);
+        if (resolve)
+            resolveClass(clazz);
+        return clazz;
+    }
+    
+    public synchronized String getFreshPackageName() {
+        return basePackageName + "$" + (++transientPackageId);
+    }
+
+    @Override
+    public THashMap<Constant, Object> getConstantCache() {
+        return valueCache;
+    }
+
+    @Override
+    public ClassLoader getClassLoader() {
+        return this;
+    }
+}