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