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

Last change on this file since 193 was 193, checked in by Maciej Komosinski, 10 years ago

Set svn:eol-style native for all textual files

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