]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scl.reflection/src/org/simantics/scl/reflection/internal/registry/Namespace.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.scl.reflection / src / org / simantics / scl / reflection / internal / registry / Namespace.java
diff --git a/bundles/org.simantics.scl.reflection/src/org/simantics/scl/reflection/internal/registry/Namespace.java b/bundles/org.simantics.scl.reflection/src/org/simantics/scl/reflection/internal/registry/Namespace.java
new file mode 100755 (executable)
index 0000000..73be05f
--- /dev/null
@@ -0,0 +1,359 @@
+package org.simantics.scl.reflection.internal.registry;\r
+\r
+import gnu.trove.map.hash.THashMap;\r
+import gnu.trove.procedure.TObjectObjectProcedure;\r
+\r
+import java.lang.reflect.Constructor;\r
+import java.lang.reflect.Field;\r
+import java.lang.reflect.Method;\r
+import java.lang.reflect.Modifier;\r
+import java.util.ArrayList;\r
+\r
+import org.simantics.scl.compiler.types.Type;\r
+import org.simantics.scl.compiler.types.Types;\r
+import org.simantics.scl.compiler.types.exceptions.SCLTypeParseException;\r
+import org.simantics.scl.compiler.types.util.ITypeEnvironment;\r
+import org.simantics.scl.reflection.MinimalTypeBindingScheme;\r
+import org.simantics.scl.reflection.ReflectionUtils;\r
+import org.simantics.scl.reflection.TypeBindingScheme;\r
+import org.simantics.scl.reflection.TypeNotFoundException;\r
+import org.simantics.scl.reflection.TypedValue;\r
+import org.simantics.scl.reflection.ValueNotFoundException;\r
+import org.simantics.scl.reflection.annotations.SCLType;\r
+import org.simantics.scl.reflection.annotations.SCLValue;\r
+import org.simantics.scl.reflection.functions.ClassMethodFunction;\r
+import org.simantics.scl.reflection.functions.ClassMethodFunction3;\r
+import org.simantics.scl.reflection.functions.ConstructorFunction;\r
+import org.simantics.scl.reflection.functions.FieldAccessorFunction;\r
+import org.simantics.scl.reflection.functions.InstanceMethodFunction;\r
+import org.simantics.scl.reflection.internal.Activator;\r
+import org.simantics.scl.reflection.internal.typeRegistry.TypeRegistry;\r
+\r
+public class Namespace {\r
+    String namespace;\r
+    ImportSeq importSeq;\r
+    ArrayList<Entry> classes = new ArrayList<Entry>();\r
+    ArrayList<ExternalClass> externalClasses = \r
+            new ArrayList<ExternalClass>();\r
+    ArrayList<ExternalMethod> externalMethods = \r
+            new ArrayList<ExternalMethod>();\r
+    volatile THashMap<String, Class<?>> types;\r
+    volatile THashMap<String, TypedValue> values;    \r
+    \r
+    public Namespace(String namespace, ImportSeq importSeq) {\r
+        this.namespace = namespace;\r
+        this.importSeq = importSeq;\r
+    }\r
+\r
+    public void addClass(Entry e) {\r
+        classes.add(e);\r
+    }\r
+    \r
+    public void addExternalMethod(ExternalMethod e) {\r
+        externalMethods.add(e);\r
+    }\r
+    \r
+    public void addExternalClass(ExternalClass e) {\r
+        externalClasses.add(e);\r
+    }\r
+    \r
+    public Class<?> getClass(String name) throws TypeNotFoundException {\r
+        if(types == null) {\r
+            try {\r
+                initializeTypes();\r
+            } catch (Exception e) {\r
+                throw new TypeNotFoundException(e);\r
+            } \r
+        }\r
+        Class<?> type = types.get(name);\r
+        if(type == null)\r
+            throw new TypeNotFoundException("Didn't find type " + name + ".");\r
+        return type;\r
+    }\r
+    \r
+    public TypedValue getValue(String name) throws ValueNotFoundException {\r
+        if(values == null) {\r
+            try {\r
+                initializeValues();\r
+            } catch (Exception e) {\r
+               e.printStackTrace();\r
+                throw new ValueNotFoundException(e);\r
+            } \r
+        }\r
+        TypedValue value = values.get(name);\r
+        if(value == null)\r
+            throw new ValueNotFoundException("Didn't find value " + name + ".");\r
+        return value;\r
+    }\r
+    \r
+    ITypeEnvironment typeEnvironment = new ITypeEnvironment() {\r
+        \r
+        @Override\r
+        public Type resolve(String namespace, String name) {\r
+            if(namespace == null) {\r
+                if(TypeRegistry.isBuiltin(name))\r
+                    namespace = Types.BUILTIN;\r
+                else if(types.contains(name))\r
+                    namespace = Namespace.this.namespace;\r
+                else\r
+                    namespace = "";\r
+            }\r
+            else {\r
+                for(ImportSeq cur = importSeq;cur != null;cur = cur.parent) {\r
+                    if(namespace.equals(cur.localName)) {\r
+                        namespace = cur.path;\r
+                        break;\r
+                    }\r
+                }\r
+            }\r
+            return Types.con(namespace, name);\r
+        }\r
+        \r
+    };\r
+    \r
+    private Type parseType(String typeText) throws SCLTypeParseException {\r
+        return Types.closure(Types.parseType(typeEnvironment, typeText));\r
+    }\r
+\r
+    private synchronized void initializeTypes() {\r
+        if(types == null) {\r
+            types = new THashMap<String, Class<?>>();\r
+            \r
+            for(Entry entry : classes) {\r
+                Class<?> clazz = entry.loadClass();\r
+                if(clazz == null) {\r
+                    Activator.logError("Didn't find class " + entry.name + ".");\r
+                    continue;\r
+                }\r
+\r
+                SCLType sclType = clazz.getAnnotation(SCLType.class);                    \r
+                if(sclType != null) {\r
+                    String name = sclType.name();\r
+                    if(name.isEmpty())\r
+                        name = clazz.getSimpleName();\r
+                    types.put(name, clazz);\r
+                }\r
+            }\r
+            \r
+            for(ExternalClass entry : externalClasses) {\r
+                Class<?> clazz = entry.loadClass();\r
+                if(clazz == null) {\r
+                    Activator.logError("Didn't find class " + entry.className + ".");\r
+                    continue;\r
+                }\r
+                \r
+                String name = entry.alternativeName;\r
+                if(name == null)\r
+                    name = clazz.getSimpleName();\r
+                types.put(name, clazz);\r
+            }\r
+        }        \r
+    }\r
+    \r
+    private void handleMethod(TypeBindingScheme scheme, Class<?> clazz, Method method) {\r
+        SCLValue sclValue = method.getAnnotation(SCLValue.class);\r
+        if(sclValue != null) {\r
+            String name = sclValue.name();\r
+            if(name.isEmpty())\r
+                name = method.getName();        \r
+            Type type;\r
+            try {\r
+                type = parseType(sclValue.type());\r
+            } catch (SCLTypeParseException e) {\r
+                Activator.logError("Method " + method.getName() + " in class " + \r
+                        clazz.getCanonicalName() + " has invalid type declaration.", e\r
+                        );\r
+                return;\r
+            }\r
+            try {\r
+                if(ReflectionUtils.isCompatible(scheme, type, method)) {\r
+                    Object value;\r
+                    if(Modifier.isStatic(method.getModifiers())) {\r
+                        int arity = method.getParameterTypes().length;\r
+                        if(arity == 3)\r
+                            value = new ClassMethodFunction3(method);\r
+                        else\r
+                            value = new ClassMethodFunction(method);\r
+                    }\r
+                    else\r
+                        value = new InstanceMethodFunction(method);\r
+                    values.put(name, new TypedValue(type, value));\r
+                }\r
+                else {\r
+                    Activator.logError("Method " + method.getName() + " in class " + \r
+                            clazz.getCanonicalName() + " has incompantible SCL type in the SCLValue annotation."\r
+                            );\r
+                    ReflectionUtils.isCompatible(scheme, type, method);\r
+                }\r
+            } catch (TypeNotFoundException e) {\r
+                Activator.logError("Couldn't find all types in the type declaration of method " + method.getName() + " in class " + \r
+                        clazz.getCanonicalName() + "."\r
+                        );\r
+            }\r
+        }\r
+    }\r
+    \r
+    private void handleConstructor(TypeBindingScheme scheme, Class<?> clazz, Constructor<?> constr) {\r
+        SCLValue sclValue = constr.getAnnotation(SCLValue.class);\r
+        if(sclValue != null) {\r
+            String name = sclValue.name();\r
+            if(name.isEmpty())\r
+                name = constr.getDeclaringClass().getSimpleName();\r
+            Type type;\r
+            try {\r
+                type = parseType(sclValue.type());\r
+            } catch (SCLTypeParseException e) {\r
+                Activator.logError("Constructor in " + \r
+                        clazz.getCanonicalName() + " has invalid type declaration.", e\r
+                        );\r
+                return;\r
+            }\r
+            try {\r
+                if(ReflectionUtils.isCompatible(scheme, type, constr)) {\r
+                    Object value = new ConstructorFunction(constr);\r
+                    values.put(name, new TypedValue(type, value));\r
+                }\r
+                else {\r
+                    Activator.logError("Constructor of " + \r
+                            clazz.getCanonicalName() + " has incompantible SCL type in the SCLValue annotation."\r
+                            );\r
+                }\r
+            } catch (TypeNotFoundException e) {\r
+                Activator.logError("Couldn't find all types in the type declaration of constructor in " + \r
+                        clazz.getCanonicalName() + "."\r
+                        );\r
+            }\r
+        }\r
+    }\r
+    \r
+    private void handleField(TypeBindingScheme scheme, Class<?> clazz, Field field) {\r
+        SCLValue sclValue = field.getAnnotation(SCLValue.class);\r
+        if(sclValue != null) {\r
+            String name = sclValue.name();\r
+            if(name.isEmpty())\r
+                name = field.getName();\r
+            Type type;\r
+            try {\r
+                type = parseType(sclValue.type());\r
+            } catch (SCLTypeParseException e) {\r
+                Activator.logError("Field " + field.getName() + " in class " + \r
+                        clazz.getCanonicalName() + " has invalid type declaration.", e\r
+                        );\r
+                return;\r
+            }\r
+            try {\r
+                if(ReflectionUtils.isCompatible(scheme, type, field)) {\r
+                    Object value;\r
+                    if(Modifier.isStatic(field.getModifiers()))\r
+                        try {\r
+                            value = field.get(null);\r
+                        } catch (IllegalArgumentException e) {\r
+                            Activator.logError("Cannot read field " + field.getName() + " in class " + \r
+                                    clazz.getCanonicalName() + ".", e\r
+                                    );\r
+                            return;\r
+                        } catch (IllegalAccessException e) {\r
+                            Activator.logError("Cannot read field " + field.getName() + " in class " + \r
+                                    clazz.getCanonicalName() + ".", e\r
+                                    );\r
+                            return;\r
+                        }\r
+                    else\r
+                        value = new FieldAccessorFunction(field);\r
+                    values.put(name, new TypedValue(type, value));\r
+                }\r
+                else {\r
+                    Activator.logError("Field " + field.getName() + " in class " + \r
+                            clazz.getCanonicalName() + " has incompantible SCL type in the SCLValue annotation."\r
+                            );\r
+                }\r
+            } catch (TypeNotFoundException e) {\r
+                Activator.logError("Couldn't find all types in the type declaration of field " + field.getName() + " in class " + \r
+                        clazz.getCanonicalName() + "."\r
+                        );\r
+            }\r
+        }\r
+    }        \r
+        \r
+    private synchronized void initializeValues() {\r
+        if(values == null) {\r
+            initializeTypes();\r
+            TypeBindingScheme scheme = MinimalTypeBindingScheme.INSTANCE;\r
+            \r
+            values = new THashMap<String, TypedValue>();\r
+            \r
+            for(Entry entry : classes) {\r
+                Class<?> clazz = entry.loadClass();\r
+                \r
+                if(clazz == null) {\r
+                    Activator.logError("Didn't find class " + entry.name + ".");\r
+                    continue;\r
+                }\r
+                \r
+                for(Method method : clazz.getMethods()) {\r
+                    handleMethod(scheme, clazz, method);\r
+                }\r
+                \r
+                for(Constructor<?> constr : clazz.getConstructors()) {\r
+                    handleConstructor(scheme, clazz, constr);\r
+                }\r
+                \r
+                for(Field field : clazz.getFields()) {\r
+                    handleField(scheme, clazz, field);\r
+                }\r
+            }\r
+            \r
+            for(ExternalMethod entry : externalMethods) {\r
+                Class<?> clazz = entry.loadClass();\r
+                \r
+                if(clazz == null) {\r
+                    Activator.logError("Didn't find class " + entry.className + ".");\r
+                    continue;\r
+                }\r
+                \r
+                Method method = entry.getMethod(clazz);\r
+                \r
+                if(method == null) {\r
+                    Activator.logError("Didn't find method " + entry.methodName + \r
+                            " in class " + entry.className + ".");\r
+                    continue;\r
+                }\r
+                \r
+                handleMethod(scheme, clazz, method);\r
+            }\r
+        }        \r
+    }\r
+    \r
+    public void print() {        \r
+        for(Entry entry : classes) {\r
+            System.out.println("    " + entry.name + " (" + entry.bundle + ")");\r
+        }\r
+        try {\r
+            initializeTypes();\r
+        } catch (Exception e) {\r
+            e.printStackTrace();\r
+            throw new RuntimeException(e);\r
+        } \r
+        types.forEachEntry(new TObjectObjectProcedure<String, Class<?>>() {            \r
+            @Override\r
+            public boolean execute(String name, Class<?> clazz) {\r
+                System.out.println("    type " + name + " = " + clazz.getCanonicalName());\r
+                return true;\r
+            }\r
+        });\r
+        try {\r
+            initializeValues();\r
+        } catch (Exception e) {\r
+            e.printStackTrace();\r
+            throw new RuntimeException(e);\r
+        } \r
+        values.forEachEntry(new TObjectObjectProcedure<String, TypedValue>() {            \r
+            @Override\r
+            public boolean execute(String name, TypedValue value) {\r
+                System.out.println("    " + name + " :: " + value.getType());\r
+                return true;\r
+            }\r
+        });\r
+    }\r
+    \r
+}\r