Aaron Kruglikov

Adding an initial API for the DomTree data structure.

Change-Id: I55da78c11f49c1e5843cfefbe0a5eed02c59498b
1 +/*
2 + * Copyright 2016-present Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onosproject.store.primitives;
18 +
19 +import com.google.common.base.MoreObjects;
20 +import com.google.common.collect.Sets;
21 +import org.onosproject.store.service.DocumentPath;
22 +
23 +import java.util.Comparator;
24 +import java.util.Iterator;
25 +import java.util.Objects;
26 +import java.util.TreeSet;
27 +
28 +import static com.google.common.base.Preconditions.checkNotNull;
29 +
30 +/**
31 + * A tree node made for {@code DocumentTree}
32 + * implementations that keeps records of its parent and children.
33 + */
34 +public class DocumentTreeNode<V> {
35 + private final DocumentPath key;
36 + private V value;
37 + private final TreeSet<DocumentTreeNode<V>> children =
38 + Sets.newTreeSet(new Comparator<DocumentTreeNode<V>>() {
39 + @Override
40 + public int compare(DocumentTreeNode<V> o1,
41 + DocumentTreeNode<V> o2) {
42 + return o1.getKey().compareTo(o2.getKey());
43 + }
44 + });
45 + private DocumentTreeNode parent;
46 +
47 + public DocumentTreeNode(DocumentPath key, V value,
48 + DocumentTreeNode parent) {
49 + this.key = checkNotNull(key);
50 + this.value = checkNotNull(value);
51 + this.parent = parent;
52 + }
53 +
54 + /**
55 + * Returns this objects key.
56 + *
57 + * @return the key
58 + */
59 + public DocumentPath getKey() {
60 + return key;
61 + }
62 +
63 + /**
64 + * Returns this objects value.
65 + *
66 + * @return the value
67 + */
68 + public V getValue() {
69 + return value;
70 + }
71 +
72 + /**
73 + * Sets this objects value.
74 + *
75 + * @param value the value to be set
76 + */
77 + public void setValue(V value) {
78 + this.value = value;
79 + }
80 +
81 + /**
82 + * Returns a collection of the children of this node.
83 + *
84 + * @return a sorted iterator for the children of this node.
85 + */
86 + public Iterator<DocumentTreeNode<V>> getChildren() {
87 + return children.iterator();
88 + }
89 +
90 + /**
91 + * Adds a child to this node.
92 + *
93 + * @param child the child node to be added
94 + * @return true if the child set was modified as a result of this call,
95 + * false otherwise
96 + */
97 + public boolean addChild(DocumentTreeNode<V> child) {
98 + return children.add(child);
99 + }
100 +
101 + /**
102 + * Removes a child from the children of this node.
103 + *
104 + * @param child the child node to be removed
105 + * @return true if the child set was modified as a result of this call,
106 + * false otherwise
107 + */
108 + public boolean removeChild(String child) {
109 + return children.remove(child);
110 + }
111 +
112 + /**
113 + * Returns the parent of this node.
114 + *
115 + * @return the parent node of this node, which may be null
116 + */
117 + public DocumentTreeNode<V> getParent() {
118 + return parent;
119 + }
120 +
121 + @Override
122 + public int hashCode() {
123 + return Objects.hash(this.key);
124 + }
125 +
126 + @Override
127 + public boolean equals(Object obj) {
128 + if (obj instanceof DocumentTreeNode) {
129 + DocumentTreeNode that = (DocumentTreeNode) obj;
130 + if (this.parent.equals(that.parent)) {
131 + if (this.children.size() == that.children.size()) {
132 + for (DocumentTreeNode child : this.children) {
133 + if (!that.children.contains(child)) {
134 + return false;
135 + }
136 + }
137 + return true;
138 + }
139 + }
140 + }
141 + return false;
142 + }
143 +
144 + @Override
145 + public String toString() {
146 + MoreObjects.ToStringHelper helper =
147 + MoreObjects.toStringHelper(getClass())
148 + .add("parent", this.parent)
149 + .add("key", this.key)
150 + .add("value", this.value);
151 + for (DocumentTreeNode child : children) {
152 + helper = helper.add("child", child.key);
153 + }
154 + return helper.toString();
155 + }
156 +
157 +}
1 +/*
2 + * Copyright 2016-present Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onosproject.store.service;
18 +
19 +/**
20 + * Exceptions for use by the {@code DocumentTree} and {@code DocumentPath}.
21 + */
22 +public class DocumentException extends RuntimeException {
23 + public DocumentException() {
24 + super();
25 + }
26 +
27 + public DocumentException(String message) {
28 + super(message);
29 + }
30 +
31 + public DocumentException(String message, Throwable cause) {
32 + super(message, cause);
33 + }
34 +
35 + public DocumentException(Throwable cause) {
36 + super(cause);
37 + }
38 +}
1 +/*
2 + * Copyright 2016-present Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onosproject.store.service;
18 +
19 +import com.google.common.base.Preconditions;
20 +import com.google.common.collect.ImmutableList;
21 +import com.google.common.collect.Lists;
22 +
23 +import java.util.ArrayList;
24 +import java.util.Iterator;
25 +import java.util.List;
26 +import java.util.Objects;
27 +
28 +/**
29 + * A path class for identifying nodes within the {@code DocumentTree}.
30 + *
31 + * Note: indexing is ONE based so the root is the 1st level, to retrieve the
32 + * root one should query level 1.
33 + */
34 +public class DocumentPath implements Comparable {
35 +
36 + private final ArrayList<String> tokens = Lists.newArrayList();
37 +
38 + /**
39 + * Private utility constructor for internal generation of partial paths only.
40 + *
41 + * @param path
42 + */
43 + private DocumentPath(List<String> path) {
44 + Preconditions.checkNotNull(path);
45 + this.tokens.addAll(path);
46 + }
47 +
48 + /**
49 + * Constructor to generate new {@DocumentPath}, new paths must contain at
50 + * least one name and string names may NOT contain any '.'s. If one field
51 + * is null that field will be ignored.
52 + *
53 + * @throws IllegalDocumentNameException if both parameters are null or the string
54 + * name contains an illegal character ('.')
55 + * @param nodeName the name of the last level of this path
56 + * @param parentPath the path representing the parents leading up to this
57 + * node, in the case of the root this should be null
58 + */
59 + public DocumentPath(String nodeName, DocumentPath parentPath) {
60 + if (nodeName.contains(".")) {
61 + throw new IllegalDocumentNameException(
62 + "Periods are not allowed in names.");
63 + }
64 + if (parentPath != null) {
65 + tokens.addAll(parentPath.path());
66 + }
67 + if (nodeName != null) {
68 + tokens.add(nodeName);
69 + }
70 + if (tokens.isEmpty()) {
71 + throw new IllegalDocumentNameException("A document path must contain at" +
72 + "least one non-null" +
73 + "element.");
74 + }
75 + }
76 +
77 + /**
78 + * Returns a path from the root to the parent of this node, if this node is
79 + * the root this call returns null.
80 + *
81 + * @return a {@code DocumentPath} representing a path to this paths parent,
82 + * null if this a root path
83 + */
84 + public DocumentPath parent() {
85 + if (tokens.size() <= 1) {
86 + return null;
87 + }
88 + return new DocumentPath(this.tokens.subList(0, tokens.size() - 1));
89 + }
90 +
91 + /**
92 + * Returns the complete list of tokens representing this path in correct
93 + * order.
94 + *
95 + * @return a list of strings representing this path
96 + */
97 + public List<String> path() {
98 + return ImmutableList.copyOf(tokens);
99 + }
100 +
101 + @Override
102 + public int hashCode() {
103 + return Objects.hash(tokens);
104 + }
105 +
106 + @Override
107 + public boolean equals(Object obj) {
108 + if (obj instanceof DocumentPath) {
109 + DocumentPath that = (DocumentPath) obj;
110 + return this.tokens.equals(that.tokens);
111 + }
112 + return false;
113 + }
114 +
115 + @Override
116 + public String toString() {
117 + StringBuilder stringBuilder = new StringBuilder();
118 + Iterator<String> iter = tokens.iterator();
119 + while (iter.hasNext()) {
120 + stringBuilder.append(iter.next());
121 + if (iter.hasNext()) {
122 + stringBuilder.append(".");
123 + }
124 + }
125 + return stringBuilder.toString();
126 + }
127 +
128 + @Override
129 + public int compareTo(Object o) {
130 + if (o instanceof DocumentPath) {
131 + DocumentPath that = (DocumentPath) o;
132 + int shorterLength = this.tokens.size() > that.tokens.size() ?
133 + that.tokens.size() : this.tokens.size();
134 + for (int i = 0; i < shorterLength; i++) {
135 + if (this.tokens.get(i).compareTo(that.tokens.get(i)) != 0) {
136 + return this.tokens.get(i).compareTo(that.tokens.get(i));
137 + }
138 + }
139 +
140 + if (this.tokens.size() > that.tokens.size()) {
141 + return 1;
142 + } else if (that.tokens.size() > this.tokens.size()) {
143 + return -1;
144 + } else {
145 + return 0;
146 + }
147 + }
148 + throw new IllegalArgumentException("Compare can only compare objects" +
149 + "of the same type.");
150 + }
151 +}
1 +/*
2 + * Copyright 2016-present Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onosproject.store.service;
18 +
19 +import org.onosproject.store.primitives.DocumentTreeNode;
20 +
21 +import java.util.Iterator;
22 +
23 +/**
24 + * Interface for a tree with structure wherein keys hold information
25 + * about the hierarchical structure of the tree (name of parent,
26 + * grandparent etc.).
27 + */
28 +public interface DocumentTree<V> {
29 +
30 + /**
31 + * Returns the root of the tree. This will be the first part of any fully
32 + * qualified path and will enable discovery of the entire tree.
33 + *
34 + * @return a string that is the name of the root of the tree.
35 + */
36 + DocumentPath root();
37 +
38 + /**
39 + * Returns a sorted list containing all key value pairs that are direct
40 + * descendants of the supplied parent. The returned list will be immutable.
41 + * If the specified parent does not exist this method will fail with an
42 + * exception.
43 + *
44 + * @throws NoSuchDocumentPathException if the parent does not exist
45 + * @param parentPath the path to the parent of the desired nodes
46 + * @return an iterator of the children of the specified parent
47 + */
48 + Iterator<DocumentTreeNode<V>> getChildren(DocumentPath parentPath);
49 +
50 + /**
51 + * Returns the value associated with the supplied key or null if no such
52 + * node exists.
53 + *
54 + * @param key the key to query
55 + * @return a value or null
56 + */
57 + DocumentTreeNode<V> getNode(DocumentPath key);
58 +
59 + /**
60 + * Takes a string that specifies the complete path to the mapping to be
61 + * added or updated and creates the key value mapping or updates the value.
62 + * If the specified parent cannot be found the operation fails with an
63 + * error.
64 + *
65 + * @throws NoSuchDocumentPathException if the specified parent does not
66 + * exist.
67 + * @param key the fully qualified key of the entry to be added or updated
68 + * @param value the non-null value to be associated with the key
69 + * @return the previous mapping or null if there was no previous mapping
70 + */
71 + V putNode(DocumentPath key, V value);
72 +
73 + /**
74 + * Takes the fully qualified name of the node to be added along with
75 + * the value to be added. If the specified key already exists it doesnot
76 + * update anything & returns false. If the parent does not exist the
77 + * operation fails with an exception.
78 + *
79 + * @throws NoSuchDocumentPathException if the specified parent does not
80 + * exist.
81 + * @param key the fully qualified key of the entry to be added or updated
82 + * @param value the non-null value to be associated with the key
83 + * @return returns true if the mapping could be added successfully
84 + */
85 + boolean createNode(DocumentPath key, V value);
86 +
87 + /**
88 + * Removes the node with the specified fully qualified key. Returns null if
89 + * the node did not exist. This method will throw an exception if called on
90 + * a non-leaf node.
91 + *
92 + * @throws IllegalDocumentModificationException if the node had children.
93 + * @param key the fully qualified key of the node to be removed
94 + * @return the previous value of the node or null if it did not exist
95 + */
96 + V removeNode(DocumentPath key);
97 +}
1 +/*
2 + * Copyright 2016-present Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onosproject.store.service;
18 +
19 +/**
20 + * An exception to be thrown when a node cannot be removed normally because
21 + * it does not exist or because it is not a leaf node.
22 + */
23 +public class IllegalDocumentModificationException extends DocumentException {
24 + public IllegalDocumentModificationException() {
25 + }
26 +
27 + public IllegalDocumentModificationException(String message) {
28 + super(message);
29 + }
30 +
31 + public IllegalDocumentModificationException(String message,
32 + Throwable cause) {
33 + super(message, cause);
34 + }
35 +
36 + public IllegalDocumentModificationException(Throwable cause) {
37 + super(cause);
38 + }
39 +}
1 +/*
2 + * Copyright 2016-present Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onosproject.store.service;
18 +
19 +/**
20 + * An exception thrown when an illegally named node is submitted.
21 + */
22 +public class IllegalDocumentNameException extends DocumentException {
23 + public IllegalDocumentNameException() {
24 + }
25 +
26 + public IllegalDocumentNameException(String message) {
27 + super(message);
28 + }
29 +
30 + public IllegalDocumentNameException(String message, Throwable cause) {
31 + super(message, cause);
32 + }
33 +
34 + public IllegalDocumentNameException(Throwable cause) {
35 + super(cause);
36 + }
37 +}
...\ No newline at end of file ...\ No newline at end of file
1 +/*
2 + * Copyright 2016-present Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onosproject.store.service;
18 +
19 +/**
20 + * An exception to be thrown when an invalid path is passed to the
21 + * {@code DocumentTree}.
22 + */
23 +public class NoSuchDocumentPathException extends DocumentException {
24 + public NoSuchDocumentPathException() {
25 + }
26 +
27 + public NoSuchDocumentPathException(String message) {
28 + super(message);
29 + }
30 +
31 + public NoSuchDocumentPathException(String message, Throwable cause) {
32 + super(message, cause);
33 + }
34 +
35 + public NoSuchDocumentPathException(Throwable cause) {
36 + super(cause);
37 + }
38 +}