source: java/main/src/main/java/com/framsticks/params/ParamsUtil.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: 11.2 KB
Line 
1package com.framsticks.params;
2
3import java.util.ArrayList;
4// import java.util.HashMap;
5import java.util.List;
6import java.util.Map;
7import java.util.TreeMap;
8import java.util.regex.Matcher;
9import java.util.regex.Pattern;
10
11import javax.annotation.Nonnull;
12
13// import org.apache.logging.log4j.Logger;
14// import org.apache.logging.log4j.LogManager;
15
16import com.framsticks.util.FramsticksException;
17import com.framsticks.util.lang.Numbers;
18
19
20import static com.framsticks.util.lang.Containers.filterInstanceof;
21
22/**
23 * @author Piotr Sniegowski
24 */
25public abstract class ParamsUtil {
26        // private final static Logger log = LogManager.getLogger(ParamsUtil.class.getName());
27
28
29        public static String readSourceToString(Source source) {
30                StringBuilder result = new StringBuilder();
31                String line;
32                while ((line = source.readLine()) != null) {
33                        result.append(line).append(" ");
34                }
35                source.close();
36                return result.toString();
37        }
38
39        public static <T> List<T> stripAccess(List<Access> accesses, Class<T> type) {
40                List<T> result = new ArrayList<T>();
41                for (Access a : accesses) {
42                        Object object = a.getSelected();
43                        if (!type.isInstance(object)) {
44                                throw new FramsticksException().msg("extracted object is of invalid type").arg("object", object).arg("desired", type).arg("actual", object.getClass()).arg("access", a);
45                        }
46                        result.add(type.cast(object));
47                }
48                return result;
49        }
50
51        public static int takeAllNonNullValues(Access to, Access from) {
52                int copied = 0;
53                for (ValueParam f : filterInstanceof(from.getParams(), ValueParam.class)) {
54                        Object v = from.get(f, Object.class);
55                        if (v == null) {
56                                continue;
57                        }
58                        // if (to.get(f, Object.class) != null) {
59                        //      continue;
60                        // }
61                        to.set(f, v);
62                        ++copied;
63                }
64                return copied;
65        }
66
67        public static int copyExistingParamsTypeSafe(Access to, Access from) {
68                int copied = 0;
69                for (ValueParam f : filterInstanceof(from.getParams(), ValueParam.class)) {
70                        Param t = from.getParam(f.getId());
71                        if (!(t instanceof ValueParam)) {
72                                continue;
73                        }
74                        if (to.getClass() != f.getClass()) {
75                                continue;
76                        }
77                        to.set((ValueParam) t, from.get(f, Object.class));
78                        ++copied;
79                }
80                return copied;
81        }
82
83        public static <T> T selectObjectForAccess(Access access, Object object, Class<T> type) {
84                if (object == null) {
85                        return null;
86                }
87                if (!type.isInstance(object)) {
88                        throw new FramsticksException().msg("trying to select object of wrong type").arg("object", object).arg("type", object.getClass()).arg("in", access);
89                }
90                return type.cast(object);
91        }
92
93        public static int getNumberOfCompositeParamChild(Access access, Object child) {
94                int count = access.getCompositeParamCount();
95                for (int i = 0; i < count; ++i) {
96                        if (access.get(i, Object.class) == child) {
97                                return i;
98                        }
99                }
100                return -1;
101        }
102
103        public static Object[] arguments(Object... args) {
104                return args;
105        }
106
107        public static Param getParam(ParamCollection collection, int i) {
108                return collection.getParam(i);
109        }
110
111        public static Param getParam(ParamCollection collection, String id) {
112                return collection.getParam(id);
113        }
114
115        public static @Nonnull <T extends Param> T castedParam(ParamCollection collection, @Nonnull final Param param, @Nonnull final Class<T> type, Object name) {
116                if (param == null) {
117                        // return null;
118                        throw new FramsticksException().msg("param is missing").arg("name", name).arg("in", collection);
119                }
120                if (!type.isInstance(param)) {
121                        // return null;
122                        throw new FramsticksException().msg("wrong type of param").arg("actual", param.getClass()).arg("requested", type).arg("in", collection);
123                }
124                return type.cast(param);
125        }
126
127        /**
128         * Gets the param entry.
129         *
130         * @param i
131         *            the offset of parameter
132         * @return the param entry
133         */
134        public static @Nonnull <T extends Param> T getParam(ParamCollection collection, final int i, @Nonnull final Class<T> type) {
135                return castedParam(collection, collection.getParam(i), type, i);
136        }
137
138        /**
139         * Gets the param entry.
140         *
141         * @param id
142         *            the getId of parameter
143         * @return the param entry
144         */
145        public static @Nonnull <T extends Param> T getParam(ParamCollection collection, @Nonnull final String id, @Nonnull final Class<T> type) {
146                return castedParam(collection, collection.getParam(id), type, id);
147        }
148
149        public static final String SERIALIZED = "@Serialized:";
150
151        public static class SerializationContext {
152                protected final StringBuilder builder = new StringBuilder();
153                protected final ArrayList<Object> objects = new ArrayList<>();
154
155                protected void appendString(String value) {
156                        builder.append('"').append(value).append('"');
157                }
158
159                protected boolean serializeInternal(Object value) {
160                        if (value == null) {
161                                builder.append("null");
162                                return true;
163                        }
164                        /** indexOf is not used here, because it uses equals() internally, which results in StackOverflowError */
165                        Class<?> type = value.getClass();
166                        if (type.equals(String.class)) {
167                                String stringValue = (String) value;
168                                appendString(stringValue);
169                                return stringValue.startsWith(SERIALIZED);
170                        }
171                        if (type.equals(Boolean.class)) {
172                                builder.append(((Boolean) value) ? "1" : "0");
173                                return false;
174                        }
175                        if (type.equals(Double.class) || type.equals(Integer.class)) {
176                                builder.append(value.toString());
177                                return false;
178                        }
179
180                        for (int i = 0; i < objects.size(); ++i) {
181                                if (objects.get(i) == value) {
182                                        builder.append("^").append(i);
183                                        return true;
184                                }
185                        }
186
187                        if (List.class.isAssignableFrom(type)) {
188                                objects.add(value);
189                                List<?> list = (List<?>) value;
190                                boolean placeComma = false;
191                                builder.append("[");
192                                for (Object element : list) {
193                                        if (placeComma) {
194                                                builder.append(",");
195                                        } else {
196                                                placeComma = true;
197                                        }
198                                        serializeInternal(element);
199                                }
200                                builder.append("]");
201                                return true;
202                        }
203                        if (Map.class.isAssignableFrom(type)) {
204                                objects.add(value);
205                                Map<?, ?> map = (Map<?, ?>) value;
206                                boolean placeComma = false;
207                                builder.append("{");
208                                for (Map.Entry<?, ?> entry : map.entrySet()) {
209                                        if (placeComma) {
210                                                builder.append(",");
211                                        } else {
212                                                placeComma = true;
213                                        }
214                                        if (!(entry.getKey() instanceof String)) {
215                                                throw new FramsticksException().msg("non string keys are not allowed in serialization").arg("key type", entry.getKey().getClass());
216                                        }
217                                        appendString((String) entry.getKey());
218                                        builder.append(":");
219                                        serializeInternal(entry.getValue());
220                                }
221                                builder.append("}");
222                                return true;
223                        }
224                        if (type.equals(OpaqueObject.class)) {
225                                builder.append(value.toString());
226                                return true;
227                        }
228                        throw new FramsticksException().msg("invalid type for serialization").arg("type", type);
229                }
230
231                public String serialize(Object value) {
232                        if (value instanceof String) {
233                                String stringValue = (String) value;
234                                if (!stringValue.startsWith(SERIALIZED)) {
235                                        return stringValue;
236                                }
237                        }
238                        boolean complex = serializeInternal(value);
239                        return (complex ? SERIALIZED : "") + builder.toString();
240                }
241
242        }
243
244
245        public static <T> String serialize(T value) {
246                return new SerializationContext().serialize(value);
247        }
248
249        public static class DeserializationContext {
250
251                public static final Pattern OPAQUE_OBJECT_PATTERN = Pattern.compile("^(\\w+)<0x([a-fA-F0-9]+)>$");
252
253                @SuppressWarnings("serial")
254                public static class Exception extends FramsticksException {
255                }
256
257                protected final ArrayList<Object> objects = new ArrayList<>();
258                protected int cursor = 0;
259                protected final String input;
260
261                /**
262                 * @param input
263                 */
264                public DeserializationContext(String input) {
265                        this.input = input;
266                        cursor = 0;
267                }
268
269                protected boolean isFinished() {
270                        return cursor == input.length();
271                }
272
273                protected boolean is(char value) {
274                        if (isFinished()) {
275                                throw fail().msg("input ended");
276                        }
277                        return input.charAt(cursor) == value;
278                }
279
280                protected boolean isOneOf(String values) {
281                        if (isFinished()) {
282                                throw fail().msg("input ended");
283                        }
284                        return values.indexOf(input.charAt(cursor)) != -1;
285                }
286
287                protected char at() {
288                        return input.charAt(cursor);
289                }
290
291                protected char at(int pos) {
292                        return input.charAt(pos);
293                }
294
295                protected FramsticksException fail() {
296                        return new Exception().arg("at", cursor).arg("input", input);
297                }
298
299                protected void force(char value) {
300                        if (!is(value)) {
301                                throw fail().msg("invalid character").arg("expected", value).arg("found", at());
302                        }
303                        next();
304                }
305
306                protected boolean isAndNext(char value) {
307                        if (!is(value)) {
308                                return false;
309                        }
310                        next();
311                        return true;
312                }
313
314                protected void next() {
315                        ++cursor;
316                        // log.info("at: {}|{}", input.substring(0, cursor), input.substring(cursor));
317                }
318
319                protected void goToNext(char value) {
320                        while (cursor < input.length()) {
321                                if (is(value)) {
322                                        return;
323                                }
324                                next();
325                        }
326                        throw fail().msg("passed end").arg("searching", value);
327                }
328
329
330                protected String forceStringRemaining() {
331                        int start = cursor;
332                        while (true) {
333                                goToNext('"');
334                                if (at(cursor - 1) != '\\') {
335                                        next();
336                                        return input.substring(start, cursor - 1);
337                                }
338                                next();
339                                // it is finishing that loop, because of throwing in goToNext()
340                        }
341                        // throw fail();
342                }
343
344                public Object deserialize() {
345                        if (isAndNext('[')) {
346                                List<Object> list = new ArrayList<>();
347                                objects.add(list);
348                                while (!isAndNext(']')) {
349                                        if (!list.isEmpty()) {
350                                                force(',');
351                                        }
352                                        Object child = deserialize();
353                                        list.add(child);
354                                }
355                                return list;
356                        }
357
358                        if (isAndNext('{')) {
359                                Map<String, Object> map = new TreeMap<>();
360                                objects.add(map);
361                                while (!isAndNext('}')) {
362                                        if (!map.isEmpty()) {
363                                                force(',');
364                                        }
365                                        force('"');
366                                        String key = forceStringRemaining();
367                                        force(':');
368                                        Object value = deserialize();
369                                        map.put(key, value);
370                                }
371                                return map;
372                        }
373
374                        if (isAndNext('"')) {
375                                return forceStringRemaining();
376                        }
377                        int start = cursor;
378                        while (!isFinished() && !isOneOf("]},")) {
379                                next();
380                        }
381                        if (start == cursor) {
382                                throw fail().msg("empty value");
383                        }
384
385                        String value = input.substring(start, cursor);
386                        if (value.equals("null")) {
387                                //TODO: add this to list?
388                                return null;
389                        }
390
391                        Matcher matcher = OPAQUE_OBJECT_PATTERN.matcher(value);
392                        if (matcher.matches()) {
393                                return new OpaqueObject(matcher.group(1), Long.parseLong(matcher.group(2), 16));
394                        }
395
396
397                        Object number = DeserializationContext.tryParseNumber(value);
398                        if (number != null) {
399                                return number;
400                        }
401
402                        if (value.charAt(0) == '^') {
403                                Integer reference = Numbers.parse(value.substring(1), Integer.class);
404                                if (reference == null) {
405                                        throw fail().msg("invalid reference").arg("reference", reference);
406                                }
407                                return objects.get(reference);
408                        }
409                        //TODO: parse ^
410                        //TODO: parse opaque object
411                        throw fail().msg("unknown entity");
412
413                }
414
415                public static Object tryParseNumber(String value) {
416                        Integer i = Numbers.parse(value, Integer.class);
417                        if (i != null) {
418                                return i;
419                        }
420
421                        Double d = Numbers.parse(value, Double.class);
422                        if (d != null) {
423                                return d;
424                        }
425
426                        return null;
427                }
428        }
429
430
431        public static Object deserialize(String value) {
432                Object number = DeserializationContext.tryParseNumber(value);
433                if (number != null) {
434                        return number;
435                }
436
437                if (!value.startsWith(SERIALIZED)) {
438                        return value;
439                }
440                return new DeserializationContext(value.substring(SERIALIZED.length())).deserialize();
441        }
442
443        public static <T> T deserialize(String value, Class<T> type) {
444                Object object = deserialize(value);
445
446                return type.cast(object);
447        }
448
449}
Note: See TracBrowser for help on using the repository browser.