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

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

HIGHLIGHTS:

  • add auto loading and saving algorithms between

frams files format and Java classes

  • respect ValueChange? events in GUI (do not reload object)
  • support results of procedures in Java server
  • make Experiment automatically convert between frams file and NetFile? object
  • add MessageLogger? (compatible with original frams server messages)
  • WorkPackageLogic? now validates results, is able to discard them, reschedule

whole package, or only uncomputed remainder

CHANGELOG:
Show just a short description in PrimeExperiment?.

Add primes_changed event to the PrimeExperiment?.

Make WorkPackageLogic? robust to frams server returning invalid results.

Add MessageLogger? to logics.

Add NetFile? interface. Support Messages from server.

Minor changes to connections.

Merge results in the PrimeExperiment?.

More netload class->file conversion to Simulator.

Move netsave parsing to Simulator.

Fix bug with inverted ordering of events firing in Experiment.

Minor changes.

Minor logging changes.

Use AccessOperations?.convert in NetLoadSaveLogic?

NetLoadSaveLogic? now encloses the conversion.

Use more generic AccessOperations? saveAll and loadAll in PrimePackage?.

Add Result class for enclosing of call invocations' results.

Improve feature request handling in Connections.

Use AccessOperations?.convert in RemoteTree? events parsing.

Minor change.

Add some information params to Java server root and CLI objects.

A draft implementation of loadAll algorithm.

That algorithm tries to load objects into a tree structure.

Add AccessOperationsTest? test.

Develop WorkPackageLogic?.

  • add state tracking fields
  • add work package generation

Add utility class SimplePrimitive?.

Meant for Java backend classes, enclose a single primitive value
and set of listeners.

Improve primitive value refresh in GUI.

When ValueChange? found in called event, do not reload whole
object, but only update GUI (no communication is performed).

Use ValueChange? in the TestClass? test.

Minor changes.

Sending all packages in PrimeExperiment? to the frams servers.

Develop AccessOperations?.loadComposites().

Remove addAccess from MultiParamLoader? interface.

There is now no default AccessProvider? in MultiParamLoader?.
User must explicitely set AccessStash? or Registry.

Improve saving algorithms in AccessOperations?.

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