source: java/main/src/main/java/com/framsticks/parsers/F0Parser.java @ 85

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

HIGHLIGHTS:

  • upgrade to Java 7
    • use try-multi-catch clauses
    • use try-with-resources were appropriate
  • configure FindBugs? (use mvn site and then navigate in browser to the report)
    • remove most bugs found
  • parametrize Dispatching environment (Dispatcher, RunAt?) to enforce more control on the place of closures actual call

CHANGELOG:
Rework FavouritesXMLFactory.

FindBugs?. Thread start.

FindBugs?. Minor change.

FindBugs?. Iterate over entrySet.

FindBugs?. Various.

FindBug?.

FindBug?. Encoding.

FindBug?. Final fields.

FindBug?.

Remove synchronization bug in ClientConnection?.

Experiments with findbugs.

Finish parametrization.

Make RunAt? an abstract class.

More changes in parametrization.

More changes in parametrizing dispatching.

Several changes to parametrize tasks.

Rename Runnable to RunAt?.

Add specific framsticks Runnable.

Add JSR305 (annotations).

Add findbugs reporting.

More improvements to ParamBuilder? wording.

Make FramsClass? accept also ParamBuilder?.

Change wording of ParamBuilder?.

Change wording of Request creation.

Use Java 7 exception catch syntax.

Add ScopeEnd? class.

Upgrade to Java 7.

File size: 7.8 KB
Line 
1package com.framsticks.parsers;
2
3import java.io.BufferedReader;
4import java.io.IOException;
5import java.io.InputStream;
6import java.io.InputStreamReader;
7import java.text.ParseException;
8import java.util.ArrayList;
9import java.util.Collection;
10import java.util.List;
11
12import com.framsticks.model.Model;
13import static com.framsticks.params.SimpleAbstractAccess.*;
14
15import com.framsticks.params.Flags;
16import com.framsticks.params.Param;
17import com.framsticks.params.PrimitiveParam;
18import com.framsticks.util.lang.Containers;
19import com.framsticks.util.lang.Exceptions;
20import com.framsticks.util.lang.Pair;
21import com.framsticks.util.lang.Strings;
22import org.apache.log4j.Logger;
23
24import com.framsticks.params.FramsClass;
25import com.framsticks.params.AccessInterface;
26
27/**
28 * The class Parser is used to parse genotype encoded in f0 representation.
29 */
30public class F0Parser {
31
32        private final static Logger log = Logger.getLogger(F0Parser.class);
33
34        /** The schema proper for f0 representation. */
35        protected final Schema schema;
36        protected final InputStream is;
37        protected final List<AccessInterface> result = new ArrayList<AccessInterface>();
38        int lineNumber = 0;
39
40        public F0Parser(Schema schema, InputStream is) {
41                assert schema != null;
42                assert is != null;
43                this.schema = schema;
44                this.is = is;
45        }
46
47        protected AccessInterface processLine(String line) {
48                try {
49
50                        Pair<String, String> p = Strings.splitIntoPair(line, ':', "");
51                        String classId = p.first.trim();
52                        FramsClass framsClass = schema.getRegistry().getInfoFromCache(classId);
53                        if (framsClass == null) {
54                                throw new Exception("unknown class id: " + classId);
55                        }
56                        AccessInterface access = schema.getRegistry().createAccess(classId, framsClass);
57                        access.select(access.createAccessee());
58                        for (Exception e : loadFromLine(access, p.second)) {
59                                warn(lineNumber, "however entry was added", e);
60                        }
61                        return access;
62                } catch (Exception e) {
63                        warn(lineNumber, "entry was not added", e);
64                }
65                return null;
66        }
67
68        /**
69         * Parses the stream with genotype in f0 representation. The correctness of
70         * genotype is checked. IO and syntax exceptions interrupts parsing and no
71         * result is returned. Other exceptions, connected with schema validation
72         * cause that certain object or it's parameter is ignored (appropriate
73         * communicate informs user about it). Inappropriate values in numeric
74         * fields (bigger than maximum or smaller than minimum values) are
75         * communicated by warnings and set to minimum / maximum value.
76         *
77         * @return the list
78         * @throws IOException
79         *             Signals that an I/O exception has occurred.
80         * @throws ParseException
81         *             the parse exception
82         */
83        public List<AccessInterface> parse() throws IOException,
84                        ParseException {
85
86                try (InputStreamReader reader = new InputStreamReader(is, "UTF-8")) {
87                        BufferedReader br = new BufferedReader(reader);
88                        while (br.ready()) {
89                                ++lineNumber;
90                                String line = br.readLine();
91                                line = (line == null ? "" : line.trim());
92                                if (lineNumber == 1) {
93                                        if (!"//0".equals(line)) {
94                                                log.warn("stream should begin with \"//0\" in the first line");
95                                        } else {
96                                                continue;
97                                        }
98                                }
99                                if (line.equals("")) {
100                                        continue;
101                                }
102                                if (line.startsWith("#")) {
103                                        continue;
104                                }
105                                AccessInterface access = processLine(line);
106                                if (access != null) {
107                                        result.add(access);
108                                }
109                        }
110
111                        /** If no 'm' (Model) line was found, than simulate it on the beginning of the result.*/
112                        if (result.isEmpty() || !(result.get(0) instanceof Model)) {
113                                result.add(0, processLine("m:"));
114                        }
115                }
116
117                return result;
118        }
119
120        private static void warn(int lineNumber, String message, Exception e) {
121                log.warn("in line " + lineNumber + " the following error occurred (" + message + "): " + e + "\n" + Exceptions.printStackTrace(e));
122        }
123
124        /** Breaks string into entries.*/
125        public List<Entry> breakIntoEntries(String parameters) throws Exception {
126                // tokenize
127                boolean inQuotes = false;
128                char previousChar = ',';
129                List<Entry> result = new ArrayList<Entry>();
130                StringBuilder stringBuilder = new StringBuilder();
131                String key = null;
132                if (parameters.trim().length() > 0) {
133                        for (char currentChar : parameters.toCharArray()) {
134                                if (!inQuotes && (currentChar == '=') && (key == null)) {
135                                        key = stringBuilder.toString().trim();
136                                        stringBuilder = new StringBuilder();
137                                } else if (!inQuotes && currentChar == ',') {
138                                        if (previousChar == ',') {
139                                                result.add(new Entry(key, null));
140                                        } else {
141                                                result.add(new Entry(key, stringBuilder.toString().trim()));
142                                        }
143                                        stringBuilder = new StringBuilder();
144                                        key = null;
145                                } else if (currentChar == '"') {
146                                        if (previousChar == '\\') {
147                                                stringBuilder.deleteCharAt(stringBuilder.length() - 1);
148                                                stringBuilder.append(currentChar);
149                                        } else {
150                                                inQuotes = !inQuotes;
151                                        }
152                                } else {
153                                        stringBuilder.append(currentChar);
154                                }
155
156                                previousChar = currentChar;
157                        }
158
159                        result.add(new Entry(key, stringBuilder.toString().trim()));
160
161                        if (inQuotes) {
162                                throw new Exception("Double quotes expected while end of line met");
163                        }
164                }
165                return result;
166        }
167
168        public List<Exception> loadFromLine(AccessInterface access, String parameters) throws Exception {
169
170                List<Entry> entries = breakIntoEntries(parameters);
171
172                List<Exception> exceptions = new ArrayList<Exception>();
173
174                Collection<Param> paramsC = access.getParams();
175                Param[] params = paramsC.toArray(new Param[] {null});
176                if (params.length == 0) {
177                        return exceptions;
178                }
179                for (PrimitiveParam p : Containers.filterInstanceof(paramsC, PrimitiveParam.class)) {
180                        Object def = p.getDef(Object.class);
181                        if (def != null) {
182                                access.set(p, def);
183                        }
184                }
185
186                int number = -1;
187                Integer nextParamNumber = 0;
188                for (Entry pair : entries) {
189                        ++number;
190                        try {
191                                Param currentParam;
192                                if (pair.key != null) {
193                                        currentParam = access.getParam(pair.key);
194                                        if (currentParam == null) {
195                                                nextParamNumber = null;
196                                                throw new Exception("no parameter with such id: " + pair.key);
197                                        }
198                                } else {
199                                        if (nextParamNumber == null || ((params[nextParamNumber].getFlags() & Flags.CANOMITNAME) == 0)) {
200                                                nextParamNumber = null;
201                                                throw new Exception(
202                                                                "parameter with offset: "
203                                                                                + number
204                                                                                + " is not set, "
205                                                                                + "because it's definition or definition of the previous param "
206                                                                                + "does not contain flag, which allows to skip the name (flag 1024)");
207                                        }
208                                        currentParam = params[nextParamNumber];
209                                }
210                                if (currentParam != null) {
211                                        if (pair.value != null) {
212                                                PrimitiveParam vp = (PrimitiveParam) currentParam;
213                                                int setFlag = access.set(vp, pair.value);
214                                                if ((setFlag & Flags.PSET_HITMIN) != 0) {
215                                                        exceptions.add(createBoundaryHitException(access, vp, pair.value, Flags.PSET_HITMIN));
216                                                }
217
218                                                if ((setFlag & Flags.PSET_HITMAX) != 0) {
219                                                        exceptions.add(createBoundaryHitException(access, vp, pair.value, Flags.PSET_HITMAX));
220                                                }
221
222                                                if ((setFlag & Flags.PSET_RONLY) != 0) {
223                                                        throw (new Exception("tried to set a read-only attribute \""
224                                                                + currentParam.getId()
225                                                                + "\" in class \"" + access.getId() + "\""));
226                                                }
227                                        }
228                                        nextParamNumber = null;
229                                        for (int j = params.length - 1; j > 0; --j) {
230                                                if (params[j - 1] == currentParam) {
231                                                        nextParamNumber = j;
232                                                }
233                                        }
234                                }
235
236                        } catch (Exception e) {
237                                exceptions.add(e);
238                        }
239                }
240                return exceptions;
241        }
242
243        private static Exception createBoundaryHitException(AccessInterface access, PrimitiveParam param, String value, int flag) {
244                boolean minimum = (flag & Flags.PSET_HITMIN) != 0;
245                String boundary = (minimum ? param.getMin(Object.class) : param.getMax(Object.class)).toString();
246                String name =  (minimum ? "minimum" : "maximum");
247                return new Exception("Tried to set attribute \""
248                                + param.getId()
249                                + "\" in class \""
250                                + access.getId()
251                                + "\" to value which exceeds " + name + " ("
252                                + value
253                                + "), truncated to: "
254                                + boundary);
255        }
256}
Note: See TracBrowser for help on using the repository browser.