source: java/main/src/main/java/com/framsticks/core/TreeOperations.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: 12.0 KB
Line 
1package com.framsticks.core;
2
3import java.util.HashSet;
4import java.util.List;
5import java.util.Set;
6
7import javax.annotation.Nonnull;
8
9import org.apache.logging.log4j.Logger;
10import org.apache.logging.log4j.LogManager;
11
12import com.framsticks.communication.File;
13import com.framsticks.params.Access;
14import com.framsticks.params.CompositeParam;
15import com.framsticks.params.EventListener;
16import com.framsticks.params.FramsClass;
17import com.framsticks.params.ListAccess;
18import com.framsticks.params.Param;
19import com.framsticks.params.ParamBuilder;
20import com.framsticks.params.PrimitiveParam;
21import com.framsticks.params.PropertiesAccess;
22import com.framsticks.params.UniqueListAccess;
23import com.framsticks.params.ParamsUtil;
24import com.framsticks.params.types.EventParam;
25import com.framsticks.params.types.ObjectParam;
26import com.framsticks.params.types.ProcedureParam;
27import com.framsticks.parsers.Loaders;
28import com.framsticks.parsers.MultiParamLoader;
29import com.framsticks.util.FramsticksException;
30import com.framsticks.util.dispatching.Dispatching;
31import com.framsticks.util.dispatching.Future;
32import com.framsticks.util.dispatching.FutureHandler;
33import com.framsticks.util.dispatching.RunAt;
34
35import static com.framsticks.util.dispatching.Dispatching.*;
36
37public final class TreeOperations {
38
39        private static final Logger log = LogManager.getLogger(TreeOperations.class);
40
41        private TreeOperations() {
42        }
43
44        public static final SideNoteKey<Boolean> FETCHED_MARK = SideNoteKey.make(Boolean.class);
45
46        public static @Nonnull
47        FramsClass processFetchedInfo(Tree tree, File file) {
48                assert tree.isActive();
49                FramsClass framsClass = Loaders.loadFramsClass(file.getContent());
50                log.debug("process fetched info for {}: {}", tree, framsClass);
51                tree.putInfoIntoCache(framsClass);
52                return framsClass;
53        }
54
55        public static Path create(Path path) {
56                assert !path.isResolved();
57
58                Access access = path.getTree().prepareAccess(path.getTop().getParam());
59                Object child = createAccessee(path.getTree(), access);
60                assert child != null;
61                if (path.size() == 1) {
62                        path.getTree().assignRootObject(child);
63                } else {
64                        Access parentAccess = bindAccess(path.getUnder());
65
66                        /** this special case is not very good - maybe hide it in createAccessee? */
67                        if (parentAccess instanceof UniqueListAccess) {
68                                access.select(child);
69                                access.set(((UniqueListAccess) parentAccess).getUidName(), path.getTop().getParam().getId());
70                        }
71
72                        parentAccess.set(path.getTop().getParam(), child);
73                }
74                path = path.appendResolution(child);
75                return path;
76        }
77
78        public static void processFetchedValues(final Path path, final List<File> files, final Access access, final Future<Path> future) {
79                assert files.size() == 1;
80                assert path.isTheSame(files.get(0).getPath());
81
82                try {
83                        log.debug("process fetched values: {}", path);
84                        final Access parsingAccess = new PropertiesAccess(access.getFramsClass());
85                        final List<Object> results = MultiParamLoader.loadAll(files.get(0).getContent(), parsingAccess);
86
87                        Dispatching.dispatchIfNotActive(path.getTree(), new RunAt<Tree>(future) {
88                                @Override
89                                protected void runAt() {
90
91                                        Path result = path.tryResolveIfNeeded();
92
93                                        if (!result.isResolved()) {
94                                                result = create(result);
95                                        }
96
97                                        if (path.getTop().getParam() instanceof ObjectParam) {
98                                                assert results.size() == 1;
99                                                ParamsUtil.takeAllNonNullValues(bindAccess(result), parsingAccess.select(results.get(0)));
100                                                mark(result.getTree(), result.getTopObject(), FETCHED_MARK, true);
101                                                future.pass(result);
102                                                return;
103                                        }
104
105                                        final ListAccess listAccess = (ListAccess) access;
106
107                                        listAccess.select(result.getTopObject());
108                                        Set<String> oldValuesIds = new HashSet<>();
109                                        for (Param p : listAccess.getParams()) {
110                                                oldValuesIds.add(p.getId());
111                                        }
112
113                                        Access targetAccess = listAccess.getElementAccess();//.cloneAccess();
114
115                                        int number = 0;
116                                        for (Object r : results) {
117
118                                                parsingAccess.select(r);
119                                                String id;
120                                                if (listAccess instanceof UniqueListAccess) {
121                                                        id = parsingAccess.get(((UniqueListAccess) listAccess).getUidName(), String.class);
122                                                } else {
123                                                        id = Integer.toString(number);
124                                                }
125                                                ++number;
126
127                                                Object childTo = listAccess.get(id, Object.class);
128                                                boolean newOne;
129                                                if (childTo == null) {
130                                                        childTo = createAccessee(result.getTree(), targetAccess);
131                                                        newOne = true;
132                                                } else {
133                                                        assert oldValuesIds.contains(id);
134                                                        newOne = false;
135                                                }
136                                                oldValuesIds.remove(id);
137
138                                                targetAccess.select(childTo);
139                                                ParamsUtil.takeAllNonNullValues(targetAccess, parsingAccess);
140                                                if (newOne) {
141                                                        listAccess.set(id, childTo);
142                                                }
143                                                mark(result.getTree(), childTo, FETCHED_MARK, true);
144
145                                        }
146                                        mark(result.getTree(), result.getTopObject(), FETCHED_MARK, true);
147
148                                        /** It looks tricky for ArrayListAccess but should also work.
149                                         *
150                                         * They should be sorted.
151                                         */
152                                        for (String id : oldValuesIds) {
153                                                listAccess.set(id, null);
154                                        }
155                                        future.pass(result);
156                                }
157                        });
158
159                } catch (FramsticksException e) {
160                        throw new FramsticksException().msg("exception occurred while loading").cause(e);
161                }
162        }
163
164        public static FramsClass getInfo(Path path) {
165                Tree tree = path.getTree();
166                assert tree.isActive();
167                log.debug("get info for: {}", path);
168                final String name = path.getTop().getParam().getContainedTypeName();
169                return tree.getInfoFromCache(name);
170        }
171
172        public static void findInfo(final Path path, final Future<FramsClass> future) {
173                log.debug("find info for: {}", path);
174                try {
175                        Tree tree = path.getTree();
176                        assert tree.isActive();
177                        final FramsClass framsClass = getInfo(path);
178                        if (framsClass != null) {
179                                future.pass(framsClass);
180                                return;
181                        }
182                        tree.info(path, future);
183                } catch (FramsticksException e) {
184                        future.handle(e);
185                }
186        }
187
188        public static @Nonnull
189        Access bindAccessFromSideNote(Tree tree, Object object) {
190                CompositeParam param = tree.getSideNote(object, Path.OBJECT_PARAM_KEY);
191                if (param == null) {
192                        throw new FramsticksException().msg("failed to bind access from side node").arg("tree", tree).arg("object", object).arg("type", object.getClass());
193                }
194                return tree.prepareAccess(param).select(object);
195        }
196
197        public static @Nonnull
198        Access bindAccess(Tree tree, String path) {
199                log.debug("bind access for textual: {} in {}", path, tree);
200                return bindAccess(Path.to(tree, path));
201        }
202
203        public static @Nonnull
204        Access bindAccess(Node node) {
205                Tree tree = node.getTree();
206                assert tree.isActive();
207                assert node.getObject() != null;
208
209                try {
210                        Access access = tree.prepareAccess(node.getParam());
211                        tree.putSideNote(node.getObject(), Path.OBJECT_PARAM_KEY, node.getParam());
212
213                        return access.select(node.getObject());
214                } catch (FramsticksException e) {
215                        throw new FramsticksException().msg("failed to prepare access for param").arg("param", node.getParam()).cause(e);
216                        // log.error("failed to bind access for {}: ", node.getParam(), e);
217                }
218        }
219
220        public static @Nonnull
221        Access bindAccess(Path path) {
222                assert path.getTree().isActive();
223                path.assureResolved();
224                log.debug("bind access for: {}", path);
225                return bindAccess(path.getTop());
226        }
227
228        public static void set(final Path path, final PrimitiveParam<?> param, final Object value, final Future<Integer> future) {
229                final Tree tree = path.getTree();
230
231                dispatchIfNotActive(tree, new RunAt<Tree>(future) {
232                        @Override
233                        protected void runAt() {
234                                tree.set(path, param, value, future);
235                        }
236                });
237        }
238
239        public static void call(final Path path, final String procedureName, final Object[] arguments, final Future<Object> future) {
240                final Tree tree = path.getTree();
241
242                dispatchIfNotActive(tree, new RunAt<Tree>(future) {
243                        @Override
244                        protected void runAt() {
245                                path.assureResolved();
246                                tree.call(path, tree.getRegistry().getFramsClass(path.getTop().getParam()).getParamEntry(procedureName, ProcedureParam.class), arguments, future);
247                        }
248                });
249        }
250
251        public static void call(final Path path, final ProcedureParam param, final Object[] arguments, final Future<Object> future) {
252                final Tree tree = path.getTree();
253
254                dispatchIfNotActive(tree, new RunAt<Tree>(future) {
255                        @Override
256                        protected void runAt() {
257                                tree.call(path, param, arguments, future);
258                        }
259                });
260        }
261
262        public static <A> void addListener(final Path path, final EventParam param, final EventListener<A> listener, final Class<A> argument, final Future<Void> future) {
263                final Tree tree = path.getTree();
264
265                dispatchIfNotActive(tree, new RunAt<Tree>(future) {
266                        @Override
267                        protected void runAt() {
268                                tree.addListener(path, param, listener, argument, future);
269                        }
270                });
271        }
272
273        public static void removeListener(final Path path, final EventParam param, final EventListener<?> listener, final Future<Void> future) {
274                final Tree tree = path.getTree();
275
276                dispatchIfNotActive(tree, new RunAt<Tree>(future) {
277                        @Override
278                        protected void runAt() {
279                                tree.removeListener(path, param, listener, future);
280                        }
281                });
282        }
283
284        /**
285         *
286         * If StackOverflow occurs in that loop in LocalTree it is probably caused
287         * the by the fact, that get operation may find the object, but Path resolution
288         * cannot.
289         * */
290        public static void tryGet(final Tree tree, final String targetPath, final Future<Path> future) {
291                log.debug("resolve textual: {} for {}", targetPath, tree);
292                dispatchIfNotActive(tree, new RunAt<Tree>(future) {
293
294                        @Override
295                        protected void runAt() {
296                                final Path path = Path.tryTo(tree, targetPath).tryResolveIfNeeded();
297                                log.debug("found: {}", path);
298                                if (path.isResolved()) {
299                                        future.pass(path);
300                                        return;
301                                }
302
303                                tree.get(path, new FutureHandler<Path>(future) {
304                                        @Override
305                                        protected void result(Path result) {
306                                                // if (result.isResolved(targetPath)) {
307                                                //      future.pass(result);
308                                                //      return;
309                                                // }
310                                                log.debug("retrying resolve textual: {} for {} with {}", targetPath, tree, result);
311                                                tryGet(tree, targetPath, future);
312                                        }
313                                });
314                        }
315                });
316        }
317
318        public static FramsClass getInfoFromCache(Path path) {
319                assert path.getTree().isActive();
320                return path.getTree().getInfoFromCache(path.getTop().getParam().getContainedTypeName());
321        }
322
323        public static Object createAccessee(Tree tree, CompositeParam param) {
324                Object object = tree.prepareAccess(param).createAccessee();
325                tree.putSideNote(object, Path.OBJECT_PARAM_KEY, param);
326                return object;
327        }
328
329        public static Object createAccessee(Tree tree, Access access) {
330                Object object = access.createAccessee();
331                tree.putSideNote(object, Path.OBJECT_PARAM_KEY, access.buildParam(new ParamBuilder()).finish(CompositeParam.class));
332                return object;
333        }
334
335        public static boolean isMarked(Tree tree, Object object, SideNoteKey<Boolean> mark, boolean defValue) {
336                assert tree.isActive();
337                Boolean v = tree.getSideNote(object, mark);
338                return (v != null ? v : defValue);
339        }
340
341        public static void mark(Tree tree, Object object, SideNoteKey<Boolean> mark, boolean value) {
342                assert tree.isActive();
343                tree.putSideNote(object, mark, value);
344        }
345
346        public static FramsClass getFramsClass(Path path) {
347                return path.getTree().getRegistry().getFramsClass(path.getTop().getParam());
348        }
349
350        public static <T extends Param> T getParam(Path path, String id, Class<T> type) {
351                return getFramsClass(path).getParamEntry(id, type);
352        }
353
354        public static <T> T getOrCreateSideNote(Tree tree, Object object, SideNoteKey<T> key) {
355                T result = tree.getSideNote(object, key);
356                if (result == null) {
357                        result = key.newValue();
358                        tree.putSideNote(object, key, result);
359                }
360                return result;
361        }
362
363        public static <T> boolean hasSideNotes(Tree tree, Object object, SideNoteKey<T> key) {
364                return tree.getSideNote(object, key) != null;
365        }
366
367        public static <T> boolean hasSideNote(Path path, SideNoteKey<T> key) {
368                return path.getTree().getSideNote(path.getTopObject(), key) != null;
369        }
370
371        public static <T> T getSideNote(Path path, SideNoteKey<T> key) {
372                assert path.isResolved();
373                return path.getTree().getSideNote(path.getTopObject(), key);
374        }
375
376        public static <T> void putSideNote(Path path, SideNoteKey<T> key, T value) {
377                path.getTree().putSideNote(path.getTopObject(), key, value);
378        }
379
380        public static boolean removeSideNote(Path path, SideNoteKey<?> key) {
381                assert path.isResolved();
382                return path.getTree().removeSideNote(path.getTopObject(), key);
383        }
384
385}
Note: See TracBrowser for help on using the repository browser.