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

Last change on this file since 193 was 193, checked in by Maciej Komosinski, 10 years ago

Set svn:eol-style native for all textual files

  • Property svn:eol-style set to native
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.