X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.scl.reflection%2Fsrc%2Forg%2Fsimantics%2Fscl%2Freflection%2Finternal%2Fregistry%2FNamespace.java;fp=bundles%2Forg.simantics.scl.reflection%2Fsrc%2Forg%2Fsimantics%2Fscl%2Freflection%2Finternal%2Fregistry%2FNamespace.java;h=73be05f6ccb45a58fca0a8276df6420ac522c372;hp=0000000000000000000000000000000000000000;hb=969bd23cab98a79ca9101af33334000879fb60c5;hpb=866dba5cd5a3929bbeae85991796acb212338a08 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 index 000000000..73be05f6c --- /dev/null +++ b/bundles/org.simantics.scl.reflection/src/org/simantics/scl/reflection/internal/registry/Namespace.java @@ -0,0 +1,359 @@ +package org.simantics.scl.reflection.internal.registry; + +import gnu.trove.map.hash.THashMap; +import gnu.trove.procedure.TObjectObjectProcedure; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; + +import org.simantics.scl.compiler.types.Type; +import org.simantics.scl.compiler.types.Types; +import org.simantics.scl.compiler.types.exceptions.SCLTypeParseException; +import org.simantics.scl.compiler.types.util.ITypeEnvironment; +import org.simantics.scl.reflection.MinimalTypeBindingScheme; +import org.simantics.scl.reflection.ReflectionUtils; +import org.simantics.scl.reflection.TypeBindingScheme; +import org.simantics.scl.reflection.TypeNotFoundException; +import org.simantics.scl.reflection.TypedValue; +import org.simantics.scl.reflection.ValueNotFoundException; +import org.simantics.scl.reflection.annotations.SCLType; +import org.simantics.scl.reflection.annotations.SCLValue; +import org.simantics.scl.reflection.functions.ClassMethodFunction; +import org.simantics.scl.reflection.functions.ClassMethodFunction3; +import org.simantics.scl.reflection.functions.ConstructorFunction; +import org.simantics.scl.reflection.functions.FieldAccessorFunction; +import org.simantics.scl.reflection.functions.InstanceMethodFunction; +import org.simantics.scl.reflection.internal.Activator; +import org.simantics.scl.reflection.internal.typeRegistry.TypeRegistry; + +public class Namespace { + String namespace; + ImportSeq importSeq; + ArrayList classes = new ArrayList(); + ArrayList externalClasses = + new ArrayList(); + ArrayList externalMethods = + new ArrayList(); + volatile THashMap> types; + volatile THashMap values; + + public Namespace(String namespace, ImportSeq importSeq) { + this.namespace = namespace; + this.importSeq = importSeq; + } + + public void addClass(Entry e) { + classes.add(e); + } + + public void addExternalMethod(ExternalMethod e) { + externalMethods.add(e); + } + + public void addExternalClass(ExternalClass e) { + externalClasses.add(e); + } + + public Class getClass(String name) throws TypeNotFoundException { + if(types == null) { + try { + initializeTypes(); + } catch (Exception e) { + throw new TypeNotFoundException(e); + } + } + Class type = types.get(name); + if(type == null) + throw new TypeNotFoundException("Didn't find type " + name + "."); + return type; + } + + public TypedValue getValue(String name) throws ValueNotFoundException { + if(values == null) { + try { + initializeValues(); + } catch (Exception e) { + e.printStackTrace(); + throw new ValueNotFoundException(e); + } + } + TypedValue value = values.get(name); + if(value == null) + throw new ValueNotFoundException("Didn't find value " + name + "."); + return value; + } + + ITypeEnvironment typeEnvironment = new ITypeEnvironment() { + + @Override + public Type resolve(String namespace, String name) { + if(namespace == null) { + if(TypeRegistry.isBuiltin(name)) + namespace = Types.BUILTIN; + else if(types.contains(name)) + namespace = Namespace.this.namespace; + else + namespace = ""; + } + else { + for(ImportSeq cur = importSeq;cur != null;cur = cur.parent) { + if(namespace.equals(cur.localName)) { + namespace = cur.path; + break; + } + } + } + return Types.con(namespace, name); + } + + }; + + private Type parseType(String typeText) throws SCLTypeParseException { + return Types.closure(Types.parseType(typeEnvironment, typeText)); + } + + private synchronized void initializeTypes() { + if(types == null) { + types = new THashMap>(); + + for(Entry entry : classes) { + Class clazz = entry.loadClass(); + if(clazz == null) { + Activator.logError("Didn't find class " + entry.name + "."); + continue; + } + + SCLType sclType = clazz.getAnnotation(SCLType.class); + if(sclType != null) { + String name = sclType.name(); + if(name.isEmpty()) + name = clazz.getSimpleName(); + types.put(name, clazz); + } + } + + for(ExternalClass entry : externalClasses) { + Class clazz = entry.loadClass(); + if(clazz == null) { + Activator.logError("Didn't find class " + entry.className + "."); + continue; + } + + String name = entry.alternativeName; + if(name == null) + name = clazz.getSimpleName(); + types.put(name, clazz); + } + } + } + + private void handleMethod(TypeBindingScheme scheme, Class clazz, Method method) { + SCLValue sclValue = method.getAnnotation(SCLValue.class); + if(sclValue != null) { + String name = sclValue.name(); + if(name.isEmpty()) + name = method.getName(); + Type type; + try { + type = parseType(sclValue.type()); + } catch (SCLTypeParseException e) { + Activator.logError("Method " + method.getName() + " in class " + + clazz.getCanonicalName() + " has invalid type declaration.", e + ); + return; + } + try { + if(ReflectionUtils.isCompatible(scheme, type, method)) { + Object value; + if(Modifier.isStatic(method.getModifiers())) { + int arity = method.getParameterTypes().length; + if(arity == 3) + value = new ClassMethodFunction3(method); + else + value = new ClassMethodFunction(method); + } + else + value = new InstanceMethodFunction(method); + values.put(name, new TypedValue(type, value)); + } + else { + Activator.logError("Method " + method.getName() + " in class " + + clazz.getCanonicalName() + " has incompantible SCL type in the SCLValue annotation." + ); + ReflectionUtils.isCompatible(scheme, type, method); + } + } catch (TypeNotFoundException e) { + Activator.logError("Couldn't find all types in the type declaration of method " + method.getName() + " in class " + + clazz.getCanonicalName() + "." + ); + } + } + } + + private void handleConstructor(TypeBindingScheme scheme, Class clazz, Constructor constr) { + SCLValue sclValue = constr.getAnnotation(SCLValue.class); + if(sclValue != null) { + String name = sclValue.name(); + if(name.isEmpty()) + name = constr.getDeclaringClass().getSimpleName(); + Type type; + try { + type = parseType(sclValue.type()); + } catch (SCLTypeParseException e) { + Activator.logError("Constructor in " + + clazz.getCanonicalName() + " has invalid type declaration.", e + ); + return; + } + try { + if(ReflectionUtils.isCompatible(scheme, type, constr)) { + Object value = new ConstructorFunction(constr); + values.put(name, new TypedValue(type, value)); + } + else { + Activator.logError("Constructor of " + + clazz.getCanonicalName() + " has incompantible SCL type in the SCLValue annotation." + ); + } + } catch (TypeNotFoundException e) { + Activator.logError("Couldn't find all types in the type declaration of constructor in " + + clazz.getCanonicalName() + "." + ); + } + } + } + + private void handleField(TypeBindingScheme scheme, Class clazz, Field field) { + SCLValue sclValue = field.getAnnotation(SCLValue.class); + if(sclValue != null) { + String name = sclValue.name(); + if(name.isEmpty()) + name = field.getName(); + Type type; + try { + type = parseType(sclValue.type()); + } catch (SCLTypeParseException e) { + Activator.logError("Field " + field.getName() + " in class " + + clazz.getCanonicalName() + " has invalid type declaration.", e + ); + return; + } + try { + if(ReflectionUtils.isCompatible(scheme, type, field)) { + Object value; + if(Modifier.isStatic(field.getModifiers())) + try { + value = field.get(null); + } catch (IllegalArgumentException e) { + Activator.logError("Cannot read field " + field.getName() + " in class " + + clazz.getCanonicalName() + ".", e + ); + return; + } catch (IllegalAccessException e) { + Activator.logError("Cannot read field " + field.getName() + " in class " + + clazz.getCanonicalName() + ".", e + ); + return; + } + else + value = new FieldAccessorFunction(field); + values.put(name, new TypedValue(type, value)); + } + else { + Activator.logError("Field " + field.getName() + " in class " + + clazz.getCanonicalName() + " has incompantible SCL type in the SCLValue annotation." + ); + } + } catch (TypeNotFoundException e) { + Activator.logError("Couldn't find all types in the type declaration of field " + field.getName() + " in class " + + clazz.getCanonicalName() + "." + ); + } + } + } + + private synchronized void initializeValues() { + if(values == null) { + initializeTypes(); + TypeBindingScheme scheme = MinimalTypeBindingScheme.INSTANCE; + + values = new THashMap(); + + for(Entry entry : classes) { + Class clazz = entry.loadClass(); + + if(clazz == null) { + Activator.logError("Didn't find class " + entry.name + "."); + continue; + } + + for(Method method : clazz.getMethods()) { + handleMethod(scheme, clazz, method); + } + + for(Constructor constr : clazz.getConstructors()) { + handleConstructor(scheme, clazz, constr); + } + + for(Field field : clazz.getFields()) { + handleField(scheme, clazz, field); + } + } + + for(ExternalMethod entry : externalMethods) { + Class clazz = entry.loadClass(); + + if(clazz == null) { + Activator.logError("Didn't find class " + entry.className + "."); + continue; + } + + Method method = entry.getMethod(clazz); + + if(method == null) { + Activator.logError("Didn't find method " + entry.methodName + + " in class " + entry.className + "."); + continue; + } + + handleMethod(scheme, clazz, method); + } + } + } + + public void print() { + for(Entry entry : classes) { + System.out.println(" " + entry.name + " (" + entry.bundle + ")"); + } + try { + initializeTypes(); + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + types.forEachEntry(new TObjectObjectProcedure>() { + @Override + public boolean execute(String name, Class clazz) { + System.out.println(" type " + name + " = " + clazz.getCanonicalName()); + return true; + } + }); + try { + initializeValues(); + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + values.forEachEntry(new TObjectObjectProcedure() { + @Override + public boolean execute(String name, TypedValue value) { + System.out.println(" " + name + " :: " + value.getType()); + return true; + } + }); + } + +}