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

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

HIGHLIGHTS:

CHANGELOG:
Make ProcedureParam? hold only ValueParams?.

Use id instead of names when naming gui components internally.

Basic procedure calling in GUI.

The actual procedure call is currently only backed
by the ObjectInstance?.

Add UnimplementedException?.

Improve naming of various gui elements.

Allow easy navigating in FEST Swing testing.

Add optional explicit order attribute to FramsClassAnnotation?.

That's because java reflection does return declared members
in any specific order. That ordering is needed only for
classes that have no representation in framsticks and need
a deterministic ordering of params.

Add ControlOwner? interface.

Add test for procedure calling in Browser.

First version of ParamAnnotation? for procedures.

Development of ProcedureParam?.

Add draft version of ProcedureParam? implementation in ReflectionAccess?.

Allow viewing FramsClasses? in gui Browser.

Extract ResourceBuilder? from ModelBuilder?.

Remove internalId from Param.

It was currently completely not utilised. Whether it is still needed
after introduction of ParamAnnotation? is arguable.

Add remaining param attributes to ParamAnnotation?.

Change AutoBuilder? semantics.

AutoBuilder? returns list of objects that are to be appended
with methods @AutoAppendAnnotation?.

This allows to omit explicit addition of ModelPackage? to instance
if the instance uses ModelBuilder? (registration of ModelPackage? comes
from schema).

Fix params ordering problem in auto created FramsClasses?.

Improve ObjectInstance?.

Several fixes to ModelBuilder?.

Improve test for ObjectInstance? in Browser.

Make initialization of robot static.

With robot recreated for second browser test, the test hanged
deep in AWT.

Add base convenience base test for Browser tests.

More tests to ObjectInstance?.

Rename Dispatcher.invokeLater() to dispatch().

Add assertDispatch.

It allows assertions in other threads, than TestNGInvoker.
Assertions are gathered after each method invocation and rethrown.

Use timeOut annotation attribute for tests involving some waiting.

Remove firstTask method (merge with joinableStart).

Clean up leftovers.

Remove unused FavouritesXMLFactory (the reading part is already
completely done with generic XmlLoader?, and writing part will be done
based on the same approach if needed).
Move UserFavourite? to the com.framsticks.gui.configuration package.

Remove GenotypeBrowser? as to specific.

This functionality will be available in ObjectInstance?.

Add interface ParamsPackage?.

Package containing registration of Java classes meant to use with
ReflectionAccess? may be in Instance using configuration.

Minor changes.

Make Group immutable.

Add AutoBuilder? interface extending Builder - only those would
be used to automatically build from XML.

Fix groups in FramsClass?.

Minor naming cleanup in Registry.

Add ModelComponent? interface.

All class creating the Model are implementing that interface.

Extract Model.build into ModelBuilder?.

ModelBuilder? will be compatible with other builders
and allow using it from configuration.

Fix NeuroConnection?.

Add synchronous get operation for dispatchers.

Rename JoinableMonitor? to Monitor.

Add ObjectInstance?.

This class is mainly for demonstration
and testing purposes.

Improve FramsServer? runner.

  • improve ExternalProcess? runner,
  • runner can kill the server but also react properly, when the server exists on it's own,
  • set default path to search for framsticks server installation,
  • add LoggingOutputListener?.
File size: 8.7 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.Arrays;
13import java.util.Collection;
14import java.util.Collections;
15import java.util.Comparator;
16import java.util.HashMap;
17import java.util.LinkedList;
18import java.util.List;
19import java.util.Map;
20
21import com.framsticks.params.annotations.FramsClassAnnotation;
22import com.framsticks.params.annotations.ParamAnnotation;
23import com.framsticks.params.types.ProcedureParam;
24
25public class ParamCandidate {
26
27        public class OneTime<T> {
28                protected final String name;
29                T value;
30
31                /**
32                 * @param name
33                 */
34                public OneTime(String name) {
35                        this.name = name;
36                }
37
38                final void set(T value) {
39                        if (this.value == null) {
40                                this.value = value;
41                                return;
42                        }
43                        if (!this.value.equals(value)) {
44                                throw new ConstructionException().msg("already set")
45                                        .arg("name", name)
46                                        .arg("in", ParamCandidate.this)
47                                        .arg("already", this.value)
48                                        .arg("now", value);
49                        }
50                }
51
52                public final T get() {
53                        return value;
54                }
55
56                public final boolean has() {
57                        return value != null;
58                }
59
60                @Override
61                public String toString() {
62                        return value == null ? "<null>" : value.toString();
63                }
64
65
66        }
67
68        protected final String id;
69        protected final OneTime<String> name = new OneTime<>("name");
70        protected final OneTime<Type> type = new OneTime<>("type");
71        protected final OneTime<Field> field = new OneTime<>("field");
72        protected final OneTime<Method> setter = new OneTime<>("setter");
73        protected final OneTime<Method> getter = new OneTime<>("getter");
74        protected final OneTime<Method> caller = new OneTime<>("caller");
75
76        protected final List<ParamAnnotation> annotations = new LinkedList<>();
77
78        /**
79         * @param id
80         */
81        public ParamCandidate(String id) {
82                this.id = id;
83        }
84
85        /**
86         * @return the id
87         */
88        public String getId() {
89                return id;
90        }
91
92        /**
93         * @return the name
94         */
95        public String getName() {
96                return name.get();
97        }
98
99        /**
100         * @return the type
101         */
102        public Type getType() {
103                return type.get();
104        }
105
106        public Class<?> getRawType() {
107                return getRawClass(type.get());
108        }
109
110        void setType(Type type) {
111                this.type.set(type);
112        }
113
114
115        /**
116         * @return the field
117         */
118        public Field getField() {
119                return field.get();
120        }
121
122        /**
123         * @return the setter
124         */
125        public Method getSetter() {
126                return setter.get();
127        }
128
129        /**
130         * @return the getter
131         */
132        public Method getGetter() {
133                return getter.get();
134        }
135
136        /**
137         * @return the getter
138         */
139        public Method getCaller() {
140                return caller.get();
141        }
142
143        /**
144         * @return the annotations
145         */
146        public List<ParamAnnotation> getAnnotations() {
147                return Collections.unmodifiableList(annotations);
148        }
149
150        void validate() throws ConstructionException {
151                try {
152                        if (caller.has()) {
153                                if (!isPublic(caller)) {
154                                        throw new ConstructionException().msg("method is not public");
155                                }
156                                if (getter.has() || setter.has()) {
157                                        throw new ConstructionException().msg("getter or setter coexist with caller");
158                                }
159                                return;
160                        }
161                        if (isPublic(field)) {
162                                if (getter.has()) {
163                                        throw new ConstructionException().msg("getter and public field coexist");
164                                }
165                                return;
166                        }
167                        if (isPublic(field)) {
168                                if (setter.has()) {
169                                        throw new ConstructionException().msg("setter and field coexist");
170                                }
171                        }
172
173                        if (!getter.has() && !field.has()) {
174                                throw new ConstructionException().msg("missing getter or field");
175                        }
176                } catch (ConstructionException e) {
177                        throw e.arg("in", this);
178                }
179        }
180
181        boolean isFinal() {
182                if (caller.has()) {
183                        return false;
184                }
185                if (Collection.class.isAssignableFrom(getRawType())) {
186                        return false;
187                }
188                if (setter.has()) {
189                        return false;
190                }
191                if (field.has()) {
192                        return Modifier.isFinal(field.get().getModifiers());
193                }
194                return true;
195        }
196
197        boolean isReadOnly() {
198                if (caller.has()) {
199                        return false;
200                }
201                if (Collection.class.isAssignableFrom(getRawType())) {
202                        return false;
203                }
204                if (isPublic(setter)) {
205                        return false;
206                }
207                if (isPublic(field)) {
208                        return Modifier.isFinal(field.get().getModifiers());
209                }
210                return true;
211        }
212
213        void add(ParamAnnotation paramAnnotation, Member member, String name) {
214                this.name.set(name);
215                annotations.add(paramAnnotation);
216                if (member instanceof Field) {
217                        field.set((Field) member);
218                        setType(field.get().getGenericType());
219                        return;
220                }
221                if (member instanceof Method) {
222                        Method m = (Method) member;
223                        if (!paramAnnotation.paramType().equals(Param.class)) {
224                                if (paramAnnotation.paramType().equals(ProcedureParam.class)) {
225                                        caller.set(m);
226                                        return;
227                                }
228                                throw new ConstructionException().msg("explicit set of paramType different than ProcedureParam is not yet supported").arg("name", name).arg("method", m).arg("in", this);
229                        }
230                        Type[] ps = m.getGenericParameterTypes();
231                        if (ps.length == 0) {
232                                getter.set(m);
233                                setType(m.getGenericReturnType());
234                                return;
235                        }
236                        if (ps.length == 1) {
237                                setter.set(m);
238                                setType(ps[0]);
239                                return;
240                        }
241                        throw new ConstructionException().msg("invalid number of arguments").arg("method", m).arg("in", this);
242                }
243                throw new ConstructionException().msg("invalid kind of member").arg("member", member).arg("in", this);
244        }
245
246        public boolean isPrimitive() {
247                return getRawType().isPrimitive();
248        }
249
250        public int getFlags() {
251                int f = 0;
252                if (isReadOnly()) {
253                        f |= Flags.READONLY;
254                }
255                return f;
256        }
257
258        @Override
259        public String toString() {
260                return id + "(" + type.toString() + ")";
261        }
262
263        public static boolean isPublic(Member member) {
264                return Modifier.isPublic(member.getModifiers());
265        }
266
267        public static boolean isPublic(OneTime<? extends Member> v) {
268                return v.has() ? isPublic(v.get()) : false;
269        }
270
271        public static <M extends Member & AnnotatedElement> void filterParamsCandidates(Set set, M[] members) {
272                for (M m : members) {
273                        ParamAnnotation pa = m.getAnnotation(ParamAnnotation.class);
274                        if (pa == null) {
275                                continue;
276                        }
277                        String id = FramsClassBuilder.getId(pa, m);
278                        ParamCandidate pc = null;
279                        if (set.getCandidates().containsKey(id)) {
280                                pc = set.getCandidates().get(id);
281                        } else {
282                                pc = new ParamCandidate(id);
283                                set.getCandidates().put(id, pc);
284                                set.getOrder().add(pc);
285                        }
286                        pc.add(pa, m, FramsClassBuilder.getName(pa, m));
287                }
288        }
289
290        public static class Set {
291                protected final Map<String, ParamCandidate> candidates;
292                protected final List<ParamCandidate> order;
293
294                /**
295                 * @param candidates
296                 * @param order
297                 */
298                public Set(Map<String, ParamCandidate> candidates, List<ParamCandidate> order) {
299                        this.candidates = candidates;
300                        this.order = order;
301                }
302
303                /**
304                 * @return the candidates
305                 */
306                public Map<String, ParamCandidate> getCandidates() {
307                        return candidates;
308                }
309
310                /**
311                 * @return the order
312                 */
313                public List<ParamCandidate> getOrder() {
314                        return order;
315                }
316        }
317
318        public static Set getAllCandidates(Class<?> javaClass) throws ConstructionException {
319
320                List<Class<?>> javaClasses = new LinkedList<>();
321                while (javaClass != null) {
322                        javaClasses.add(0, javaClass);
323                        javaClass = javaClass.getSuperclass();
324                }
325
326                Set resultSet = new Set(new HashMap<String, ParamCandidate>(), new LinkedList<ParamCandidate>());
327
328                for (Class<?> j : javaClasses) {
329                        Set set = new Set(resultSet.getCandidates(), new LinkedList<ParamCandidate>());
330                        filterParamsCandidates(set, j.getDeclaredFields());
331                        filterParamsCandidates(set, j.getDeclaredMethods());
332
333                        FramsClassAnnotation fa = j.getAnnotation(FramsClassAnnotation.class);
334                        if (fa != null) {
335                                final List<String> order = Arrays.asList(fa.order());
336                                Collections.sort(set.getOrder(), new Comparator<ParamCandidate>() {
337                                        @Override
338                                        public int compare(ParamCandidate pc0, ParamCandidate pc1) {
339                                                int u0 = order.indexOf(pc0.getId());
340                                                int u1 = order.indexOf(pc1.getId());
341                                                if (u0 == -1 || u1 == -1) {
342                                                        return 0;
343                                                }
344                                                return u0 - u1;
345                                        }
346                                });
347                        }
348                        resultSet.getOrder().addAll(0, set.getOrder());
349                }
350
351                for (ParamCandidate pc : resultSet.getOrder()) {
352                        pc.validate();
353                }
354
355                return resultSet;
356        }
357
358        public static Class<?> getRawClass(final Type type) {
359                if (type == null) {
360                        throw new IllegalArgumentException();
361                }
362                if (Class.class.isInstance(type)) {
363                        return Class.class.cast(type);
364                }
365                if (ParameterizedType.class.isInstance(type)) {
366                        final ParameterizedType parameterizedType = ParameterizedType.class.cast(type);
367                        return getRawClass(parameterizedType.getRawType());
368                } else if (GenericArrayType.class.isInstance(type)) {
369                        GenericArrayType genericArrayType = GenericArrayType.class.cast(type);
370                        Class<?> c = getRawClass(genericArrayType.getGenericComponentType());
371                        return Array.newInstance(c, 0).getClass();
372                } else {
373                        return null;
374                }
375        }
376
377};
Note: See TracBrowser for help on using the repository browser.