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

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

HIGHLIGTS:

  • complete events implementation
  • add CLI in Java Framsticks server
  • add automatic registration for events in GUI
  • improve objects fetching (object are never overwritten with new instances)
  • properly react for ListChange? events
  • add ListPanel? with table view
    • columns to be shown may be statically specified in configuration
    • currently modyfying data through tables is not available
  • improve maven configuration
    • configuration file may be specified without touching pom.xml

CHANGELOG:
Extract constants from Flags into ParamFlags? and SetStateFlags?.

Extract flags I/O to FlagsUtils? class.

Configured maven to exec given resource configuration.

For example:
mvn exec:exec -Dframsticks.config=/configs/managed-console.xml

Cleanup pom.xml

Rename ObjectTree? to LocalTree? (also make LocalTree? and RemoteTree? final).

Minor change.

Add maximum number of columns in ListPanelProvider?.

Improve ColumnsConfig? interpretation.

Automatically fill FramsClass?.name if trying to construct empty.

Improve identitifer case mangling in XmlLoader?.

Introduce configurable ColumnsConfig?.

Draft working version of ListPanel?.

Table is being shown (although empty).

More improvements to table building.

Move some functionality from Frame to TreeModel?.

Move tree classes in gui to separate package.

Remove old table related classes.

Add draft implementation of TableModel?.

Redirect ParamBuilder?.forAccess to AccessInterface?.

Optimize ParamBuilder?.forAccess()

Do not clear list when loading.

Do not load fetched values directly.

Implement different AccessInterface? copying policy.

Optimize fetching values routine.

Remove Mode enum (work out get semantics).

Some improvements to ListChange? handling.

Improve UniqueListAccess?.

Add reaction for ListChanges? in the TreeNode?.

EventListeners? are being added in the TreeNode?.

Listeners for ListParams? are now very naive (they download
whole list).

Automatially register on events in GUI.

Events are working in RemoteTree? and Server.

Move listeners to the ClientSideManagedConnection?.

Remove old classes responsible for event subscriptions.

Improve event reading.

Improve events handling at server side.

Add register attribute in FramsClassAnnotation?
to automatically also register other classes.

Registering events works.

Setup for remote listeners registration.

More improvements.

Minor changes.

Add rootTree to the ClientAtServer?.

Moving CLI to the ClientAtServer?.

Fix bug: use Void.TYPE instead of Void.class

More development around CLI.

  • Improve Path resolving.

Add synthetic root to ObjectTree?.

It is needed to allow sybling for the original root
that would containg CLI.

Some work with registering events in RemoteTree?.

Draft implementation of listener registering in RemoteTree?.

Support events registration in the ObjectTree?.

Add events support to ReflectionAccess?.

EventParam? is recognized by ParamCandidate?.

Prepare interface for Events across project.

Add EventListener? and API for listeners in Tree.

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