Adding more unit tests.
Made some classes abstract which should have been.
diff --git a/core/api/src/main/java/org/onlab/onos/net/DefaultAnnotations.java b/core/api/src/main/java/org/onlab/onos/net/DefaultAnnotations.java
index 88eafb2..001518e 100644
--- a/core/api/src/main/java/org/onlab/onos/net/DefaultAnnotations.java
+++ b/core/api/src/main/java/org/onlab/onos/net/DefaultAnnotations.java
@@ -5,6 +5,8 @@
import java.util.Objects;
import java.util.Set;
+import static com.google.common.base.Preconditions.checkNotNull;
+
/**
* Represents a set of simple annotations that can be used to add arbitrary
* attributes to various parts of the data model.
@@ -19,9 +21,9 @@
}
/**
- * Creates a new set of annotations using the specified immutable map.
+ * Creates a new set of annotations using clone of the specified hash map.
*
- * @param map immutable map of key/value pairs
+ * @param map hash map of key/value pairs
*/
private DefaultAnnotations(Map<String, String> map) {
this.map = map;
@@ -36,6 +38,38 @@
return new Builder();
}
+ /**
+ * Merges the specified base set of annotations and additional sparse
+ * annotations into new combined annotations. If the supplied sparse
+ * annotations are empty, the original base annotations are returned.
+ * Any keys tagged for removal in the sparse annotations will be omitted
+ * in the resulting merged annotations.
+ *
+ * @param annotations base annotations
+ * @param sparseAnnotations additional sparse annotations
+ * @return combined annotations or the original base annotations if there
+ * are not additional annotations
+ */
+ public static DefaultAnnotations merge(DefaultAnnotations annotations,
+ SparseAnnotations sparseAnnotations) {
+ checkNotNull(annotations, "Annotations cannot be null");
+ if (sparseAnnotations == null || sparseAnnotations.keys().isEmpty()) {
+ return annotations;
+ }
+
+ // Merge the two maps. Yes, this is not very efficient, but the
+ // use-case implies small maps and infrequent merges, so we opt for
+ // simplicity.
+ Map<String, String> merged = copy(annotations.map);
+ for (String key : sparseAnnotations.keys()) {
+ if (sparseAnnotations.isRemoved(key)) {
+ merged.remove(key);
+ } else {
+ merged.put(key, sparseAnnotations.value(key));
+ }
+ }
+ return new DefaultAnnotations(merged);
+ }
@Override
public Set<String> keys() {
@@ -53,15 +87,20 @@
return Objects.equals(Builder.REMOVED, map.get(key));
}
+ @SuppressWarnings("unchecked")
+ private static HashMap<String, String> copy(Map<String, String> original) {
+ if (original instanceof HashMap) {
+ return (HashMap) ((HashMap) original).clone();
+ }
+ throw new IllegalArgumentException("Expecting HashMap instance");
+ }
+
/**
* Facility for gradually building model annotations.
*/
public static final class Builder {
private static final String REMOVED = "~rEmOvEd~";
-
- // FIXME: Figure out whether and how to make this immutable and serializable
-// private final ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
private final Map<String, String> builder = new HashMap<>();
// Private construction is forbidden.
@@ -99,8 +138,7 @@
* @return annotations
*/
public DefaultAnnotations build() {
-// return new DefaultAnnotations(builder.build());
- return new DefaultAnnotations(builder);
+ return new DefaultAnnotations(copy(builder));
}
}
}