source: java/main/src/main/java/com/framsticks/parsers/MultiParamLoader.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: 9.7 KB
Line 
1package com.framsticks.parsers;
2
3import com.framsticks.params.*;
4import org.apache.log4j.Logger;
5
6import java.io.FileNotFoundException;
7import java.io.IOException;
8import java.util.*;
9
10public class MultiParamLoader {
11
12        public interface StatusListener {
13                void onStatusChange();
14        }
15
16        private final static Logger log = Logger.getLogger(MultiParamLoader.class);
17
18        /**
19         * The class which name was recently found in the file, to which execution
20         * should be passed.
21         */
22        public AccessInterface getLastAccessInterface() {
23                return lastAccessInterface;
24        }
25
26        /** TODO does it support multilines? */
27        /**
28         * Specifies the condition to break execution.
29         */
30        public enum Status {
31                None, Finished, BeforeObject, AfterObject, BeforeUnknown, OnComment, OnError, Loading
32        }
33
34        protected final Map<Status, List<StatusListener>> listeners = new HashMap<>();
35
36        /**
37         * Specifies the action that should be taken inside loops.
38         */
39        private enum LoopAction {
40                Nothing, Break, Continue
41        }
42
43        protected AccessInterface lastAccessInterface;
44
45        protected static final FramsClass emptyFramsClass = FramsClass.build().idAndName("<empty>").finish();
46        /**
47         * Empty Param representing unknown classes - used to omit unknown
48         * objects in the file.
49         */
50        protected AccessInterface emptyParam = new PropertiesAccess(emptyFramsClass);
51
52        /**
53         * Last comment found in the file.
54         */
55        protected String lastComment;
56
57        /**
58         * Set of break conditions.
59         */
60        private EnumSet<Status> breakConditions = EnumSet.of(Status.None);
61
62        /**
63         * Status of current execution.
64         */
65        private Status status = Status.None;
66
67
68        /**
69         * File from which data should be read.
70         */
71        private SourceInterface currentSource;
72
73        protected String currentLine;
74
75
76        /**
77         * All the files read by the loader (there could be many of them because of
78         * '#|include').
79         */
80        private Stack<String> fileStack = new Stack<String>();
81
82        /**
83         * A map that specifies connection between the getName of the file and the
84         * actual reader.
85         */
86        private Map<String, SourceInterface> fileMap = new HashMap<String, SourceInterface>();
87
88        /**
89         * List of known classes.
90         */
91        private Map<String, AccessInterface> knownParamInterfaces = new HashMap<String, AccessInterface>();
92
93        /**
94         * Last unknown object found in the file.
95         */
96        private String lastUnknownObjectName;
97
98        /**
99         * @return the currentLine
100         */
101        public String getCurrentLine() {
102                return currentLine;
103        }
104
105        public MultiParamLoader() {
106
107        }
108
109        /**
110         * Starts reading the file.
111         */
112        public Status go() throws Exception {
113                log.trace("go");
114
115                while (!isFinished()) {
116                        // check if we are before some known or unknown object
117                        LoopAction loopAction = tryReadObject();
118                        if (loopAction == LoopAction.Break) {
119                                break;
120                        } else if (loopAction == LoopAction.Continue) {
121                                continue;
122                        }
123
124                        // read data
125                        currentLine = currentSource.readLine();
126
127                        // end of file
128                        if (currentLine == null) {
129                                if (!returnFromIncluded()) {
130                                        finish();
131                                        break;
132                                } else {
133                                        continue;
134                                }
135                        }
136                        log.trace("read line: " + currentLine);
137
138                        // empty line
139                        if (currentLine.length() == 0) {
140                                continue;
141                        }
142
143                        // check if some file should be included
144                        if (isIncludeLine(currentLine) == LoopAction.Continue) {
145                                continue;
146                        }
147
148                        // check if should break on comment
149                        if (isCommentLine(currentLine) == LoopAction.Break) {
150                                break;
151                        }
152
153                        // get class getName
154                        LoopAction action = changeCurrentParamInterface(currentLine);
155                        if (action == LoopAction.Break) {
156                                break;
157                        }
158                        if (action == LoopAction.Continue) {
159                                continue;
160                        }
161                        log.warn("unknown line: " + currentLine);
162                }
163
164                return status;
165        }
166
167        /**
168         * Checks whether the reader found a known or unknown object and execution
169         * should be passed to it.
170         * @throws Exception
171         */
172        private LoopAction tryReadObject() throws Exception {
173                if (status == Status.BeforeObject
174                                || (status == Status.BeforeUnknown && lastAccessInterface != null)) {
175                        // found object - let it load data
176                        if (lastAccessInterface.getSelected() == null) {
177                                lastAccessInterface.select(lastAccessInterface.createAccessee());
178                        }
179                        log.trace("loading into " + lastAccessInterface);
180                        lastAccessInterface.load(currentSource);
181
182                        if (changeStatus(Status.AfterObject)) {
183                                return LoopAction.Break;
184                        }
185                        return LoopAction.Continue;
186                } else if (status == Status.BeforeUnknown) {
187                        log.warn("omitting unknown object: " + lastUnknownObjectName);
188
189                        // found unknown object
190                        emptyParam.load(currentSource);
191                        if (changeStatus(Status.AfterObject)) {
192                                return LoopAction.Break;
193                        }
194                        return LoopAction.Continue;
195                }
196
197                return LoopAction.Nothing;
198        }
199
200        /**
201         * Checks whether some additional file shouldn't be included.
202         */
203        private LoopAction isIncludeLine(String line) throws FileNotFoundException {
204                try {
205                        // found comment
206                        if (line.charAt(0) == '#') {
207                                // maybe we should include something
208                                if (line.substring(1, 8).equals("include")) {
209                                        int beg = line.indexOf('\"');
210                                        if (beg == -1) {
211                                                log.info("Wanted to include some file, but the format is incorrect");
212                                                return LoopAction.Continue;
213                                        }
214
215                                        String includeFileName = line.substring(beg + 1);
216                                        int end = includeFileName.indexOf('\"');
217                                        if (end == -1) {
218                                                log.info("Wanted to include some file, but the format is incorrect");
219                                                return LoopAction.Continue;
220                                        }
221
222                                        includeFileName = includeFileName.substring(0, end);
223
224                                        include(includeFileName);
225
226                                        return LoopAction.Continue;
227                                }
228                        }
229                } catch (IndexOutOfBoundsException ex) {
230                        // value after # sign is shorter than expected 7 characters - do
231                        // nothing
232                }
233
234                return LoopAction.Nothing;
235        }
236
237        /**
238         * Checks whether execution shouldn't break on comment.
239         */
240        private LoopAction isCommentLine(String line) {
241                if (line.charAt(0) == '#') {
242                        lastComment = line;
243                        if (changeStatus(Status.OnComment)) {
244                                // it's a simple comment - maybe we should break?
245                                return LoopAction.Break;
246                        }
247                }
248                return LoopAction.Nothing;
249        }
250
251        /**
252         * Gets the getName of the class from line read from file.
253         */
254        private LoopAction changeCurrentParamInterface(String line) {
255                // found key - value line
256                if (line.charAt(line.length() - 1) == ':') {
257                        String typeName = line.substring(0, line.length() - 1);
258                        lastAccessInterface = knownParamInterfaces.get(typeName);
259
260                        if (lastAccessInterface != null) {
261                                if (changeStatus(Status.BeforeObject)) {
262                                        return LoopAction.Break;
263                                } else {
264                                        return LoopAction.Continue;
265                                }
266                        } else {
267                                lastUnknownObjectName = typeName;
268                                if (changeStatus(Status.BeforeUnknown)) {
269                                        return LoopAction.Break;
270                                } else {
271                                        return LoopAction.Continue;
272                                }
273                        }
274                }
275                return LoopAction.Nothing;
276        }
277
278        /**
279         * Adds another break condition.
280         */
281        public void addBreakCondition(Status condition) {
282                breakConditions.add(condition);
283        }
284
285        /**
286         * Removes break condition.
287         */
288        public void removeBreakCondition(Status condition) {
289                breakConditions.remove(condition);
290        }
291
292        /**
293         * Adds another class.
294         */
295        public void addAccessInterface(AccessInterface accessInterface) {
296                /**TODO: by id or by name? rather by id, because from file is always lowercase*/
297                knownParamInterfaces.put(accessInterface.getId(), accessInterface);
298        }
299
300        /**
301         * Checks whether execution is finished.
302         */
303        private boolean isFinished() {
304                return (status == Status.Finished);
305        }
306
307        private void finish() {
308                log.trace("finishing");
309                if (currentSource != null) {
310                        currentSource.close();
311                }
312
313                changeStatus(Status.Finished);
314        }
315
316        /**
317         * Opens selected file.
318         */
319
320        public boolean setNewSource(SourceInterface source) {
321                log.debug("switching current source to " + source.getFilename() + "...");
322
323                currentSource = source;
324                changeStatus(Status.Loading);
325
326                return true;
327        }
328
329        /**
330         * Includes specified file.
331         */
332        private void include(String includeFilename) {
333
334                includeFilename = currentSource.demangleInclude(includeFilename);
335
336                if (includeFilename == null) {
337                        return;
338                }
339                // check if it is already included and break if it is
340                if (isAlreadyIncluded(includeFilename)) {
341                        log.debug("circular reference ignored (" + includeFilename
342                                        + ")");
343                        return;
344                }
345
346                log.info("including file " + includeFilename + "...");
347
348                SourceInterface newSource = currentSource.openInclude(includeFilename);
349                if (newSource == null) {
350                        return;
351                }
352
353                fileStack.add(currentSource.getFilename());
354                fileMap.put(currentSource.getFilename(), currentSource);
355                setNewSource(newSource);
356
357        }
358
359        /**
360         * Checks whether selected file was already included.
361         */
362        private boolean isAlreadyIncluded(String filename) {
363                for (String file : fileStack) {
364                        if (filename.equals(file)) {
365                                log.warn("file " + filename + " was already included");
366                                return true;
367                        }
368                }
369
370                return false;
371        }
372
373        /**
374         * Returns from included file.
375         */
376        private boolean returnFromIncluded() throws IOException {
377                if (fileStack.size() == 0) {
378                        return false;
379                }
380
381                if (currentSource != null) {
382                        currentSource.close();
383                }
384
385                String filename = fileStack.pop();
386                currentSource = fileMap.get(filename);
387                fileMap.remove(filename);
388
389                return true;
390        }
391
392        /**
393         * Checks whether execution should break on selected condition.
394         */
395        private boolean changeStatus(Status status) {
396                log.trace("changing status: " + this.status.toString() + " -> " + status.toString());
397                this.status = status;
398                if (listeners.containsKey(status)) {
399                        for (StatusListener l : listeners.get(status)) {
400                                l.onStatusChange();
401                        }
402                }
403                return breakConditions.contains(status);
404        }
405
406        public Object returnObject() {
407                assert lastAccessInterface != null;
408                Object result = lastAccessInterface.getSelected();
409                if (result == null) {
410                        return null;
411                }
412                lastAccessInterface.select(null);
413                return result;
414        }
415
416        public void addListener(Status status, StatusListener listener) {
417                if (!listeners.containsKey(status)) {
418                        listeners.put(status, new LinkedList<StatusListener>());
419                }
420                listeners.get(status).add(listener);
421        }
422}
Note: See TracBrowser for help on using the repository browser.