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