1 package org.simantics.scl.reflection.internal.registry;
3 import gnu.trove.map.hash.THashMap;
4 import gnu.trove.procedure.TObjectObjectProcedure;
6 import java.lang.reflect.Constructor;
7 import java.lang.reflect.Field;
8 import java.lang.reflect.Method;
9 import java.lang.reflect.Modifier;
10 import java.util.ArrayList;
12 import org.simantics.scl.compiler.types.Type;
13 import org.simantics.scl.compiler.types.Types;
14 import org.simantics.scl.compiler.types.exceptions.SCLTypeParseException;
15 import org.simantics.scl.compiler.types.util.ITypeEnvironment;
16 import org.simantics.scl.reflection.MinimalTypeBindingScheme;
17 import org.simantics.scl.reflection.ReflectionUtils;
18 import org.simantics.scl.reflection.TypeBindingScheme;
19 import org.simantics.scl.reflection.TypeNotFoundException;
20 import org.simantics.scl.reflection.TypedValue;
21 import org.simantics.scl.reflection.ValueNotFoundException;
22 import org.simantics.scl.reflection.annotations.SCLType;
23 import org.simantics.scl.reflection.annotations.SCLValue;
24 import org.simantics.scl.reflection.functions.ClassMethodFunction;
25 import org.simantics.scl.reflection.functions.ClassMethodFunction3;
26 import org.simantics.scl.reflection.functions.ConstructorFunction;
27 import org.simantics.scl.reflection.functions.FieldAccessorFunction;
28 import org.simantics.scl.reflection.functions.InstanceMethodFunction;
29 import org.simantics.scl.reflection.internal.Activator;
30 import org.simantics.scl.reflection.internal.typeRegistry.TypeRegistry;
32 public class Namespace {
35 ArrayList<Entry> classes = new ArrayList<Entry>();
36 ArrayList<ExternalClass> externalClasses =
37 new ArrayList<ExternalClass>();
38 ArrayList<ExternalMethod> externalMethods =
39 new ArrayList<ExternalMethod>();
40 volatile THashMap<String, Class<?>> types;
41 volatile THashMap<String, TypedValue> values;
43 public Namespace(String namespace, ImportSeq importSeq) {
44 this.namespace = namespace;
45 this.importSeq = importSeq;
48 public void addClass(Entry e) {
52 public void addExternalMethod(ExternalMethod e) {
53 externalMethods.add(e);
56 public void addExternalClass(ExternalClass e) {
57 externalClasses.add(e);
60 public Class<?> getClass(String name) throws TypeNotFoundException {
64 } catch (Exception e) {
65 throw new TypeNotFoundException(e);
68 Class<?> type = types.get(name);
70 throw new TypeNotFoundException("Didn't find type " + name + ".");
74 public TypedValue getValue(String name) throws ValueNotFoundException {
78 } catch (Exception e) {
80 throw new ValueNotFoundException(e);
83 TypedValue value = values.get(name);
85 throw new ValueNotFoundException("Didn't find value " + name + ".");
89 ITypeEnvironment typeEnvironment = new ITypeEnvironment() {
92 public Type resolve(String namespace, String name) {
93 if(namespace == null) {
94 if(TypeRegistry.isBuiltin(name))
95 namespace = Types.BUILTIN;
96 else if(types.contains(name))
97 namespace = Namespace.this.namespace;
102 for(ImportSeq cur = importSeq;cur != null;cur = cur.parent) {
103 if(namespace.equals(cur.localName)) {
104 namespace = cur.path;
109 return Types.con(namespace, name);
114 private Type parseType(String typeText) throws SCLTypeParseException {
115 return Types.closure(Types.parseType(typeEnvironment, typeText));
118 private synchronized void initializeTypes() {
120 types = new THashMap<String, Class<?>>();
122 for(Entry entry : classes) {
123 Class<?> clazz = entry.loadClass();
125 Activator.logError("Didn't find class " + entry.name + ".");
129 SCLType sclType = clazz.getAnnotation(SCLType.class);
130 if(sclType != null) {
131 String name = sclType.name();
133 name = clazz.getSimpleName();
134 types.put(name, clazz);
138 for(ExternalClass entry : externalClasses) {
139 Class<?> clazz = entry.loadClass();
141 Activator.logError("Didn't find class " + entry.className + ".");
145 String name = entry.alternativeName;
147 name = clazz.getSimpleName();
148 types.put(name, clazz);
153 private void handleMethod(TypeBindingScheme scheme, Class<?> clazz, Method method) {
154 SCLValue sclValue = method.getAnnotation(SCLValue.class);
155 if(sclValue != null) {
156 String name = sclValue.name();
158 name = method.getName();
161 type = parseType(sclValue.type());
162 } catch (SCLTypeParseException e) {
163 Activator.logError("Method " + method.getName() + " in class " +
164 clazz.getCanonicalName() + " has invalid type declaration.", e
169 if(ReflectionUtils.isCompatible(scheme, type, method)) {
171 if(Modifier.isStatic(method.getModifiers())) {
172 int arity = method.getParameterTypes().length;
174 value = new ClassMethodFunction3(method);
176 value = new ClassMethodFunction(method);
179 value = new InstanceMethodFunction(method);
180 values.put(name, new TypedValue(type, value));
183 Activator.logError("Method " + method.getName() + " in class " +
184 clazz.getCanonicalName() + " has incompatible SCL type in the SCLValue annotation."
186 ReflectionUtils.isCompatible(scheme, type, method);
188 } catch (TypeNotFoundException e) {
189 Activator.logError("Couldn't find all types in the type declaration of method " + method.getName() + " in class " +
190 clazz.getCanonicalName() + "."
196 private void handleConstructor(TypeBindingScheme scheme, Class<?> clazz, Constructor<?> constr) {
197 SCLValue sclValue = constr.getAnnotation(SCLValue.class);
198 if(sclValue != null) {
199 String name = sclValue.name();
201 name = constr.getDeclaringClass().getSimpleName();
204 type = parseType(sclValue.type());
205 } catch (SCLTypeParseException e) {
206 Activator.logError("Constructor in " +
207 clazz.getCanonicalName() + " has invalid type declaration.", e
212 if(ReflectionUtils.isCompatible(scheme, type, constr)) {
213 Object value = new ConstructorFunction(constr);
214 values.put(name, new TypedValue(type, value));
217 Activator.logError("Constructor of " +
218 clazz.getCanonicalName() + " has incompatible SCL type in the SCLValue annotation."
221 } catch (TypeNotFoundException e) {
222 Activator.logError("Couldn't find all types in the type declaration of constructor in " +
223 clazz.getCanonicalName() + "."
229 private void handleField(TypeBindingScheme scheme, Class<?> clazz, Field field) {
230 SCLValue sclValue = field.getAnnotation(SCLValue.class);
231 if(sclValue != null) {
232 String name = sclValue.name();
234 name = field.getName();
237 type = parseType(sclValue.type());
238 } catch (SCLTypeParseException e) {
239 Activator.logError("Field " + field.getName() + " in class " +
240 clazz.getCanonicalName() + " has invalid type declaration.", e
245 if(ReflectionUtils.isCompatible(scheme, type, field)) {
247 if(Modifier.isStatic(field.getModifiers()))
249 value = field.get(null);
250 } catch (IllegalArgumentException e) {
251 Activator.logError("Cannot read field " + field.getName() + " in class " +
252 clazz.getCanonicalName() + ".", e
255 } catch (IllegalAccessException e) {
256 Activator.logError("Cannot read field " + field.getName() + " in class " +
257 clazz.getCanonicalName() + ".", e
262 value = new FieldAccessorFunction(field);
263 values.put(name, new TypedValue(type, value));
266 Activator.logError("Field " + field.getName() + " in class " +
267 clazz.getCanonicalName() + " has incompatible SCL type in the SCLValue annotation."
270 } catch (TypeNotFoundException e) {
271 Activator.logError("Couldn't find all types in the type declaration of field " + field.getName() + " in class " +
272 clazz.getCanonicalName() + "."
278 private synchronized void initializeValues() {
281 TypeBindingScheme scheme = MinimalTypeBindingScheme.INSTANCE;
283 values = new THashMap<String, TypedValue>();
285 for(Entry entry : classes) {
286 Class<?> clazz = entry.loadClass();
289 Activator.logError("Didn't find class " + entry.name + ".");
293 for(Method method : clazz.getMethods()) {
294 handleMethod(scheme, clazz, method);
297 for(Constructor<?> constr : clazz.getConstructors()) {
298 handleConstructor(scheme, clazz, constr);
301 for(Field field : clazz.getFields()) {
302 handleField(scheme, clazz, field);
306 for(ExternalMethod entry : externalMethods) {
307 Class<?> clazz = entry.loadClass();
310 Activator.logError("Didn't find class " + entry.className + ".");
314 Method method = entry.getMethod(clazz);
317 Activator.logError("Didn't find method " + entry.methodName +
318 " in class " + entry.className + ".");
322 handleMethod(scheme, clazz, method);
327 public void print() {
328 for(Entry entry : classes) {
329 System.out.println(" " + entry.name + " (" + entry.bundle + ")");
333 } catch (Exception e) {
335 throw new RuntimeException(e);
337 types.forEachEntry(new TObjectObjectProcedure<String, Class<?>>() {
339 public boolean execute(String name, Class<?> clazz) {
340 System.out.println(" type " + name + " = " + clazz.getCanonicalName());
346 } catch (Exception e) {
348 throw new RuntimeException(e);
350 values.forEachEntry(new TObjectObjectProcedure<String, TypedValue>() {
352 public boolean execute(String name, TypedValue value) {
353 System.out.println(" " + name + " :: " + value.getType());