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

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

HIGHLIGHTS:

  • cleanup Instance management
    • extract Instance interface
    • extract Instance common algorithms to InstanceUtils?
  • fix closing issues: Ctrl+C or window close button

properly shutdown whole program

by Java Framsticks framework

  • fix parsing and printing of all request types
  • hide exception passing in special handle method of closures
    • substantially improve readability of closures
    • basically enable use of exception in asynchronous closures

(thrown exception is transported back to the caller)

  • implement call request on both sides

CHANGELOG:
Further improve calling.

Improve instance calling.

Calling is working on both sides.

Improve exception handling in testing.

Waiters do not supercede other apllication exception being thrown.

Finished parsing and printing of all request types (with tests).

Move implementation and tests of request parsing to Request.

Add tests for Requests.

Improve waits in asynchronours tests.

Extract more algorithms to InstanceUtils?.

Extract Instance.resolve to InstanceUtils?.

Improve naming.

Improve passing exception in InstanceClient?.

Hide calling of passed functor in StateCallback?.

Hide Exception passing in asynchronous closures.

Hide exception passing in Future.

Make ResponseCallback? an abstract class.

Make Future an abstract class.

Minor change.

Move getPath to Path.to()

Move bindAccess to InstanceUtils?.

Extract common things to InstanceUtils?.

Fix synchronization bug in Connection.

Move resolve to InstanceUtils?.

Allow names of Joinable to be dynamic.

Add support for set request server side.

More fixes in communication.

Fix issues with parsing in connection.

Cut new line characters when reading.

More improvements.

Migrate closures to FramsticksException?.

Several changes.

Extract resolveAndFetch to InstanceUtils? algorithms.

Test resolving and fetching.

More fixes with function signature deduction.

Do not print default values in SimpleAbstractAccess?.

Add test of FramsClass? printing.

Improve FramsticksException? messages.

Add explicit dispatcher synchronization feature.

Rework assertions in tests.

Previous solution was not generic enough.

Allow addition of joinables to collection after start.

Extract SimulatorInstance? from RemoteInstance?.

Remove PrivateJoinableCollection?.

Improve connections.

Move shutdown hook to inside the Monitor.

It should work in TestNG tests, but it seems that
hooks are not called.

In ServerTest? client connects to testing server.

Move socket initialization to receiver thread.

Add proper closing on Ctrl+C (don't use signals).

Fix bugs with server accepting connections.

Merge Entity into Joinable.

Reworking ServerInstance?.

Extract more algorithm to InstanceUtils?.

Extract some common functionality from AbstractInstance?.

Functions were placed in InstanceUtils?.

Hide registry of Instance.

Use ValueParam? in Instance interface.

Minor change.

Extract Instance interface.

Old Instance is now AbstractInstance?.

File size: 11.4 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 addressPattern = 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 = addressPattern.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.