source: java/main/src/main/java/com/framsticks/structure/TreeOperations.java @ 105

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

HIGHLIGHTS:

  • import refactorization: move Tree, Path, etc.

from core to structure package

  • initial serialization implementation
  • improve PrimeExperiment? test
  • many organizational changes and convenience improvements

CHANGELOG:
Make registry in AbstractTree? final.

Move most classes from core to structure package.

Minor changes.

Switch names of Future and FutureHandler?.

Rename ExceptionResultHandler? to ExceptionHandler?.

Rename ExceptionHandler? to ExceptionDispatcherHandler?.

Fix bug in ParamCandidate? cache.

Add missing synchronization to the BufferedDispatcher?.

Develop @Serialized support.

Rework serialization further.

Add serialization/deserialization interface to ValueParam?.

Move getStorageType and isNumeric from Param down to params hierarchy.

Minor changes.

Improve param type induction.

Add TestSerializedClass? for testing new serialization.

Add info files gor GenePool? and Population.

Add standard.expt exemplary netfile.

Add type name field to PropertiesObject?.

Use PropertiesObject? for PropertiesAccess? instead of ordinary map.

Hide getFramsClass is several more places.

More unification accross FramsClass?, Access and Path.

Add ParamCollection?.

Simplify interface for getting params from FramsClass?, Access
or Path.

Make Access.call() interface variadic.

Add arguments(args) convenience wrapper around new Object[] {args}.

Upgrade to apache.commons.lang version 3.1

Minor improvement with Response constructors.

Develop proper result printing in ClientAtServer?.

Add experimentNetsave to PrimeExperiment?.

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