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

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

HIGHLIGHTS:

  • add proper exception passing between communication sides:

if exception occur during handling client request, it is
automatically passed as comment to error response.

it may be used to snoop communication between peers

  • fix algorithm choosing text controls in GUI
  • allow GUI testing in virtual frame buffer (xvfb)

FEST had some problem with xvfb but workaround was found

supports tab-completion based on requests history

CHANGELOG:
Further improve handling of exceptions in GUI.

Add StatusBar? implementing ExceptionResultHandler?.

Make completion processing asynchronous.

Minor changes.

Improve completion in console.

Improve history in InteractiveConsole?.

First working version of DirectConsole?.

Minor changes.

Make Connection.address non final.

It is more suitable to use in configuration.

Improvement of consoles.

Improve PopupMenu? and closing of FrameJoinable?.

Fix BrowserTest?.

Found bug with FEST running under xvfb.

JButtonFixture.click() is not working under xvfb.
GuiTest? has wrapper which uses JButton.doClick() directly.

Store CompositeParam? param in TreeNode?.

Simplify ClientSideManagedConnection? connecting.

There is now connectedFunctor needed, ApplicationRequests? can be
send right after creation. They are buffered until the version
and features are negotiated.

Narow down interface of ClientSideManagedConnection?.

Allow that connection specialization send only
ApplicationRequests?.

Improve policy of text control choosing.

Change name of Genotype in BrowserTest?.

Make BrowserTest? change name of Genotype.

Minor change.

First working draft of TrackConsole?.

Simplify Consoles.

More improvements with gui joinables.

Unify initialization on gui joinables.

More rework of Frame based entities.

Refactorize structure of JFrames based entities.

Extract GuiTest? from BrowserBaseTest?.

Reorganize Console classes structure.

Add Collection view to JoinableCollection?.

Configure timeout in testing.

Minor changes.

Rework connections hierarchy.

Add Mode to the get operation.

Make get and set in Tree take PrimitiveParam?.

Unify naming of operations.

Make RunAt? use the given ExceptionHandler?.

It wraps the virtual runAt() method call with
try-catch passing exception to handler.

Force RunAt? to include ExceptionHandler?.

Improve ClientAtServer?.

Minor change.

Another sweep with FindBugs?.

Rename Instance to Tree.

Minor changes.

Minor changes.

Further clarify semantics of Futures.

Add FutureHandler?.

FutureHandler? is refinement of Future, that proxifies
exception handling to ExceptionResultHandler? given
at construction time.

Remove StateFunctor? (use Future<Void> instead).

Make Connection use Future<Void>.

Unparametrize *ResponseFuture?.

Remove StateCallback? not needed anymore.

Distinguish between sides of ResponseFuture?.

Base ResponseCallback? on Future (now ResponseFuture?).

Make asynchronous store taking Future for flags.

Implement storeValue in ObjectInstance?.

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