source: java/main/src/main/java/com/framsticks/params/SimpleAbstractAccess.java @ 77

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

Add new java codebase.

File size: 13.7 KB
Line 
1package com.framsticks.params;
2
3import java.io.IOException;
4import java.text.DecimalFormat;
5import java.text.DecimalFormatSymbols;
6import java.util.ArrayList;
7import java.util.Collection;
8import java.util.List;
9
10import com.framsticks.params.types.*;
11import org.apache.log4j.Logger;
12import java.util.Locale;
13
14/**
15 * The Class SimpleAbstractAccess implements all the methods of AccessInterface
16 * which actions can be implemented with usage of {@link AccessInterface} methods
17 * or concern schema, which is stored in {@link #framsClass}
18 *
19 * Based on c++ class SimpleAbstractParam located in: cpp/gdk/param.*
20 *
21 * @author Jarek Szymczak <name.surname@gmail.com>, Mateusz Jarus (please
22 *         replace name and surname with my personal data)
23 *
24 * @author Piotr Sniegowski
25 */
26public abstract class SimpleAbstractAccess implements AccessInterface {
27
28        private final static Logger LOGGER = Logger.getLogger(SimpleAbstractAccess.class.getName());
29
30
31
32    @Override
33        public final FramsClass getFramsClass() {
34                return framsClass;
35        }
36
37        public void setFramsClass(FramsClass framsClass) {
38                this.framsClass = framsClass;
39        }
40
41
42
43
44    /**
45         * Simple String key, value class.
46         */
47        private static class Entry {
48
49                String key;
50                String value;
51
52                Entry(String key, String value) {
53                        this.key = key;
54                        this.value = value;
55                }
56
57                @Override
58                public String toString() {
59                        return key + " = " + value;
60                }
61        }
62
63        protected FramsClass framsClass;
64
65        @Override
66        public String getId() {
67                return framsClass.getId();
68        }
69
70    @Override
71        public int getParamCount() {
72                return framsClass.getParamCount();
73        }
74
75        @Override
76        public Param getParam(int i) {
77                return framsClass.getParamEntry(i);
78        }
79
80        @Override
81        public Param getParam(String id) {
82                return framsClass.getParamEntry(id);
83        }
84
85
86        @Override
87        public Param getGroupMember(int gi, int n) {
88                return framsClass.getGroupMember(gi, n);
89        }
90
91        @Override
92        public <T> T get(int i, Class<T> type) {
93                return get(getParam(i), type);
94        }
95
96        @Override
97        public <T> T get(String id, Class<T> type) {
98                return get(getParam(id), type);
99        }
100
101
102        @Override
103        public <T> int set(String id, T value) {
104                return set(getParam(id), value);
105        }
106
107        @Override
108        public <T> int set(int i, T value) {
109                return set(getParam(i), value);
110        }
111
112        @SuppressWarnings("unchecked")
113        @Override
114        public <T> int set(Param param, T value) {
115                int flags = 0;
116                //String id = param.getEffectiveId();
117                try {
118            Object oldValue = get(param, param.getStorageType());
119            Object casted = param.reassign(value, oldValue);
120            if (casted != oldValue) {
121                internalSet(param, casted);
122            }
123        } catch (CastFailure e) {
124            LOGGER.error("casting failure while set: ", e);
125
126        }
127        return flags;
128    }
129
130
131
132
133        @Override
134        public void setDefault(boolean numericOnly) {
135                for (int i = 0; i < framsClass.getParamCount(); i++)
136                        setDefault(i, numericOnly);
137        }
138
139        @Override
140        public void setDefault(int i, boolean numericOnly) {
141                Param entry = framsClass.getParamEntry(i);
142                if ((entry != null)     && (!numericOnly || entry.isNumeric())) {
143                        set(i, entry.getDef(entry.getStorageType()));
144                }
145        }
146
147        @Override
148        public void setMin() {
149                for (int i = 0; i < framsClass.getParamCount(); i++) {
150                        setMin(i);
151                }
152        }
153
154        @SuppressWarnings("unchecked")
155        @Override
156        public void setMin(int i) {
157                Param entry = framsClass.getParamEntry(i);
158                Object min = entry.getMin(entry.getStorageType());
159                if (min != null) {
160                        set(i, min);
161                }
162        }
163
164        @Override
165        public void setMax() {
166                for (int i = 0; i < framsClass.getParamCount(); i++) {
167                        setMax(i);
168                }
169        }
170
171        @SuppressWarnings("unchecked")
172        @Override
173        public void setMax(int i) {
174                Param entry = framsClass.getParamEntry(i);
175                Object max = entry.getMax(entry.getStorageType());
176                if (max != null) {
177                        set(i, max);
178                }
179        }
180
181        @Override
182        public void copyFrom(AccessInterface src) {
183                clearValues();
184                //TODO: iterate over self, and pull from src
185                /*
186                for (int i = 0; i < src.getFramsClass().size(); i++) {
187                        this.set(i, src.get(i, Object.class));
188                }
189                */
190        }
191
192
193
194
195        @Override
196        public void save(SinkInterface sink) {
197        assert framsClass != null;
198        sink.print(framsClass.getId()).print(":").breakLine();
199        for (Param p : framsClass.getParamEntries()) {
200            if (p instanceof ValueParam) {
201                Object value = get(p, Object.class);
202                if (value == null) {
203                    continue;
204                }
205                sink.print(p.getId()).print(":");
206                ((ValueParam)p).save(sink, value);
207                sink.breakLine();
208
209
210                //continue;
211            }
212            /*
213            if (p instanceof CompositeParam) {
214                if (!(p instanceof ListParam)) {
215                    continue;
216                }
217                Collection c = get(p, Collection.class);
218                if (c != null) {
219                    save(stream, p, c.size());
220                }
221            }
222            */
223
224        }
225        sink.breakLine();
226        }
227
228        @Override
229        public String save2(boolean omitDefaultValues) {
230                StringBuilder stringBuilder = new StringBuilder();
231                DecimalFormat df = new DecimalFormat("#.###", new DecimalFormatSymbols(
232                                Locale.ENGLISH));
233                boolean canOmitName = false;
234                int n = 0;
235                for (int i = 0; i < framsClass.getParamCount(); i++) {
236                        Object value = this.get(i, Object.class);
237                        Object def = framsClass.getParamEntry(i).getDef(Object.class);
238                        if (value != null && (!omitDefaultValues || !value.equals(def))) {
239                                if ((n != i && !canOmitName)
240                                                || (getParam(i).getFlags() & Flags.CANOMITNAME) == 0) {
241                                        stringBuilder.append(getParam(i).getId());
242                                        stringBuilder.append("=");
243                                }
244                                n++;
245                                canOmitName = true;
246                                if (this.get(i, Object.class) instanceof String) {
247                                        String valueString = this.get(i, String.class);
248                                        valueString = valueString.replaceAll("\\\"", "\\\\\"");
249                                        valueString = valueString.contains(",") ? "\""
250                                                        + valueString + "\"" : valueString;
251                                        // if ("".equals(valueString.trim()))
252                                        // value = "\"\"";
253                                        stringBuilder.append(valueString);
254                                } else if (this.get(i, Object.class) instanceof Double) {
255                                        stringBuilder.append(df.format(this.get(i, Double.class)));
256                                } else
257                                        stringBuilder.append(this.get(i, Object.class));
258                                stringBuilder.append(", ");
259                        } else {
260                                canOmitName = false;
261                        }
262                }
263
264                String params = "";
265                if (stringBuilder.length() > 1)
266                        params = stringBuilder.substring(0, stringBuilder.length() - 2);
267
268                return getId() + ":" + params;
269        }
270
271    /*
272    private static void appendToValue(StringBuilder value, String line) {
273
274        if (value.length() != 0) {
275            value.append(System.getProperty("line.separator"));
276        }
277        value.append(line);
278    }
279    */
280
281    private Entry readEntry(SourceInterface source)
282            throws IOException {
283
284        String line;
285        String key = null;
286        StringBuilder value = null;
287        while ((line = source.readLine()) != null)
288        {
289            if (key == null) {
290                int colonIndex = line.indexOf(':');
291                if (colonIndex == -1) {
292                    return null;
293                }
294                key = line.substring(0, colonIndex);
295                String inlineValue = line.substring(colonIndex + 1);
296
297
298                if (!inlineValue.startsWith("~")) {
299                    return new Entry(key, inlineValue);
300                }
301                value = new StringBuilder();
302                value.append(inlineValue.substring(1));
303                continue;
304            }
305            if (value.length() != 0) {
306                value.append(System.getProperty("line.separator"));
307            }
308            if (line.contains("~")) {
309                value.append(line.substring(0, line.indexOf("~")));
310                return new Entry(key, value.toString());
311            }
312            value.append(line);
313            /*
314            if (line.contains("~")) {
315                String lastLine = line.substring(0, line.indexOf("~"));
316                if (lastLine.length() > 0) {
317                    appendToValue(value, lastLine);
318                }
319                return new Entry(key, value.toString());
320            }
321            appendToValue(value, line);
322            */
323        }
324        return null;
325    }
326
327    @Override
328    public void load(SourceInterface source) throws Exception {
329        //TODO not clearing values, because get from manager gives only fields, not children
330        //this.clearValues();
331
332        Entry entry;
333
334        while ((entry = readEntry(source)) != null) {
335            Param param = getParam(entry.key);
336            if (param == null) {
337                continue;
338            }
339            if ((param.getFlags() & Flags.DONTLOAD) != 0) {
340                LOGGER.debug("DontLoad flag was set - not loading...");
341            } else {
342                int retFlags = this.set(param, entry.value);
343                if ((retFlags & (Flags.PSET_HITMIN | Flags.PSET_HITMAX)) != 0) {
344                    String which = ((retFlags & Flags.PSET_HITMIN) != 0) ? "small"
345                            : "big";
346                    LOGGER.warn("value of key '" + entry.key
347                            + "' was too " + which + ", adjusted");
348                }
349            }
350        }
351    }
352
353    @Override
354        public List<Exception> load2(String line) throws Exception {
355                this.clearValues();
356
357                // list of not terminable exceptions that occured
358                List<Exception> exceptions = new ArrayList<Exception>();
359
360                int indexOfColon = line.indexOf(':');
361                if (indexOfColon < 0)
362                        indexOfColon = line.length();
363                String classId = line.substring(0, indexOfColon).trim();
364                if (!getId().equals(classId))
365                        throw new Exception(
366                                        "Inappropriate getId of param interface (class), specified \""
367                                                        + classId + "\" while should be \"" + getId()
368                                                        + "\"");
369                String parameters;
370                if (indexOfColon == line.length())
371                        parameters = "";
372                else
373                        parameters = line.substring(indexOfColon + 1);
374
375                // tokenize
376                boolean doubleQuotes = false;
377                char previousChar = ',';
378                List<Entry> result = new ArrayList<Entry>();
379                StringBuilder stringBuilder = new StringBuilder();
380                String key = "";
381                if (parameters.trim().length() > 0) {
382                        for (char currentChar : parameters.toCharArray()) {
383                                if (!doubleQuotes && currentChar == '=' && "".equals(key)) {
384                                        key = stringBuilder.toString();
385                                        stringBuilder = new StringBuilder();
386                                } else if (!doubleQuotes && currentChar == ',') {
387                                        if (previousChar == ',') {
388                                                result.add(new Entry(key.trim(), null));
389                                        } else {
390                                                result.add(new Entry(key.trim(), stringBuilder
391                                                                .toString().trim()));
392                                        }
393                                        stringBuilder = new StringBuilder();
394                                        key = "";
395                                } else if (currentChar == '"') {
396                                        if (previousChar == '\\') {
397                                                stringBuilder.deleteCharAt(stringBuilder.length() - 1);
398                                                stringBuilder.append(currentChar);
399                                        } else
400                                                doubleQuotes = !doubleQuotes;
401                                } else {
402                                        stringBuilder.append(currentChar);
403                                }
404
405                                previousChar = currentChar;
406                        }
407
408                        String last = stringBuilder.toString().trim();
409                        // if (last.length() > 0 || previousChar == '\"'
410                        // || previousChar == ':')
411                        result.add(new Entry(key.trim(), last));
412
413                        if (doubleQuotes)
414                                throw new Exception(
415                                                "Double quotes expected while end of line met");
416                }
417
418                // if successfully parsed set all necessary values
419
420                //TODO: name omitting
421                Param currentParam = null;
422                boolean illegallyOmittedName = false;
423                for (Entry pair : result) {
424                        try {
425
426                                if (pair.key != null && !"".equals(pair.key)) {
427                                        Param param = getParam(pair.key);
428                                        if (param == null) {
429                                                illegallyOmittedName = true;
430                                                throw new Exception("No parameter with such id: "
431                                                                + pair.key);
432                                        } else {
433                                                currentParam = param;
434                                                illegallyOmittedName = false;
435                                        }
436                                } else if (illegallyOmittedName
437                                                || (currentParam.getFlags() & Flags.CANOMITNAME) == 0) {
438                                        throw new Exception(
439                                                        "Parameter with offset: "
440                                                                        + currentParam
441                                                                        + " is not set, "
442                                                                        + "because it's definition or definition of one of the previous params "
443                                                                        + "does not contain flag, which allow to skip the getName (flag 1024)");
444                                }
445
446                                if (pair.value != null) {
447                                        int setFlag = this.set(currentParam, pair.value);
448                                        if ((setFlag & Flags.PSET_HITMIN) != 0) {
449                                                exceptions.add(createBoundaryHitException(currentParam, pair.value, Flags.PSET_HITMIN));
450                                        }
451
452                                        if ((setFlag & Flags.PSET_HITMAX) != 0) {
453                                                exceptions.add(createBoundaryHitException(currentParam, pair.value, Flags.PSET_HITMAX));
454                                        }
455
456                                        if ((setFlag & Flags.PSET_RONLY) != 0) {
457                                                throw (new Exception(
458                                                                "Tried to set a read-only attribute \""
459                                                                                + currentParam.getId()
460                                                                                + "\" in class \"" + getId() + "\""));
461                                        }
462                                }
463
464                        } catch (Exception e) {
465                                exceptions.add(e);
466                        //} finally {
467                        //  currentProperty++;
468                        }
469                }
470                return exceptions;
471        }
472
473        private Exception createBoundaryHitException(Param param, String value, int flag) {
474                boolean minimum = (flag & Flags.PSET_HITMIN) != 0;
475                String boundary = (minimum ? param.getMin(Object.class) : param.getMax(Object.class)).toString();
476                String name =  (minimum ? "minimum" : "maximum");
477                return new Exception("Tried to set attribute \""
478                                + param.getId()
479                                + "\" in class \""
480                                + getId()
481                                + "\" to value which exceeds " + name + " ("
482                                + value
483                                + "), truncated to: "
484                                + boundary);
485        }
486       
487        protected abstract <T> void internalSet(Param param, T value);
488
489    @Override
490    public Collection<Param> getParams() {
491        return framsClass.getParamEntries();
492    }
493
494    /*
495        protected <T extends Comparable<T>> int setAndCut(Param param, Object value, Class<T> type) {
496                int flags = 0;
497                T val = type.cast(value);
498                T min = param.getMin(type);
499                T max = param.getMax(type);
500                if (min != null && val.compareTo(min) < 0) {
501                        val = min;
502                        flags |= Flags.PSET_HITMIN;
503                }
504                if (max != null && val.compareTo(max) > 0) {
505                        val = max;
506                        flags |= Flags.PSET_HITMAX;
507                }
508                internalSet(param, val);
509                return flags;
510        }*/
511
512
513}
Note: See TracBrowser for help on using the repository browser.