source: java/main/src/main/java/com/framsticks/params/ParamBuilder.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: 11.2 KB
Line 
1package com.framsticks.params;
2
3import com.framsticks.params.annotations.FramsClassAnnotation;
4import com.framsticks.params.annotations.ParamAnnotation;
5import com.framsticks.params.types.*;
6import com.framsticks.util.Builder;
7import com.framsticks.util.FramsticksException;
8import com.framsticks.util.lang.Strings;
9
10import org.apache.log4j.Logger;
11
12import java.lang.reflect.InvocationTargetException;
13import java.util.ArrayList;
14import java.util.Arrays;
15import java.util.List;
16import java.util.regex.Matcher;
17import java.util.regex.Pattern;
18
19import javax.annotation.Nonnull;
20
21/**
22 * The class ParamBuilder helps building Param objects.
23 *
24 * @author Mateusz Jarus <name.surname@gmail.com> (please replace name and
25 *         surname with my personal data)
26 *
27 * @author Piotr Śniegowski
28 */
29
30@FramsClassAnnotation(name = "prop", id = "prop")
31public class ParamBuilder implements Builder<Param> {
32        private final static Logger log = Logger.getLogger(ParamBuilder.class.getName());
33
34        private static final String ID_FIELD = "id";
35        private static final String NAME_FIELD = "name";
36        private static final String HELP_FIELD = "help";
37        private static final String GROUP_FIELD = "group";
38        private static final String TYPE_FIELD = "type";
39        private static final String FLAGS_FIELD = "flags";
40
41        /** The parameter id. */
42        private String id;
43
44        /** The number of group, that parameter belongs to. */
45        private Integer group;
46
47        /** The flags stored as a bit sum. */
48        private Integer flags = 0;
49
50        /** The parameter name. */
51        private String name;
52
53        /** The help (description) concerning parameter. */
54        private String help;
55
56        /** The type of parameter. */
57        private Class<? extends Param> paramType;
58
59        private Object min;
60
61        private Object max;
62
63        private Object def;
64
65        private Integer extra;
66
67        String containedTypeName;
68
69        protected Class<?> storageType;
70
71        protected FramsClassBuilder classBuilder;
72
73        public ParamBuilder() {
74                this(null);
75        }
76
77        protected ValueParam resultType;
78
79        protected List<ValueParam> argumentsType;
80
81        /**
82         * @param classBuilder
83         */
84        public ParamBuilder(FramsClassBuilder classBuilder) {
85                this.classBuilder = classBuilder;
86        }
87
88
89        /**
90         * @return the min
91         */
92        @ParamAnnotation
93        public Object getMin() {
94                return min;
95        }
96
97        /**
98         * @return the max
99         */
100        @ParamAnnotation
101        public Object getMax() {
102                return max;
103        }
104
105        /**
106         * @return the def
107         */
108        @ParamAnnotation
109        public Object getDef() {
110                return def;
111        }
112
113        public String getContainedTypeName() {
114                return Strings.notEmpty(containedTypeName) ? containedTypeName : null;
115        }
116
117        /**
118         * @return the resultType
119         */
120        public ValueParam getResultType() {
121                return resultType;
122        }
123
124
125        /**
126         * @param resultType the resultType to set
127         */
128        public ParamBuilder resultType(ValueParam resultType) {
129                this.resultType = resultType;
130                return this;
131        }
132
133        /**
134         * @return the argumentsType
135         */
136        public List<ValueParam> getArgumentsType() {
137                return argumentsType;
138        }
139
140
141        /**
142         * @param argumentsType the argumentsType to set
143         */
144        public ParamBuilder argumentsType(List<ValueParam> argumentsType) {
145                this.argumentsType = argumentsType;
146                return this;
147        }
148
149        /**
150         * @return the enumValues
151         */
152        public List<String> getEnumValues() {
153                return enumValues;
154        }
155
156        /**
157         * @return the uid
158         */
159        public String getUid() {
160                return uid;
161        }
162
163        public @Nonnull <T extends Param> T finish(Class<T> requested) {
164                Param param = finish();
165                if (!requested.isInstance(param)) {
166                        throw new FramsticksException().msg("param is of wrong type").arg("requested", requested).arg("actual", param.getClass());
167                }
168                return requested.cast(param);
169        }
170
171        /**
172         * Build Param based on provided data.
173         *
174         * @return Param object
175         * @throws Exception
176         *             when Param getType is not defined
177         */
178        public @Nonnull Param finish() {
179                try {
180                        if (paramType == null) {
181                                throw new FramsticksException().msg("trying to finish incomplete param");
182                        }
183                        return paramType.getConstructor(ParamBuilder.class).newInstance(this);
184                } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException | FramsticksException e) {
185                        throw new FramsticksException().msg("failed to create param").cause(e).arg("name", name);
186                }
187        }
188
189        @ParamAnnotation
190        public ParamBuilder id(String id) {
191                this.id = id;
192                return this;
193        }
194
195        public <T extends Param> ParamBuilder type(Class<T> type) {
196                assert type != null;
197                this.paramType = type;
198                return this;
199        }
200
201        /**
202         * @return the id
203         */
204        @ParamAnnotation
205        public String getId() {
206                return id;
207        }
208
209        @ParamAnnotation
210        public ParamBuilder group(Integer group) {
211                this.group = group;
212                return this;
213        }
214
215        @ParamAnnotation
216        public ParamBuilder flags(Integer flags) {
217                this.flags = flags;
218                return this;
219        }
220
221        @ParamAnnotation
222        public ParamBuilder name(String name) {
223                this.name = name;
224                return this;
225        }
226
227        protected <T extends Number> void parseMinMaxDefNumber(Class<T> type, String second, String third, String fourth) {
228                if (second != null) {
229                        min = second;
230                }
231                if (third != null) {
232                        max = third;
233                }
234                if (fourth != null) {
235                        def = fourth;
236                }
237        }
238
239        protected List<String> enumValues;
240
241        public ParamBuilder enums(List<String> values) {
242                enumValues = values;
243                return type(EnumParam.class);
244        }
245
246        protected String uid;
247
248        @ParamAnnotation
249        public ParamBuilder type(String type) {
250                // typeString = type;
251                assert type != null;
252
253                log.trace("parsing type: " + type);
254
255                String[] typeSplitted = type.split(" ");
256                String first = typeSplitted[0];
257                String second = typeSplitted.length > 1 ? typeSplitted[1] : null;
258                String third = typeSplitted.length > 2 ? typeSplitted[2] : null;
259                String fourth = typeSplitted.length > 3 ? typeSplitted[3] : null;
260
261                switch (first.charAt(0)) {
262                        case 'o': {
263                                containedTypeName = second != null ? second : first.substring(1);
264                                type(ObjectParam.class);
265                                break;
266                        }
267                        case 'p': {
268                                type(ProcedureParam.class);
269                                signature(type.substring(1));
270                                break;
271                        }
272                        case 'd': {
273
274                                int tildeIndex = type.indexOf("~");
275                                if (tildeIndex != -1) {
276                                        enums(Arrays.asList(type.substring(tildeIndex + 1).split("~")));
277                                } else {
278                                        if (first.length() >= 2) {
279                                                switch (first.charAt(1)) {
280                                                        case 'b': {
281                                                                type(BinaryParam.class);
282                                                                break;
283                                                        }
284                                                        case 'c': {
285                                                                type(ColorParam.class);
286                                                                break;
287                                                        }
288                                                        default: {
289                                                                log.error("unknown type: " + first);
290                                                                return this;
291                                                        }
292                                                }
293                                        }
294                                        if ("0".equals(second) && "1".equals(third)) {
295                                                type(BooleanParam.class);
296                                        }
297                                        if (paramType == null) {
298                                                type(DecimalParam.class);
299                                        }
300                                }
301                                if (DecimalParam.class.isAssignableFrom(this.paramType)) {
302                                        parseMinMaxDefNumber(Integer.class, second, third, fourth);
303                                }
304                                break;
305                        }
306                        case 'f': {
307                                type(FloatParam.class);
308                                parseMinMaxDefNumber(Double.class, second, third, fourth);
309                                break;
310                        }
311                        case 'x': {
312                                type(UniversalParam.class);
313                                break;
314                        }
315                        case 's': {
316                                type(StringParam.class);
317                                min(second);
318                                max(third);
319                                break;
320                        }
321                        case 'e': {
322                                type(EventParam.class);
323                                break;
324                        }
325                        case 'l': {
326                                containedTypeName = second;
327                                if (third != null) {
328                                        type(UniqueListParam.class);
329                                        uid = third;
330                                } else {
331                                        type(ArrayListParam.class);
332                                }
333                                break;
334                        }
335                        default:{
336                                log.error("unknown type: " + first);
337                                return this;
338                        }
339                }
340                return this;
341        }
342
343        @ParamAnnotation
344        public ParamBuilder help(String help) {
345                this.help = help;
346                return this;
347        }
348
349        /**
350         * @return the group
351         */
352        @ParamAnnotation
353        public Integer getGroup() {
354                return group;
355        }
356
357        /**
358         * @return the flags
359         */
360        @ParamAnnotation
361        public Integer getFlags() {
362                return flags;
363        }
364
365        /**
366         * @return the name
367         */
368        @ParamAnnotation
369        public String getName() {
370                return name;
371        }
372
373        /**
374         * @return the help
375         */
376        @ParamAnnotation
377        public String getHelp() {
378                return help;
379        }
380
381        @ParamAnnotation
382        public String getType() {
383                return "?";
384        }
385
386        @ParamAnnotation(id = "xtra")
387        public Integer getExtra() {
388                return extra;
389        }
390
391        /**
392         * @return the paramType
393         */
394        public Class<? extends Param> getParamType() {
395                return paramType;
396        }
397
398        @ParamAnnotation(id = "xtra")
399        public ParamBuilder extra(Integer extra) {
400                this.extra = extra;
401                return this;
402        }
403
404        @ParamAnnotation
405        public ParamBuilder min(Object min) {
406                this.min = min;
407                return this;
408        }
409
410        @ParamAnnotation
411        public ParamBuilder max(Object max) {
412                this.max = max;
413                return this;
414        }
415
416        @ParamAnnotation
417        public ParamBuilder def(Object def) {
418                this.def = def;
419                return this;
420        }
421
422
423        public Param build(String line) throws Exception {
424                String[] paramEntryValues = line.split(",");
425
426                if (paramEntryValues.length == 0) {
427                        log.warn("field empty or wrong format (" + line
428                                        + ") - omitting");
429                        return null;
430                }
431
432                for (int i = 0; i < paramEntryValues.length; ++i) {
433                        paramEntryValues[i] = paramEntryValues[i].trim();
434                }
435
436                try {
437                        id(paramEntryValues[0]);
438                        group(Integer.valueOf(paramEntryValues[1]));
439                        flags(Flags.read(paramEntryValues[2]));
440                        name(paramEntryValues[3]);
441                        type(paramEntryValues[4]);
442                        help(paramEntryValues[6]);
443                } catch (IndexOutOfBoundsException e) {
444                        /** everything is ok, parameters have just finished*/
445                } catch (NumberFormatException ex) {
446                        log.warn("wrong format of entry: " + line
447                                        + ", omitting");
448                        return null;
449                }
450                return finish();
451        }
452
453        public void setField(String key, String value) {
454                switch (key) {
455                        case ID_FIELD:
456                                id(value);
457                                break;
458                        case NAME_FIELD:
459                                name(value);
460                                break;
461                        case TYPE_FIELD:
462                                type(value);
463                                break;
464                        case FLAGS_FIELD:
465                                flags(Flags.read(value));
466                                break;
467                        case HELP_FIELD:
468                                help(value);
469                                break;
470                        case GROUP_FIELD:
471                                group(Integer.valueOf(value));
472                                break;
473                        default:
474                                log.error("unknown field for Param: " + key);
475                                break;
476                }
477        }
478
479        public ParamBuilder fillDef(Object def) {
480                if (this.def == null) {
481                        return def(def);
482                }
483                return this;
484        }
485
486        public ParamBuilder fillStorageType(Class<?> storageType) {
487                if (this.storageType == null) {
488                        this.storageType = storageType;
489                }
490                return this;
491        }
492
493        public Class<?> getStorageType() {
494                return storageType;
495        }
496
497        public ParamBuilder forAccess(AccessInterface access) {
498                return name(access.getId()).type("o " + access.getId());
499        }
500
501        protected static ValueParam parseProcedureTypePart(String type, String name) {
502                return Param.build().type(type).name(name).id(name).finish(ValueParam.class);
503        }
504
505        private static Pattern addressPattern = Pattern.compile("^([^\\(]+)?\\(([^\\)]*)\\)$");
506
507        public ParamBuilder signature(String signature) {
508                argumentsType = new ArrayList<>();
509
510                if (!Strings.notEmpty(signature)) {
511                        resultType = null;
512                        return this;
513                }
514                Matcher matcher = addressPattern.matcher(signature);
515                if (!matcher.matches()) {
516                        throw new FramsticksException().msg("invalid signature");
517                }
518                String result = Strings.collapse(matcher.group(1));
519                resultType = (result != null) ? parseProcedureTypePart(result, null) : null;
520                String arguments = matcher.group(2);
521                if (!Strings.notEmpty(arguments)) {
522                        return this;
523                }
524                int number = 0;
525                for (String a : arguments.split(",")) {
526                        int space = a.indexOf(' ');
527                        String type;
528                        String name;
529                        if (space == -1) {
530                                type = a;
531                                name = "arg" + number;
532                        } else {
533                                type = a.substring(0, space);
534                                name = a.substring(space + 1);
535                        }
536                        argumentsType.add(parseProcedureTypePart(type, name));
537                        ++number;
538                }
539                return this;
540        }
541
542
543        public ParamBuilder idAndName(String name) {
544                id(name);
545                name(name);
546                return this;
547        }
548}
549
Note: See TracBrowser for help on using the repository browser.