source: java/main/src/main/java/com/framsticks/params/ParamCandidate.java @ 107

Last change on this file since 107 was 107, checked in by psniegowski, 11 years ago

HIGHLIGHTS:

  • add SimultorProviders? hierarchy
  • start Framsticks server over SSH
  • FJF compatible with Framsticks 4.0rc3
  • reading and writing of standard.expt
  • a proof-of-concept implementation of StandardExperiment?

CHANGELOG:
Optionally return FreeAccess? from registry.

Add SimulatorRange?.

StandardExperiment? with genotypes circulation.

Automate registration around StandardState?.

More improvements to StandardExperiment?.

Skeleton version of StandardExperiment?.

Test saving of StandardState?.

Standard experiment state is being loaded.

More development towards StandardState? reading.

Work on reading standard experiment state.

Add classes for standard experiment.

Update example standard.expt

Add FreeAccess? and FreeObject?.

Made compatible with version 4.0rc3

Change deserialization policy.

Improve SSH support.

Working running simulator over SSH.

Fix joining bug in Experiment.

Working version of SimulatorRunner?.

Add more SimulatorProviders?.

Working PrimeExperimentTest? with 4.0rc3

Add references to deserialization.

Add OpaqueObject? and it's serialization.

Add deserialization of dictionaries.

Partial implementation of deserialization.

Add more tests for deserialization.

Prepare tests for deserialization.

Add proper result to prime experiment test.

Minor fixes to simulators providers.

Draft version of SimulatorProvider?.

Add SimulatorProvider? interface.

File size: 15.5 KB
RevLine 
[86]1package com.framsticks.params;
2
3import java.lang.reflect.AnnotatedElement;
4import java.lang.reflect.Array;
5import java.lang.reflect.Field;
6import java.lang.reflect.GenericArrayType;
7import java.lang.reflect.Member;
8import java.lang.reflect.Method;
9import java.lang.reflect.Modifier;
10import java.lang.reflect.ParameterizedType;
11import java.lang.reflect.Type;
[101]12import java.util.ArrayList;
[90]13import java.util.Arrays;
[86]14import java.util.Collection;
[90]15import java.util.Collections;
16import java.util.Comparator;
[86]17import java.util.HashMap;
[101]18import java.util.HashSet;
19import java.util.IdentityHashMap;
[90]20import java.util.LinkedList;
21import java.util.List;
[86]22import java.util.Map;
23
[90]24import com.framsticks.params.annotations.FramsClassAnnotation;
[86]25import com.framsticks.params.annotations.ParamAnnotation;
[90]26import com.framsticks.params.types.ProcedureParam;
[102]27// import com.framsticks.util.FramsticksException;
[86]28
29public class ParamCandidate {
30
31        public class OneTime<T> {
32                protected final String name;
33                T value;
34
35                /**
36                 * @param name
37                 */
38                public OneTime(String name) {
39                        this.name = name;
40                }
41
42                final void set(T value) {
43                        if (this.value == null) {
44                                this.value = value;
45                                return;
46                        }
47                        if (!this.value.equals(value)) {
48                                throw new ConstructionException().msg("already set")
49                                        .arg("name", name)
50                                        .arg("in", ParamCandidate.this)
51                                        .arg("already", this.value)
52                                        .arg("now", value);
53                        }
54                }
55
56                public final T get() {
57                        return value;
58                }
59
60                public final boolean has() {
61                        return value != null;
62                }
63
64                @Override
65                public String toString() {
66                        return value == null ? "<null>" : value.toString();
67                }
68
69
70        }
71
72        protected final String id;
73        protected final OneTime<String> name = new OneTime<>("name");
74        protected final OneTime<Type> type = new OneTime<>("type");
75        protected final OneTime<Field> field = new OneTime<>("field");
76        protected final OneTime<Method> setter = new OneTime<>("setter");
77        protected final OneTime<Method> getter = new OneTime<>("getter");
[90]78        protected final OneTime<Method> caller = new OneTime<>("caller");
[99]79        protected final OneTime<Method> adder = new OneTime<>("adder");
80        protected final OneTime<Method> remover = new OneTime<>("remover");
[105]81        protected final OneTime<Class<? extends Param>> paramType = new OneTime<>("paramType");
[107]82        protected final OneTime<String> stringType = new OneTime<>("stringType");
[105]83
[101]84        protected int flags = 0;
[86]85
[90]86        protected final List<ParamAnnotation> annotations = new LinkedList<>();
87
[86]88        /**
89         * @param id
90         */
91        public ParamCandidate(String id) {
92                this.id = id;
93        }
94
95        /**
96         * @return the id
97         */
98        public String getId() {
99                return id;
100        }
101
102        /**
103         * @return the name
104         */
105        public String getName() {
106                return name.get();
107        }
108
109        /**
110         * @return the type
111         */
112        public Type getType() {
113                return type.get();
114        }
115
116        public Class<?> getRawType() {
117                return getRawClass(type.get());
118        }
119
120        void setType(Type type) {
121                this.type.set(type);
122        }
123
124
125        /**
126         * @return the field
127         */
128        public Field getField() {
129                return field.get();
130        }
131
132        /**
133         * @return the setter
134         */
135        public Method getSetter() {
136                return setter.get();
137        }
138
139        /**
140         * @return the getter
141         */
142        public Method getGetter() {
143                return getter.get();
144        }
145
[90]146        /**
147         * @return the getter
148         */
149        public Method getCaller() {
150                return caller.get();
151        }
152
153        /**
[99]154         * @return the getter
155         */
156        public Method getAdder() {
157                return adder.get();
158        }
159
160        /**
161         * @return the getter
162         */
163        public Method getRemover() {
164                return remover.get();
165        }
166
167        /**
[90]168         * @return the annotations
169         */
170        public List<ParamAnnotation> getAnnotations() {
171                return Collections.unmodifiableList(annotations);
172        }
173
[101]174        protected final java.util.Set<Class<?>> dependantClasses = new HashSet<>();
175
176        // public void addDependantClass(Class<?> javaClass) {
177        //      dependantClasses.add(javaClass);
178        // }
179
180        /**
181         * @return the dependantClasses
182         */
183        public java.util.Set<Class<?>> getDependantClasses() {
184                return Collections.unmodifiableSet(dependantClasses);
185        }
186
[86]187        void validate() throws ConstructionException {
188                try {
[99]189                        if (adder.has() != remover.has()) {
190                                throw new ConstructionException().msg("only one of event manipulator methods is defined");
191                        }
192                        if (adder.has() && remover.has()) {
193                                return;
194                        }
[90]195                        if (caller.has()) {
196                                if (!isPublic(caller)) {
197                                        throw new ConstructionException().msg("method is not public");
198                                }
199                                if (getter.has() || setter.has()) {
200                                        throw new ConstructionException().msg("getter or setter coexist with caller");
201                                }
202                                return;
203                        }
[86]204                        if (isPublic(field)) {
205                                if (getter.has()) {
206                                        throw new ConstructionException().msg("getter and public field coexist");
207                                }
208                                return;
209                        }
[88]210                        if (isPublic(field)) {
[86]211                                if (setter.has()) {
212                                        throw new ConstructionException().msg("setter and field coexist");
213                                }
214                        }
215
[88]216                        if (!getter.has() && !field.has()) {
217                                throw new ConstructionException().msg("missing getter or field");
[86]218                        }
[99]219                        if (getter.has() || field.has() || setter.has()) {
220                                if (type.get().equals(Void.TYPE)) {
221                                        throw new ConstructionException().msg("type of field is void");
222                                }
223                        }
[86]224                } catch (ConstructionException e) {
225                        throw e.arg("in", this);
226                }
227        }
228
229        boolean isFinal() {
[90]230                if (caller.has()) {
231                        return false;
232                }
[99]233                if (adder.has() || remover.has()) {
234                        return false;
235                }
[100]236                if (field.has()) {
237                        return Modifier.isFinal(field.get().getModifiers());
[86]238                }
239                if (setter.has()) {
240                        return false;
241                }
[100]242                if (Collection.class.isAssignableFrom(getRawType())) {
243                        return false;
[86]244                }
245                return true;
246        }
247
248        boolean isReadOnly() {
[90]249                if (caller.has()) {
250                        return false;
251                }
[99]252                if (adder.has() || remover.has()) {
253                        return false;
254                }
[86]255                if (Collection.class.isAssignableFrom(getRawType())) {
256                        return false;
257                }
258                if (isPublic(setter)) {
259                        return false;
260                }
261                if (isPublic(field)) {
262                        return Modifier.isFinal(field.get().getModifiers());
263                }
264                return true;
265        }
266
[105]267        // public static <T extends Param> boolean isParamAnnorationOfTypeOrUnspecified(ParamAnnotation paramAnnotation, Class<T> paramType) {
268        //      return paramAnnotation.paramType().equals(Param.class) || paramAnnotation.paramType().equals(paramType);
269        // }
270
271        // public static <T extends Param> boolean isParamAnnorationOfType(ParamAnnotation paramAnnotation, Class<T> paramType) {
272        //      return paramAnnotation.paramType().equals(paramType);
273        // }
274
[90]275        void add(ParamAnnotation paramAnnotation, Member member, String name) {
[86]276                this.name.set(name);
[90]277                annotations.add(paramAnnotation);
[101]278                flags |= paramAnnotation.flags();
[105]279                if (!paramAnnotation.paramType().equals(Param.class)) {
280                        paramType.set(paramAnnotation.paramType());
281                }
[107]282                if (!"".equals(paramAnnotation.stringType())) {
283                        stringType.set(paramAnnotation.stringType());
284                }
[86]285                if (member instanceof Field) {
[90]286                        field.set((Field) member);
[86]287                        setType(field.get().getGenericType());
288                        return;
289                }
290                if (member instanceof Method) {
291                        Method m = (Method) member;
[105]292                        if (paramAnnotation.paramType().equals(ProcedureParam.class)) {
293                                caller.set(m);
294                                return;
[90]295                        }
[86]296                        Type[] ps = m.getGenericParameterTypes();
[99]297                        Class<?>[] pts = m.getParameterTypes();
[86]298                        if (ps.length == 0) {
[99]299                                if (m.getReturnType().equals(Void.TYPE)) {
300                                        throw new ConstructionException().msg("failed to add getter of void return type");
301                                }
[86]302                                getter.set(m);
303                                setType(m.getGenericReturnType());
304                                return;
305                        }
306                        if (ps.length == 1) {
[99]307                                if (pts[0].equals(EventListener.class)) {
308                                        if (member.getName().startsWith("add")) {
309                                                adder.set(m);
310                                                setType(ps[0]);
311                                                return;
312                                        }
313                                        if (member.getName().startsWith("remove")) {
314                                                remover.set(m);
315                                                setType(ps[0]);
316                                                return;
317                                        }
318                                        throw new ConstructionException().msg("invalid name of event manipulator").arg("method", m).arg("in", this);
319                                }
[86]320                                setter.set(m);
321                                setType(ps[0]);
322                                return;
323                        }
324                        throw new ConstructionException().msg("invalid number of arguments").arg("method", m).arg("in", this);
325                }
326                throw new ConstructionException().msg("invalid kind of member").arg("member", member).arg("in", this);
327        }
328
329        public boolean isPrimitive() {
330                return getRawType().isPrimitive();
331        }
332
333        public int getFlags() {
[101]334                int f = flags;
[86]335                if (isReadOnly()) {
[99]336                        f |= ParamFlags.READONLY;
[86]337                }
338                return f;
339        }
340
341        @Override
342        public String toString() {
[88]343                return id + "(" + type.toString() + ")";
[86]344        }
345
346        public static boolean isPublic(Member member) {
347                return Modifier.isPublic(member.getModifiers());
348        }
349
350        public static boolean isPublic(OneTime<? extends Member> v) {
351                return v.has() ? isPublic(v.get()) : false;
352        }
353
[90]354        public static <M extends Member & AnnotatedElement> void filterParamsCandidates(Set set, M[] members) {
[86]355                for (M m : members) {
356                        ParamAnnotation pa = m.getAnnotation(ParamAnnotation.class);
357                        if (pa == null) {
358                                continue;
359                        }
360                        String id = FramsClassBuilder.getId(pa, m);
361                        ParamCandidate pc = null;
[90]362                        if (set.getCandidates().containsKey(id)) {
363                                pc = set.getCandidates().get(id);
[86]364                        } else {
365                                pc = new ParamCandidate(id);
[90]366                                set.getCandidates().put(id, pc);
367                                set.getOrder().add(pc);
[86]368                        }
[90]369                        pc.add(pa, m, FramsClassBuilder.getName(pa, m));
370                }
371        }
[86]372
[90]373        public static class Set {
374                protected final Map<String, ParamCandidate> candidates;
375                protected final List<ParamCandidate> order;
[101]376                protected final java.util.Set<Class<?>> dependantClasses = new HashSet<>();
[107]377                protected final java.util.Set<String> dependantClassesFromInfo = new HashSet<>();
[90]378
379                /**
380                 * @param candidates
381                 * @param order
382                 */
383                public Set(Map<String, ParamCandidate> candidates, List<ParamCandidate> order) {
384                        this.candidates = candidates;
385                        this.order = order;
[86]386                }
[90]387
388                /**
389                 * @return the candidates
390                 */
391                public Map<String, ParamCandidate> getCandidates() {
392                        return candidates;
393                }
394
395                /**
396                 * @return the order
397                 */
398                public List<ParamCandidate> getOrder() {
399                        return order;
400                }
[101]401
402                public java.util.Set<Class<?>> getDependentClasses() {
403                        return dependantClasses;
404                }
[107]405
406                public java.util.Set<String> getDependentClassesFromInfo() {
407                        return dependantClassesFromInfo;
408                }
[86]409        }
410
[101]411        protected static final Map<Class<?>, Set> setsCache = Collections.synchronizedMap(new IdentityHashMap<Class<?>, Set>());
412
[105]413        public static Set getAllCandidates(final Class<?> javaClass) throws ConstructionException {
[101]414                Set result = setsCache.get(javaClass);
415                if (result != null) {
416                        return result;
417                }
[86]418
[90]419                List<Class<?>> javaClasses = new LinkedList<>();
[105]420                Class<?> jc = javaClass;
421                while (jc != null) {
422                        javaClasses.add(0, jc);
423                        jc = jc.getSuperclass();
[86]424                }
425
[101]426                result = new Set(new HashMap<String, ParamCandidate>(), new LinkedList<ParamCandidate>());
[90]427
428                for (Class<?> j : javaClasses) {
[101]429                        Set set = new Set(result.getCandidates(), new LinkedList<ParamCandidate>());
430
[90]431                        filterParamsCandidates(set, j.getDeclaredFields());
432                        filterParamsCandidates(set, j.getDeclaredMethods());
433
434                        FramsClassAnnotation fa = j.getAnnotation(FramsClassAnnotation.class);
435                        if (fa != null) {
[101]436
437                                if (j != javaClass) {
438                                        result.dependantClasses.add(j);
439                                }
440                                for (Class<?> r : fa.register()) {
441                                        result.dependantClasses.add(r);
442                                }
[107]443                                for (String i : fa.registerFromInfo()) {
444                                        result.dependantClassesFromInfo.add(i);
445                                }
[101]446
[90]447                                final List<String> order = Arrays.asList(fa.order());
448                                Collections.sort(set.getOrder(), new Comparator<ParamCandidate>() {
449                                        @Override
450                                        public int compare(ParamCandidate pc0, ParamCandidate pc1) {
451                                                int u0 = order.indexOf(pc0.getId());
452                                                int u1 = order.indexOf(pc1.getId());
453                                                if (u0 == -1 || u1 == -1) {
454                                                        return 0;
455                                                }
456                                                return u0 - u1;
457                                        }
458                                });
459                        }
[101]460                        result.getOrder().addAll(0, set.getOrder());
[90]461                }
462
[101]463                for (ParamCandidate pc : result.getOrder()) {
[86]464                        pc.validate();
[101]465                        pc.induceParamType(Param.build());
466                        result.dependantClasses.addAll(pc.getDependantClasses());
[86]467                }
468
[101]469                setsCache.put(javaClass, result);
470
471                return result;
[86]472        }
473
474        public static Class<?> getRawClass(final Type type) {
[90]475                if (type == null) {
476                        throw new IllegalArgumentException();
477                }
[86]478                if (Class.class.isInstance(type)) {
479                        return Class.class.cast(type);
480                }
481                if (ParameterizedType.class.isInstance(type)) {
482                        final ParameterizedType parameterizedType = ParameterizedType.class.cast(type);
483                        return getRawClass(parameterizedType.getRawType());
484                } else if (GenericArrayType.class.isInstance(type)) {
485                        GenericArrayType genericArrayType = GenericArrayType.class.cast(type);
486                        Class<?> c = getRawClass(genericArrayType.getGenericComponentType());
487                        return Array.newInstance(c, 0).getClass();
488                } else {
489                        return null;
490                }
491        }
492
[101]493        protected ParamBuilder induceParamType(ParamBuilder builder, Type type) {
494                // if (type.equals(Void.TYPE)) {
495                //      throw new ConstructionException().msg("void is not a valid type");
496                // }
497
[105]498
[101]499                if (type instanceof ParameterizedType) {
500                        ParameterizedType p = (ParameterizedType) type;
501                        Type rawType = p.getRawType();
502                        Type containedType = null;
503                        boolean map = false;
504                        StringBuilder b = new StringBuilder();
505                        if (rawType.equals(Map.class)) {
506                                containedType = p.getActualTypeArguments()[1];
507                                map = true;
508                                b.append("l");
509                        } else if (rawType.equals(List.class)) {
510                                containedType = p.getActualTypeArguments()[0];
511                                b.append("l");
512                        } else if (rawType.equals(EventListener.class)) {
513                                containedType = p.getActualTypeArguments()[0];
514                                b.append("e");
[102]515                        } else {
516                                return induceParamType(builder, rawType);
517                                // throw new FramsticksException().msg("unknown raw type").arg("raw type", rawType);
[101]518                        }
519                        if (!(containedType instanceof Class)) {
520                                return builder;
521                        }
522                        b.append(" ");
523
524                        Class<?> containedClass = (Class<?>) containedType;
525                        FramsClassAnnotation fca = containedClass.getAnnotation(FramsClassAnnotation.class);
526                        if (fca == null) {
527                                throw new ConstructionException().msg("the contained class is not annotated").arg("class", containedClass);
528                        }
529                        dependantClasses.add(containedClass);
530                        b.append(FramsClassBuilder.getName(fca, containedClass));
531                        if (map) {
532                                b.append(" uid");
533                        }
534
535                        builder.type(b.toString());
536                        return builder;
537                }
538
539                if (type instanceof Class) {
540
541                        Class<?> cl = (Class<?>) type;
542
[102]543                        // this is draft implementation of future support for enum
[101]544                        // if (cl.isEnum()) {
545                        //      Class<? extends Enum<?>> enumType = (Class<? extends Enum<?>>) cl;
546                        //      Enum<?>[] enums = enumType.getEnumConstants();
547                        //      StringBuilder b = new StringBuilder();
548
549                        //      b.append("d 0 ").append(enums.length - 1).append(" 0 ");
550                        //      for (Enum<?> e : enums) {
551                        //              b.append("~").append(e.name());
552                        //      }
553                        //      return b.toString();
554                        // }
555                        if (cl.equals(Integer.class) || cl.equals(int.class)) {
556                                builder.type("d");
557                                return builder;
558                        }
559                        if (cl.equals(String.class)) {
560                                builder.type("s");
561                                return builder;
562                        }
563                        if (cl.equals(Double.class) || cl.equals(double.class)) {
564                                builder.type("f");
565                                return builder;
566                        }
567                        if (cl.equals(Boolean.class) || cl.equals(boolean.class)) {
568                                builder.type( "d 0 1");
569                                return builder;
570                        }
571                        if (cl.equals(Object.class)) {
572                                builder.type("x");
573                                return builder;
574                        }
575
576
577                        // builder.type("o " + (cl).getCanonicalName());
578                        builder.type("o " + cl.getSimpleName());
579                        dependantClasses.add(cl);
580                        builder.fillStorageType(cl);
581                        return builder;
582                }
583
584                throw new ConstructionException().msg("failed to find framsticks for native type").arg("type", type);
585        }
586
587        public ParamBuilder induceParamType(ParamBuilder builder) {
[107]588
589                if (stringType.has()) {
590                        return builder.type(stringType.get());
591                }
592
[101]593                Method method = getCaller();
594                if (method == null) {
[105]595                        if (paramType.has()) {
596                                return builder.type(paramType.get());
597                        }
[101]598                        return induceParamType(builder, getType());
599                }
600
601                if (!method.getReturnType().equals(Void.TYPE)) {
602                        builder.resultType(induceParamType(Param.build(), method.getGenericReturnType()).finish(ValueParam.class));
603                }
604
605                List<ValueParam> arguments = new ArrayList<>();
606                int number = 0;
607                for (Type arg : method.getGenericParameterTypes()) {
608                        arguments.add(induceParamType(Param.build(), arg).idAndName("arg" + (number++)).finish(ValueParam.class));
609                }
610                builder.argumentsType(arguments);
611
612                return builder;
613        }
614
[86]615};
Note: See TracBrowser for help on using the repository browser.