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

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

HIGHLIGHTS:

  • loading f0 schema with XmlLoader?
  • use XmlLoader? to load configuration
  • introduce unified fork-join model of various entities

(Instances, Connections, GUI Frames, etc.),
all those entities clean up gracefully on
shutdown, which may be initialized by user
or by some entity

  • basing on above, simplify several organizing classes

(Observer, main class)

(to host native frams server process from Java level)

CHANGELOG:
Remove redundant Observer class.

Clean up in AbstractJoinable?.

Update ExternalProcess? class to changes in joining model.

Another sweep through code with FindBugs?.

Find bug with not joining RemoteInstance?.

Joining almost works.

Much improved joining model.

More improvement to joining model.

Add logging messages around joinable operations.

Rename methods in AbstractJoinable?.

Improve Joinable.

Rewrite of entity structure.

More simplifications with entities.

Further improve joinables.

Let Frame compose from JFrame instead of inheriting.

Add join classes.

Improvements of closing.

Add Builder interface.

Add FramsServerTest?.xml

FramsServer? may be configured through xml.

Make Framsticks main class an Observer of Entities.

Make Observer a generic type.

Remove variables regarding to removed endpoint.

Simplify observer (remove endpoints).

More changes to Observer and Endpoint.

Minor improvements.

Add OutputListener? to ExternalProcess?.

Improve testing of ExternalProcess?.

Add ExternalProcess? runner.

Rename the Program class to Framsticks.

Migrate Program to use XmlLoader? configuration.

First steps with configuration using XmlLoader?.

Fix several bugs.

Move all f0 classes to apriopriate package.

XmlLoader? is able to load Schema.

XmlLoader? is loading classes and props.

Add GroupBuilder?.

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