source: java/main/src/main/java/com/framsticks/structure/Path.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: 9.3 KB
Line 
1package com.framsticks.structure;
2
3import com.framsticks.params.Access;
4import com.framsticks.params.CompositeParam;
5import com.framsticks.params.Param;
6import com.framsticks.params.ParamCollection;
7import com.framsticks.util.ExceptionHandler;
8import com.framsticks.util.FramsticksException;
9import com.framsticks.util.dispatching.Dispatching;
10import com.framsticks.util.dispatching.IgnoreExceptionHandler;
11import com.framsticks.util.lang.Pair;
12
13import java.util.Iterator;
14import java.util.LinkedList;
15import java.util.List;
16import java.util.regex.Pattern;
17
18import javax.annotation.Nonnull;
19import javax.annotation.concurrent.Immutable;
20
21import org.apache.commons.collections.ListUtils;
22
23/**
24 * @author Piotr Sniegowski
25 */
26@Immutable
27public final class Path implements ParamCollection {
28        // private final static Logger log = LogManager.getLogger(Path.class.getName());
29
30        final Tree tree;
31        final String textual;
32        final LinkedList<Node> nodes;
33
34        public static final SideNoteKey<CompositeParam> OBJECT_PARAM_KEY = SideNoteKey.make(CompositeParam.class);
35
36        protected static Object getKnownChild(Tree tree, Access access, CompositeParam param, ExceptionHandler handler) {
37                Object child = access.get(param, Object.class);
38                if (child == null) {
39                        return null;
40                }
41                try {
42                        tree.prepareAccess(param);
43                        tree.putSideNote(child, OBJECT_PARAM_KEY, param);
44                        return child;
45                } catch (FramsticksException e) {
46                        handler.handle(e);
47                }
48                return null;
49        }
50
51        /**
52         * @param tree
53         * @param textual
54         * @param nodes
55         */
56        Path(Tree tree, String textual, LinkedList<Node> nodes) {
57                this.tree = tree;
58                this.textual = textual;
59                this.nodes = nodes;
60        }
61
62        public Path appendNode(Node node) {
63                assert isResolved();
64                return new PathBuilder().tree(tree).textual(textual + ((size() == 1) ? "" : "/") + node.getParam().getId()).add(nodes).add(node).finish();
65        }
66
67        public Path appendParam(CompositeParam param) {
68                assert isResolved();
69                return appendNode(new Node(tree, param, null));
70        }
71
72        public static class PathBuilder {
73
74                Tree tree;
75                String textual;
76                final LinkedList<Node> nodes = new LinkedList<Node>();
77
78                public Path finish() {
79                        assert tree != null;
80                        assert textual != null;
81                        return new Path(tree, textual, nodes);
82                }
83
84                public PathBuilder()
85                {
86                }
87
88                public PathBuilder tree(Tree tree) {
89                        this.tree = tree;
90                        return this;
91                }
92
93                public PathBuilder textual(String textual) {
94                        this.textual = textual;
95                        return this;
96                }
97
98                public PathBuilder add(List<Node> nodes) {
99                        this.nodes.addAll(nodes);
100                        return this;
101                }
102
103                public PathBuilder add(Node node) {
104                        this.nodes.add(node);
105                        return this;
106                }
107
108                public PathBuilder setLast(Object object) {
109                        Node n = nodes.pollLast();
110                        nodes.add(new Node(n.getTree(), n.getParam(), object));
111                        return this;
112                }
113
114                public PathBuilder buildUpTo(List<Node> nodes, Node node) {
115                        StringBuilder b = new StringBuilder();
116                        boolean add = false;
117                        for (Node n : nodes) {
118                                this.nodes.add(n);
119                                if (add) {
120                                        b.append("/").append(n.getParam().getId());
121                                }
122                                add = true;
123                                if (n == node) {
124                                        break;
125                                }
126                        }
127                        this.textual = (nodes.size() == 1) ? "/" : b.toString();
128                        return this;
129                }
130
131                public static Iterator<String> splitPath(String path) {
132                        List<String> list = new LinkedList<String>();
133                        for (String s : path.split("/")) {
134                                if (!s.isEmpty()) {
135                                        list.add(s);
136                                }
137                        }
138                        return list.iterator();
139                }
140
141                public PathBuilder resolve(@Nonnull Tree tree, String textual) {
142                        return resolve(tree, textual, IgnoreExceptionHandler.getInstance());
143                }
144
145                public PathBuilder resolve(@Nonnull Tree tree, String textual, ExceptionHandler handler) {
146
147                        assert nodes.isEmpty();
148                        assert tree.isActive();
149                        this.tree = tree;
150
151                        Node current = tree.getAssignedRoot();
152                        nodes.add(current);
153
154                        StringBuilder b = new StringBuilder();
155                        Iterator<String> i = splitPath(textual);
156                        while (i.hasNext() && current.getObject() != null) {
157                                Access access = TreeOperations.bindAccess(current);// tree.prepareAccess(current.getParam());
158                                String e = i.next();
159                                Param p = access.getParam(e);
160                                if (p == null) {
161                                        break;
162                                }
163                                if (!(p instanceof CompositeParam)) {
164                                        throw new FramsticksException().msg("param is not a composite").arg("param", p).arg("tree", tree).arg("textual", textual).arg("access", access);
165                                }
166                                CompositeParam c = (CompositeParam) p;
167                                b.append("/").append(e);
168                                access.select(current.getObject());
169                                tree.putSideNote(current.getObject(), OBJECT_PARAM_KEY, current.getParam());
170                                current = new Node(current.getTree(), c, getKnownChild(tree, access, c, handler));
171                                nodes.add(current);
172                        }
173                        this.textual = (nodes.size() == 1) ? "/" : b.toString();
174
175                        return this;
176                }
177        }
178
179        public static PathBuilder build() {
180                return new PathBuilder();
181        }
182
183        public Path appendResolution(Object object) {
184                assert !isResolved();
185                Path result = new PathBuilder().textual(textual).tree(tree).add(nodes).setLast(object).finish();
186                assert size() == result.size();
187                return result;
188        }
189
190        public final Object getTopObject() {
191                return getTop().getObject();
192        }
193
194        public final Node getTop() {
195                return nodes.getLast();
196        }
197
198        public final Node getUnder() {
199                assert nodes.size() >= 2;
200                return nodes.get(nodes.size() - 2);
201        }
202
203        public final String getTextual() {
204                return textual;
205        }
206
207        public String toString() {
208                return tree + textual + (!isResolved() ? "!" : "");
209        }
210
211        public String getFullTextual() {
212                return tree.getName() + textual;
213        }
214
215        public final int size() {
216                assert Dispatching.isThreadSafe();
217                return nodes.size();
218        }
219
220        public final boolean isResolved() {
221                assert Dispatching.isThreadSafe();
222                return getTop().getObject() != null;
223        }
224
225        public final boolean isResolved(String textual) {
226                assert Dispatching.isThreadSafe();
227                return isTheSame(textual) && isResolved();
228        }
229
230        public final boolean isTheSame(String textual) {
231                assert Dispatching.isThreadSafe();
232                return this.textual.equals(textual);
233        }
234
235        public final boolean isTheSameTextually(Path path) {
236                assert Dispatching.isThreadSafe();
237                return (tree == path.getTree()) && textual.equals(path.getTextual());
238        }
239
240        public final @Nonnull Tree getTree() {
241                assert Dispatching.isThreadSafe();
242                return tree;
243        }
244
245        public Path tryResolveIfNeeded() {
246                if (isResolved()) {
247                        return this;
248                }
249                return tryFindResolution();
250        }
251
252        /** Attach resolution at end, if available.
253         *
254         * @return Modified path, if resolution was available, this otherwise.
255         */
256        public Path tryFindResolution() {
257                assert tree.isActive();
258                assert !isResolved();
259                if (size() == 1) {
260                        return Path.build().resolve(tree, "/").finish();
261                }
262                Object child = getKnownChild(tree, TreeOperations.bindAccess(getUnder()), getTop().getParam(), IgnoreExceptionHandler.getInstance());
263                if (child == null) {
264                        return this;
265                }
266                return appendResolution(child);
267        }
268
269
270        public String getLastElement() {
271                return getTop().getParam().getId();
272        }
273
274        public final boolean isOwner(Tree tree) {
275                return this.tree == tree;
276        }
277
278        @SuppressWarnings("unchecked")
279        public
280        List<Node> getNodes() {
281                return ListUtils.unmodifiableList(nodes);
282        }
283
284        public Path assureResolved() {
285                if (!isResolved()) {
286                        throw new FramsticksException().msg("path is not resolved").arg("path", this);
287                }
288                return this;
289        }
290
291        public static Path tryTo(@Nonnull Tree tree, String textual) {
292                return Path.build().resolve(tree, textual).finish();
293        }
294
295        public static Path to(@Nonnull Tree tree, String textual) {
296                Path path = tryTo(tree, textual);
297                if (path.getTextual().equals(textual)) {
298                        return path;
299                }
300                throw new FramsticksException().msg("failed to create path").arg("textual", textual).arg("result", path).arg("tree", tree);
301        }
302
303        public boolean isTheSameObjects(Path path) {
304                if (tree != path.getTree()) {
305                        return false;
306                }
307                if (size() != path.size()) {
308                        return false;
309                }
310                if (!getTextual().equals(path.getTextual())) {
311                        return false;
312                }
313                Iterator<Node> a = nodes.iterator();
314                Iterator<Node> b = path.getNodes().iterator();
315                while (a.hasNext()) {
316                        assert b.hasNext();
317                        if (a.next() != b.next()) {
318                                return false;
319                        }
320                }
321                return true;
322        }
323
324        public static final Pattern pathPattern = Pattern.compile("(\\/)|((\\/[^/]+)+)");
325
326        public static boolean isValidString(String path) {
327                return pathPattern.matcher(path).matches();
328        }
329
330        public static String appendString(String path, String element) {
331                if (path.equals("/")) {
332                        return path + element;
333                }
334                return path + "/" + element;
335        }
336
337        public static Pair<String, String> removeLastElement(String path) {
338                assert isValidString(path);
339                if (path.equals("/")) {
340                        throw new FramsticksException().msg("cannot remove last element from root path");
341                }
342                int index = path.lastIndexOf('/');
343                assert index != -1;
344                if (index == 0) {
345                        return new Pair<String, String>("/", path.substring(1));
346                }
347                return new Pair<String, String>(path.substring(0, index), path.substring(index + 1));
348        }
349
350        public static String validateString(String path) {
351                if (!isValidString(path)) {
352                        throw new FramsticksException().msg("path string validation failured").arg("path", path);
353                }
354                return path;
355        }
356
357        @Override
358        public Param getParam(int i) {
359                return TreeOperations.getFramsClass(this).getParam(i);
360        }
361
362        @Override
363        public Param getParam(String id) {
364                return TreeOperations.getFramsClass(this).getParam(id);
365        }
366
367        @Override
368        public int getParamCount() {
369                return TreeOperations.getFramsClass(this).getParamCount();
370        }
371
372        @Override
373        public Iterable<Param> getParams() {
374                return TreeOperations.getFramsClass(this).getParams();
375        }
376        // public boolean isEmpty() {
377        //      return nodes.isEmpty();
378        // }
379
380}
381
Note: See TracBrowser for help on using the repository browser.