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

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

HIGHLIGHTS:

for Joinables running

CHANGELOG:
Add WorkPackageLogic? and classes representing prime experiment state.

Add classes for PrimeExperiment? state.

Extract single netload routine in Simulator.

Working netload with dummy content in PrimeExperiment?.

More development with NetLoadSaveLogic? and PrimeExperiment?.

Improvement around prime.

Improve BufferedDispatcher?.isActive logic.

Add prime-all.xml configuration.

Manual connecting to existing simulators from GUI.

Guard in SimulatorConnector? against expdef mismatch.

Guard against empty target dispatcher in BufferedDispatcher?.

Make BufferedDispatcher? a Dispatcher (and Joinable).

Minor improvements.

Done StackedJoinable?, improve Experiment.

Develop StackedJoinable?.

Add StackedJoinable? utility joinables controller.

Add dependency on apache-commons-lang.

Add ready ListChange? on Simulators.

Improve hints in ListChange?.

Several improvements.

Found bug with dispatching in Experiment.

Minor improvements.

Fix bug with early finishing Server.

Many changes in Dispatching.

Fix bug with connection.

Do not obfuscate log with socket related exceptions.

Add SocketClosedException?.

Add SimulatorConnector?.

Work out conception of experiment composing of logics building blocks.

Rename SinkInterface? to Sink.

Move saving of Accesses into AccessOperations?.

Some improvements to Experiment.

Improve joinables.

Fix issue with joinables closing.

Add direct and managed consoles to popup menu.

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