source: java/main/src/main/java/com/framsticks/params/ParamBuilder.java @ 97

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

HIGHLIGHTS:

  • add proper exception passing between communication sides:

if exception occur during handling client request, it is
automatically passed as comment to error response.

it may be used to snoop communication between peers

  • fix algorithm choosing text controls in GUI
  • allow GUI testing in virtual frame buffer (xvfb)

FEST had some problem with xvfb but workaround was found

supports tab-completion based on requests history

CHANGELOG:
Further improve handling of exceptions in GUI.

Add StatusBar? implementing ExceptionResultHandler?.

Make completion processing asynchronous.

Minor changes.

Improve completion in console.

Improve history in InteractiveConsole?.

First working version of DirectConsole?.

Minor changes.

Make Connection.address non final.

It is more suitable to use in configuration.

Improvement of consoles.

Improve PopupMenu? and closing of FrameJoinable?.

Fix BrowserTest?.

Found bug with FEST running under xvfb.

JButtonFixture.click() is not working under xvfb.
GuiTest? has wrapper which uses JButton.doClick() directly.

Store CompositeParam? param in TreeNode?.

Simplify ClientSideManagedConnection? connecting.

There is now connectedFunctor needed, ApplicationRequests? can be
send right after creation. They are buffered until the version
and features are negotiated.

Narow down interface of ClientSideManagedConnection?.

Allow that connection specialization send only
ApplicationRequests?.

Improve policy of text control choosing.

Change name of Genotype in BrowserTest?.

Make BrowserTest? change name of Genotype.

Minor change.

First working draft of TrackConsole?.

Simplify Consoles.

More improvements with gui joinables.

Unify initialization on gui joinables.

More rework of Frame based entities.

Refactorize structure of JFrames based entities.

Extract GuiTest? from BrowserBaseTest?.

Reorganize Console classes structure.

Add Collection view to JoinableCollection?.

Configure timeout in testing.

Minor changes.

Rework connections hierarchy.

Add Mode to the get operation.

Make get and set in Tree take PrimitiveParam?.

Unify naming of operations.

Make RunAt? use the given ExceptionHandler?.

It wraps the virtual runAt() method call with
try-catch passing exception to handler.

Force RunAt? to include ExceptionHandler?.

Improve ClientAtServer?.

Minor change.

Another sweep with FindBugs?.

Rename Instance to Tree.

Minor changes.

Minor changes.

Further clarify semantics of Futures.

Add FutureHandler?.

FutureHandler? is refinement of Future, that proxifies
exception handling to ExceptionResultHandler? given
at construction time.

Remove StateFunctor? (use Future<Void> instead).

Make Connection use Future<Void>.

Unparametrize *ResponseFuture?.

Remove StateCallback? not needed anymore.

Distinguish between sides of ResponseFuture?.

Base ResponseCallback? on Future (now ResponseFuture?).

Make asynchronous store taking Future for flags.

Implement storeValue in ObjectInstance?.

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