source: java/main/src/main/java/com/framsticks/core/Path.java @ 87

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

HIGHLIGHTS:

  • FramsClass? and contained Param are now immutable classes (like String),

which allows to refer to them concurrently without synchronization
(which for example in turn simplifies GUI management)

  • also make Path immutable (which was earlier only assumed)
  • add global cache for FramsClasses? created solely and automatically

on base of Java classes.

representations basing on given FramsClass?

  • above changes greatly improved GUI responsivness during browsing
  • furtherly improve Param class hierarchy
  • allow to inject actions on state changes into MultiParamLoader?
  • add more tests

CHANGELOG:

Add StatusListener? to MultiParamLoader?.

Minor refactorization in MultiParamLoader?.

First step with auto append.

Add SchemaTest?.

Improve Registry.

Clean up in Registry.

Work out Registry.

Use annotations for Param.

Fix ListChange?.

Improve fluent interface of the FramsClassBuilder?.

Done caching of ReflectionAccess?.Backend

Fix hashCode of Pair.

A step on a way to cache ReflectionAccess?.Backend

Make SimpleAbstractAccess?.framsClass a final field.

Add static cache for FramsClasses? based on java.

Only classes created strictly and automatically
based on java classes are using this cache.

Make all Params immutable.

Many improvement to make Param immutable.

Make PrimitiveParam? generic type.

Several changes to make Param immutable.

Make FramsClass? immutable.

Another improvement to Path immutability.

Several improvements to Path.

Improve PathTest?.

Configurarable MutabilityDetector?.

File size: 5.9 KB
Line 
1package com.framsticks.core;
2
3import com.framsticks.params.AccessInterface;
4import com.framsticks.params.CompositeParam;
5import com.framsticks.params.Param;
6import com.framsticks.util.dispatching.Dispatching;
7
8import java.util.Iterator;
9import java.util.LinkedList;
10import java.util.List;
11
12import javax.annotation.concurrent.Immutable;
13
14import org.apache.commons.collections.ListUtils;
15
16/**
17 * @author Piotr Sniegowski
18 */
19@Immutable
20public final class Path {
21        // private final static Logger log = Logger.getLogger(Path.class.getName());
22
23        final Instance instance;
24        final String textual;
25        final LinkedList<Node> nodes;
26
27        protected static Object getKnownChild(Instance instance, AccessInterface access, CompositeParam param) {
28                Object child = access.get(param, Object.class);
29                if (child == null) {
30                        return null;
31                }
32                return (instance.registry.prepareAccess(param) != null) ? child : null;
33        }
34
35        /**
36         * @param instance
37         * @param textual
38         * @param nodes
39         */
40        Path(Instance instance, String textual, LinkedList<Node> nodes) {
41                this.instance = instance;
42                this.textual = textual;
43                this.nodes = nodes;
44        }
45
46        public Path appendNode(Node node) {
47                assert isResolved();
48                return new PathBuilder().instance(instance).textual(textual + ((size() == 1) ? "" : "/") + node.getParam().getId()).add(nodes).add(node).finish();
49        }
50
51        public Path appendParam(CompositeParam param) {
52                assert isResolved();
53                return appendNode(new Node(param, null));
54        }
55
56        public static class PathBuilder {
57
58                Instance instance;
59                String textual;
60                final LinkedList<Node> nodes = new LinkedList<Node>();
61
62                public Path finish() {
63                        assert instance != null;
64                        assert textual != null;
65                        return new Path(instance, textual, nodes);
66                }
67
68                public PathBuilder()
69                {
70                }
71
72                public PathBuilder instance(Instance instance) {
73                        this.instance = instance;
74                        return this;
75                }
76
77                public PathBuilder textual(String textual) {
78                        this.textual = textual;
79                        return this;
80                }
81
82                public PathBuilder add(List<Node> nodes) {
83                        this.nodes.addAll(nodes);
84                        return this;
85                }
86
87                public PathBuilder add(Node node) {
88                        this.nodes.add(node);
89                        return this;
90                }
91
92                public PathBuilder setLast(Object object) {
93                        Node n = nodes.pollLast();
94                        nodes.add(new Node(n.getParam(), object));
95                        return this;
96                }
97
98                public PathBuilder buildUpTo(List<Node> nodes, Node node) {
99                        StringBuilder b = new StringBuilder();
100                        boolean add = false;
101                        for (Node n : nodes) {
102                                this.nodes.add(n);
103                                if (add) {
104                                        b.append("/").append(n.getParam().getId());
105                                }
106                                add = true;
107                                if (n == node) {
108                                        break;
109                                }
110                        }
111                        this.textual = (nodes.size() == 1) ? "/" : b.toString();
112                        return this;
113                }
114
115                public PathBuilder resolve(Instance instance, String textual) {
116
117                        assert nodes.isEmpty();
118                        assert instance.isActive();
119                        this.instance = instance;
120
121                        nodes.add(instance.root);
122                        Node current = instance.root;
123
124                        StringBuilder b = new StringBuilder();
125                        Iterator<String> i = Instance.splitPath(textual);
126                        while (i.hasNext() && current.getObject() != null) {
127                                AccessInterface access = instance.registry.prepareAccess(current.getParam());
128                                if (access == null) {
129                                        break;
130                                }
131                                String e = i.next();
132                                Param p = access.getParam(e);
133                                if (!(p instanceof CompositeParam)) {
134                                        //entries.add(new Entry());
135                                        break;
136                                }
137                                CompositeParam c = (CompositeParam)p;
138                                b.append("/").append(e);
139                                access.select(current.getObject());
140                                current = new Node(c, getKnownChild(instance, access, c));
141                                nodes.add(current);
142                        }
143                        this.textual = (nodes.size() == 1) ? "/" : b.toString();
144
145                        return this;
146                }
147        }
148
149        public static PathBuilder build() {
150                return new PathBuilder();
151        }
152
153        public Path appendResolution(Object object) {
154                assert !isResolved();
155                Path result = new PathBuilder().textual(textual).instance(instance).add(nodes).setLast(object).finish();
156                assert size() == result.size();
157                return result;
158        }
159
160        public final Object getTopObject() {
161                return getTop().getObject();
162        }
163
164        public final Node getTop() {
165                return nodes.getLast();
166        }
167
168        public final Node getUnder() {
169                assert nodes.size() >= 2;
170                return nodes.get(nodes.size() - 2);
171        }
172
173        public final String getTextual() {
174                return textual;
175        }
176
177        public String toString() {
178                return instance + textual + (!isResolved() ? "!" : "");
179        }
180
181        public final int size() {
182                assert Dispatching.isThreadSafe();
183                return nodes.size();
184        }
185
186        public final boolean isResolved() {
187                assert Dispatching.isThreadSafe();
188                return getTop().getObject() != null;
189        }
190
191        public final boolean isResolved(String textual) {
192                assert Dispatching.isThreadSafe();
193                return isTheSame(textual) && isResolved();
194        }
195
196        public final boolean isTheSame(String textual) {
197                assert Dispatching.isThreadSafe();
198                return this.textual.equals(textual);
199        }
200
201        public final Instance getInstance() {
202                assert Dispatching.isThreadSafe();
203                return instance;
204        }
205
206
207        /** Attach resolution at end, if available.
208         *
209         * @return Modified path, if resolution was available, this otherwise.
210         */
211        public Path tryFindResolution() {
212                assert instance.isActive();
213                assert !isResolved();
214                if (size() == 1) {
215                        return Path.build().resolve(instance, "/").finish();//appendResolution(instance.root.object);
216                }
217                Object child = getKnownChild(instance, instance.bindAccess(getUnder()), getTop().getParam());
218                if (child == null) {
219                        return this;
220                }
221                return appendResolution(child);
222        }
223
224        public boolean matches(Path p) {
225                assert Dispatching.isThreadSafe();
226                assert instance == p.instance;
227                Iterator<Node> a = nodes.iterator();
228                Iterator<Node> b = p.nodes.iterator();
229                while (a.hasNext() && b.hasNext()) {
230                        Node an = a.next();
231                        Node bn = b.next();
232                        if (an.object != bn.object) {
233                                return false;
234                        }
235                }
236                return a.hasNext() == b.hasNext();
237        }
238
239        public String getLastElement() {
240                return getTop().getParam().getId();
241        }
242
243        public final boolean isOwner(Instance instance) {
244                return this.instance == instance;
245        }
246
247        // public void setInstance(Instance instance) {
248        //      this.instance = instance;
249        // }
250
251        @SuppressWarnings("unchecked")
252        public
253        List<Node> getNodes() {
254                return ListUtils.unmodifiableList(nodes);
255        }
256}
257
Note: See TracBrowser for help on using the repository browser.