source: java/main/src/main/java/com/framsticks/params/FramsClassBuilder.java @ 100

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

HIGHLIGHTS:

  • add <include/> to configuration
  • add side notes to tree
    • used to store arbitrary information alongside the tree structure
  • migrate to log4j2
    • supports lazy string evaluation of passed arguments
  • improve GUI tree
    • it stays in synchronization with actual state (even in high load test scenario)
  • improve panel management in GUI
  • make loading objects in GUI more lazy
  • offload parsing to connection receiver thread
    • info parsing
    • first step of objects parsing
  • fix connection parsing bug (eof in long values)
  • support zero-arguments procedure in table view

CHANGELOG:
Implement procedure calls from table view.

Refactorization around procedures in tables.

Add table editor for buttons.

Render buttons in the the list view.

Further improve Columns.

Add Column class for TableModel?.

Accept also non-arguments ProcedureParams? in tableView.

Increase maximal TextAreaControl? size.

Add tooltip to ProcedureControl?.

Fix bug of interpreting eofs in long values by connection reader.

Further rework connection parsing.

Simplify client connection processing.

Test ListChange? modification.

Test ListChange? events with java server.

Add TestChild?.

Fix bug with fast deregistering when connecting to running server.

Another minor refactorization in TreeOperations?.

Fix bug in SimpleAbstractAccess? loading routine.

Another minor improvement.

Minor change.

Make reading of List objects two-phase.

Another minor change.

Dispatch parsing into receiver thread.

Another step.

Enclose passing value in ObjectParam? case in closure.

Minor step.

Minor change on way to offload parsing.

Temporarily comment out single ValueParam? get.

It will be generalized to multi ValueParam?.

Process info in receiver thread.

Add DispatchingExceptionHandler?.

Make waits in browser test longer.

Use FETCHED_MARK.

It is honored in GUI, where it used to decide whether to get values

after user action.

It is set in standard algorithm for processing fetched values.

Add remove operation to side notes.

Make loading more lazy.

Improve loading policy.

On node choose load itself, on node expansion, load children.

Minor improvement.

Fix bug with panel interleaving.

Minor improvements.

Improve panel management.

More cleaning around panels.

Reorganize panels.

Further improve tree.

Fix bug in TreeModel?.

Remove children from TreeNode?.

Implement TreeNode? hashCode and equals.

Make TreeNode? delegate equals and hashcode to internal reference.

Move listeners from TreeNode? to side notes.

Store path.textual as a side note.

Side note params instead of accesses for objects.

More refactorizations.

In TreeNode? bindAccess based on side notes.

Minor step.

Hide createAccess.

Rename AccessInterface? to Access.

Minor changes.

Several improvements in high load scenarios.

Change semantics of ArrayListAccess?.set(index, null);

It now removes the element, making list shorter
(it was set to null before).

Add path remove handler.

Handle exceptions in Connection.

Update .gitignore

Configure logging to file.

Move registration to TreeModel?.

Further refactorization.

Minor refactorization.

Minor improvements.

Use specialized event also for Modify action of ListChange?.

Use remove events.

Use the insertion events for tree.

Further improve tree refreshing.

Further improve reacting on events in GUI.

Fix problem with not adding objects on addition list change.

Migrate to log4j lazy String construction interface.

Migrate imports to log4j2.

Drop dependency on adapter to version 1.2.

Switch log4j implementation to log4j2.

Add dirty mark to the NodeAtFrame?.

Make selecting in AccessInterfaces? type safe.

Ignore containers size settings in Model and Genotype.

Use tree side notes to remember local changes and panels.

Add sideNotes to tree.

They will be used to store various accompanying information
right in the tree.

Use ReferenceIdentityMap? from apache in TreeNode?.

It suits the need perfectly (weak semantics on both key and value).

Make ArrayListParam? do not react size changes.

Guard in TableModel? before not yet loaded objects.

Add <include/> clause and AutoInjector?.

Extract common columns configuration to separate xml,
that can be included by other configurations.

File size: 9.7 KB
Line 
1package com.framsticks.params;
2
3import java.io.InputStream;
4import java.lang.reflect.Field;
5import java.lang.reflect.Member;
6import java.lang.reflect.Method;
7import java.lang.reflect.ParameterizedType;
8import java.lang.reflect.Type;
9import java.util.ArrayList;
10import java.util.Collections;
11import java.util.IdentityHashMap;
12import java.util.LinkedList;
13import java.util.List;
14import java.util.Map;
15
16import org.apache.logging.log4j.Logger;
17import org.apache.logging.log4j.LogManager;
18
19import com.framsticks.params.annotations.AutoAppendAnnotation;
20import com.framsticks.params.annotations.FramsClassAnnotation;
21import com.framsticks.params.annotations.ParamAnnotation;
22import com.framsticks.parsers.FileSource;
23import com.framsticks.parsers.Loaders;
24import com.framsticks.util.Builder;
25import com.framsticks.util.Misc;
26import com.framsticks.util.lang.Containers;
27import com.framsticks.util.lang.Strings;
28
29@FramsClassAnnotation(id = "class", name = "class")
30public class FramsClassBuilder implements Builder<FramsClass> {
31        private static final Logger log =
32                LogManager.getLogger(FramsClassBuilder.class);
33
34        public static String getName(FramsClassAnnotation fca, Class<?> javaClass) {
35                return fca.name().equals("") ? javaClass.getSimpleName() : fca.name();
36        }
37
38        public static String getId(FramsClassAnnotation fca, Class<?> javaClass) {
39                return fca.id().equals("") ? javaClass.getSimpleName() : fca.id();
40        }
41
42        public static ParamBuilder induceParamType(ParamBuilder builder, Type type) {
43                // if (type.equals(Void.TYPE)) {
44                //      throw new ConstructionException().msg("void is not a valid type");
45                // }
46
47                if (type instanceof ParameterizedType) {
48                        ParameterizedType p = (ParameterizedType) type;
49                        Type rawType = p.getRawType();
50                        Type containedType = null;
51                        //TODO make implementation here
52                        boolean map = false;
53                        StringBuilder b = new StringBuilder();
54                        if (rawType.equals(Map.class)) {
55                                containedType = p.getActualTypeArguments()[1];
56                                map = true;
57                                b.append("l");
58                        } else if (rawType.equals(List.class)) {
59                                containedType = p.getActualTypeArguments()[0];
60                                b.append("l");
61                        } else if (rawType.equals(EventListener.class)) {
62                                containedType = p.getActualTypeArguments()[0];
63                                b.append("e");
64                        }
65                        if (!(containedType instanceof Class)) {
66                                return builder;
67                        }
68                        b.append(" ");
69
70                        Class<?> containedClass = (Class<?>) containedType;
71                        FramsClassAnnotation fca = containedClass.getAnnotation(FramsClassAnnotation.class);
72                        if (fca == null) {
73                                throw new ConstructionException().msg("the contained class is not annotated").arg("class", containedClass);
74                        }
75                        b.append(getName(fca, containedClass));
76                        //TODO parametrize this
77                        if (map) {
78                                b.append(" uid");
79                        }
80
81                        builder.type(b.toString());
82                        return builder;
83                }
84
85                if (type instanceof Class) {
86
87                        Class<?> cl = (Class<?>) type;
88
89                        // TODO: future support for enum
90                        // if (cl.isEnum()) {
91                        //      Class<? extends Enum<?>> enumType = (Class<? extends Enum<?>>) cl;
92                        //      Enum<?>[] enums = enumType.getEnumConstants();
93                        //      StringBuilder b = new StringBuilder();
94
95                        //      b.append("d 0 ").append(enums.length - 1).append(" 0 ");
96                        //      for (Enum<?> e : enums) {
97                        //              b.append("~").append(e.name());
98                        //      }
99                        //      return b.toString();
100                        // }
101                        if (cl.equals(Integer.class) || cl.equals(int.class)) {
102                                builder.type("d");
103                                return builder;
104                        }
105                        if (cl.equals(String.class)) {
106                                builder.type("s");
107                                return builder;
108                        }
109                        if (cl.equals(Double.class) || cl.equals(double.class)) {
110                                builder.type("f");
111                                return builder;
112                        }
113                        if (cl.equals(Boolean.class) || cl.equals(boolean.class)) {
114                                builder.type( "d 0 1");
115                                return builder;
116                        }
117                        if (cl.equals(Object.class)) {
118                                builder.type("x");
119                                return builder;
120                        }
121
122
123                        // builder.type("o " + (cl).getCanonicalName());
124                        builder.type("o " + cl.getSimpleName());
125                        builder.fillStorageType(cl);
126                        return builder;
127                }
128
129                throw new ConstructionException().msg("failed to find framsticks for native type").arg("type", type);
130        }
131
132
133        public static ParamBuilder induceParamType(ParamBuilder builder, ParamCandidate candidate) {
134                Method method = candidate.getCaller();
135                if (method == null) {
136                        return induceParamType(builder, candidate.getType());
137                }
138
139                if (!method.getReturnType().equals(Void.TYPE)) {
140                        builder.resultType(induceParamType(Param.build(), method.getGenericReturnType()).finish(ValueParam.class));
141                }
142
143                List<ValueParam> arguments = new ArrayList<>();
144                int number = 0;
145                for (Type arg : method.getGenericParameterTypes()) {
146                        arguments.add(induceParamType(Param.build(), arg).idAndName("arg" + (number++)).finish(ValueParam.class));
147                }
148                builder.argumentsType(arguments);
149
150                return builder;
151        }
152
153        public static final String GENERATE_HELP_PREFIX = "automatically generated from: ";
154
155        public static FramsClass readFromStream(InputStream stream) {
156                return Loaders.loadFramsClass(new FileSource(stream));
157        }
158
159        // public static Class<? extends Param> getParamType(@Nonnull Class<?> c) {
160        //      if (c.equals(Integer.class)) {
161        //              return DecimalParam.class;
162        //      }
163        //      if (c.equals(Double.class)) {
164        //              return FloatParam.class;
165        //      }
166        //      if (c.equals(String.class)) {
167        //              return StringParam.class;
168        //      }
169        //      if (c.equals(Object.class)) {
170        //              return UniversalParam.class;
171        //      }
172        //      return null;
173        // }
174
175        public static String extractIdOf(Member member) {
176                if (member instanceof Field) {
177                        return member.getName();
178                }
179                if (member instanceof Method) {
180                        Method m = (Method) member;
181                        String n = m.getName();
182                        int argsNum = m.getParameterTypes().length;
183                        if (argsNum == 0) {
184                                return n.startsWith("get") ? Strings.uncapitalize(n.substring(3)) : n;
185                        }
186                        if (argsNum == 1) {
187                                if (n.startsWith("set")) {
188                                        return Strings.uncapitalize(n.substring(3));
189                                }
190                                if (n.startsWith("add")) {
191                                        return Strings.uncapitalize(n.substring(3));
192                                }
193                                if (n.startsWith("remove")) {
194                                        return Strings.uncapitalize(n.substring(6));
195                                }
196                                return n;
197                        }
198                        log.error("invalid number of arguments");
199                        return null;
200                }
201                log.error("invalid kind of member");
202                return null;
203        }
204        public static String getName(ParamAnnotation annotation, Member member) {
205                return annotation.name().equals("") ? Strings.capitalize(extractIdOf(member)) : annotation.name();
206        }
207
208        public static String getId(ParamAnnotation annotation, Member member) {
209                return annotation.id().equals("") ? extractIdOf(member) : annotation.id();
210        }
211
212        public static ParamBuilder fill(ParamBuilder builder, Member member, ParamAnnotation annotation) {
213                return builder
214                        .id(getId(annotation, member))
215                        .name(getName(annotation, member));
216
217        }
218
219        public static final Map<Class<?>, FramsClass> synchronizedCacheForBasedOnForJavaClass = Collections.synchronizedMap(new IdentityHashMap<Class<?>, FramsClass>());
220
221        public FramsClass forClass(Class<?> javaClass) throws ConstructionException {
222                FramsClass result = synchronizedCacheForBasedOnForJavaClass.get(javaClass);
223                if (result != null) {
224                        return result;
225                }
226
227                log.debug("building for class {}", javaClass);
228
229                FramsClassAnnotation fca = javaClass.getAnnotation(FramsClassAnnotation.class);
230                if (fca == null) {
231                        throw new ConstructionException().msg("java class is not annotated with FramsClassAnnotation").arg("java", javaClass);
232                }
233
234                id(getId(fca, javaClass));
235                name(getName(fca, javaClass));
236
237                for (ParamCandidate pc : ParamCandidate.getAllCandidates(javaClass).getOrder()) {
238                        ParamBuilder builder = Param.build().id(pc.getId()).name(pc.getName()).flags(pc.getFlags());
239
240                        induceParamType(builder, pc);
241
242                        for (ParamAnnotation pa : pc.getAnnotations()) {
243                                if (!"".equals(pa.def())) {
244                                        builder.def(pa.def());
245                                }
246                                if (!"".equals(pa.help())) {
247                                        builder.help(pa.help());
248                                }
249                                if (!"".equals(pa.min())) {
250                                        builder.min(pa.min());
251                                }
252                                if (!"".equals(pa.max())) {
253                                        builder.max(pa.max());
254                                }
255                                builder.extra(pa.extra());
256                                if (!"".equals(pa.stringType())) {
257                                        builder.type(pa.stringType());
258                                }
259                                if (!pa.paramType().equals(Param.class)) {
260                                        builder.type(pa.paramType());
261                                }
262                        }
263                        param(builder);
264                }
265
266                result = finish();
267
268                synchronizedCacheForBasedOnForJavaClass.put(javaClass, result);
269
270                return result;
271        }
272
273
274        protected String id;
275
276        protected String name;
277
278        protected String description;
279
280        protected final List<Param> params = new LinkedList<>();
281
282        protected List<GroupBuilder> groupBuilders = new ArrayList<GroupBuilder>();
283
284        @ParamAnnotation
285        public FramsClassBuilder id(String id) {
286                this.id = id;
287                return this;
288        }
289
290        @ParamAnnotation
291        public FramsClassBuilder name(String name) {
292                this.name = name;
293                return this;
294        }
295
296        public FramsClassBuilder idAndName(String v) {
297                this.id = v;
298                this.name = v;
299                return this;
300        }
301
302        @ParamAnnotation(id = "desc")
303        public FramsClassBuilder description(String description) {
304                this.description = description;
305                return this;
306        }
307
308        public FramsClassBuilder() {
309        }
310
311        public FramsClass finish() {
312                return new FramsClass(this);
313        }
314
315        @AutoAppendAnnotation
316        public FramsClassBuilder param(ParamBuilder builder) {
317                Param param = builder.finish();
318
319                Integer group = param.getGroup();
320                if (group != null) {
321                        Containers.getFromList(groupBuilders, group, "group", this).addParam(param);
322                }
323
324                params.add(param);
325                return this;
326        }
327
328        @AutoAppendAnnotation
329        public FramsClassBuilder group(GroupBuilder builder) {
330                groupBuilders.add(builder);
331                return this;
332        }
333
334        /**
335         * @return the id
336         */
337        @ParamAnnotation
338        public String getId() {
339                return id;
340        }
341
342        /**
343         * @return the name
344         */
345        @ParamAnnotation
346        public String getName() {
347                return name;
348        }
349
350        /**
351         * @return the description
352         */
353        @ParamAnnotation(id = "desc")
354        public String getDescription() {
355                return description;
356        }
357
358        public FramsClassBuilder group(String group) {
359                return group(new GroupBuilder().name(group));
360        }
361
362        @Override
363        public String toString() {
364                return "FramsClassBuilder for " + Misc.returnNotNull(id, "<not yet known>");
365        }
366
367}
Note: See TracBrowser for help on using the repository browser.