source: java/main/src/main/java/com/framsticks/parsers/MultiParamLoader.java @ 101

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

HIGHLIGHTS:

  • improve tree side notes
  • improve GUI layout
  • add foldable list of occured events to EventControl?
  • improve automatic type conversion in proxy listeners
  • implement several Access functionalities as algorithms independent of Access type
  • introduce draft base classes for distributed experiments
  • automatically register dependant Java classes to FramsClass? registry
  • add testing prime experiment and configuration
  • simplify and improve task dispatching

CHANGELOG:
Improve task dispatching in RemoteTree?.

GUI no longer hangs on connection problems.

Make all dispatchers joinables.

Refactorize Thread dispatcher.

Remove Task and PeriodicTask?.

Use Java utilities in those situations.

Reworking tasks dispatching.

Fix bug in EventControl? listener dispatching.

Minor improvements.

Add testing configuration for ExternalProcess? in GUI.

More improvement to prime.

Support for USERREADONLY in GUI.

Add that flag to various params in Java classes.

Remove redundant register clauses from several FramsClassAnnotations?.

Automatically gather and register dependant classes.

Add configuration for prime.

Improve Simulator class.

Add prime.xml configuration.

Introduce draft Experiment and Simulator classes.

Add prime experiment tests.

Enclose typical map with listeners into SimpleUniqueList?.

Needfile works in GUI.

Improve needfile handling in Browser.

More improvement with NeedFile?.

Implementing needfile.

Update test.

Rename ChangeEvent? to TestChangeEvent?.

Automatic argument type search in RemoteTree? listeners.

MultiParamLoader? uses AccessProvider?. By default old implementation
enclosed in AccessStash? or Registry.

Minor changes.

Rename SourceInterface? to Source.

Also improve toString of File and ListSource?.

Remove unused SimpleSource? class.

Add clearing in HistoryControl?.

Show entries in table at EventControl?.

Improve EventControl?.

Add listeners registration to EventControl?.

Add foldable table to HistoryControl?.

Add control row to Procedure and Event controls.

Improve layout of controls.

Another minor change to gui layout.

Minor improvement in the SliderControl?.

Minor changes.

Move ReflectionAccess?.Backend to separate file.

It was to cluttered.

Cleanup in ReflectionAccess?.

Move setMin, setMax, setDef to AccessOperations?.

Extract loading operation into AccessOperations?.

Append Framsticks to name of UnsupportedOperationException?.

The java.lang.UnsupportedOperationException? was shadowing this class.

Rename params.Util to params.ParamsUtil?.

Several improvements.

Minor changes.

Implement revert functionality.

Improve local changes management.

Minor improvement.

Remove methods rendered superfluous after SideNoteKey? improvement.

Improve SideNoteKey?.

It is now generic type, so explicit type specification at
call site is no more needed.

Introduce SideNoteKey? interface.

Only Objects implementing that key may be used as side note keys.

Minor improvements.

Use strings instead of ValueControls? in several gui mappings.

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