--- /dev/null
+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