blob: 6da48fa7470f3dbd9a4070f5296656237c833894 [file] [log] [blame]
Madan Jampaniec1df022015-10-13 21:23:03 -07001/*
2 * Copyright 2015 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 */
16package org.onosproject.cluster;
17
David K. Bainbridgee676dab2015-10-23 16:13:07 -070018import java.util.Arrays;
Madan Jampaniec1df022015-10-13 21:23:03 -070019import java.util.Collection;
20import java.util.Set;
21import java.util.stream.Collectors;
22
23import static com.google.common.base.Preconditions.checkNotNull;
24import static com.google.common.base.Verify.verifyNotNull;
25import static com.google.common.base.Verify.verify;
26
27import com.google.common.base.MoreObjects;
28import com.google.common.collect.Collections2;
29import com.google.common.collect.ImmutableSet;
David K. Bainbridgee676dab2015-10-23 16:13:07 -070030import com.google.common.collect.Sets;
Madan Jampaniec1df022015-10-13 21:23:03 -070031
32/**
33 * Cluster metadata.
34 * <p>
35 * Metadata specifies the attributes that define a ONOS cluster and comprises the collection
36 * of {@link org.onosproject.cluster.ControllerNode nodes} and the collection of data
37 * {@link org.onosproject.cluster.Partition partitions}.
38 */
39public final class ClusterMetadata {
40
Ayaka Koshibe3ddb7b22015-12-10 17:32:59 -080041 // Name to use when the ClusterMetadataService is in transient state
42 public static final String NO_NAME = "";
43
Madan Jampaniec1df022015-10-13 21:23:03 -070044 private String name;
45 private Set<ControllerNode> nodes;
46 private Set<Partition> partitions;
47
48 /**
49 * Returns a new cluster metadata builder.
50 * @return The cluster metadata builder.
51 */
52 public static Builder builder() {
53 return new Builder();
54 }
55
56 /**
57 * Returns the name of the cluster.
58 *
59 * @return cluster name
60 */
61 public String getName() {
62 return this.name;
63 }
64
65 /**
66 * Returns the collection of {@link org.onosproject.cluster.ControllerNode nodes} that make up the cluster.
67 * @return cluster nodes
68 */
69 public Collection<ControllerNode> getNodes() {
70 return this.nodes;
71 }
72
73 /**
74 * Returns the collection of data {@link org.onosproject.cluster.Partition partitions} that make up the cluster.
75 * @return collection of partitions.
76 */
77 public Collection<Partition> getPartitions() {
78 return this.partitions;
79 }
80
81 @Override
82 public String toString() {
83 return MoreObjects.toStringHelper(ClusterMetadata.class)
84 .add("name", name)
85 .add("nodes", nodes)
86 .add("partitions", partitions)
87 .toString();
88 }
89
David K. Bainbridgee676dab2015-10-23 16:13:07 -070090 @Override
91 public int hashCode() {
92 return Arrays.deepHashCode(new Object[] {name, nodes, partitions});
93 }
94
95 /*
96 * Provide a deep quality check of the meta data (non-Javadoc)
97 *
98 * @see java.lang.Object#equals(java.lang.Object)
99 */
100 @Override
101 public boolean equals(Object object) {
102
103 if (!ClusterMetadata.class.isInstance(object)) {
104 return false;
105 }
106 ClusterMetadata that = (ClusterMetadata) object;
107
108 if (!this.name.equals(that.name) || this.nodes.size() != that.nodes.size()
109 || this.partitions.size() != that.partitions.size()) {
110 return false;
111 }
112
113 return Sets.symmetricDifference(this.nodes, that.nodes).isEmpty()
114 && Sets.symmetricDifference(this.partitions, that.partitions).isEmpty();
115 }
116
Madan Jampaniec1df022015-10-13 21:23:03 -0700117 /**
118 * Builder for a {@link ClusterMetadata} instance.
119 */
120 public static class Builder {
121
122 private final ClusterMetadata metadata;
123
124 public Builder() {
125 metadata = new ClusterMetadata();
126 }
127
128 /**
129 * Sets the cluster name, returning the cluster metadata builder for method chaining.
130 * @param name cluster name
131 * @return this cluster metadata builder
132 */
133 public Builder withName(String name) {
134 metadata.name = checkNotNull(name);
135 return this;
136 }
137
138 /**
139 * Sets the collection of cluster nodes, returning the cluster metadata builder for method chaining.
140 * @param controllerNodes collection of cluster nodes
141 * @return this cluster metadata builder
142 */
143 public Builder withControllerNodes(Collection<ControllerNode> controllerNodes) {
144 metadata.nodes = ImmutableSet.copyOf(checkNotNull(controllerNodes));
145 return this;
146 }
147
148 /**
149 * Sets the collection of data partitions, returning the cluster metadata builder for method chaining.
150 * @param partitions collection of partitions
151 * @return this cluster metadata builder
152 */
153 public Builder withPartitions(Collection<Partition> partitions) {
154 metadata.partitions = ImmutableSet.copyOf(checkNotNull(partitions));
155 return this;
156 }
157
158 /**
159 * Builds the cluster metadata.
160 * @return cluster metadata
161 * @throws com.google.common.base.VerifyException VerifyException if the metadata is misconfigured
162 */
163 public ClusterMetadata build() {
164 verifyMetadata();
165 return metadata;
166 }
167
168 /**
169 * Validates the constructed metadata for semantic correctness.
170 * @throws VerifyException if the metadata is misconfigured.
171 */
172 private void verifyMetadata() {
173 verifyNotNull(metadata.getName(), "Cluster name must be specified");
174 verifyNotNull(metadata.getNodes(), "Cluster nodes must be specified");
175 verifyNotNull(metadata.getPartitions(), "Cluster partitions must be specified");
176 verify(!metadata.getNodes().isEmpty(), "Cluster nodes must not be empty");
177 verify(!metadata.getPartitions().isEmpty(), "Cluster nodes must not be empty");
178
179 // verify that partitions are constituted from valid cluster nodes.
180 boolean validPartitions = Collections2.transform(metadata.getNodes(), ControllerNode::id)
David K. Bainbridgee676dab2015-10-23 16:13:07 -0700181 .containsAll(metadata.getPartitions()
182 .stream()
183 .flatMap(r -> r.getMembers().stream())
184 .collect(Collectors.toSet()));
Madan Jampaniec1df022015-10-13 21:23:03 -0700185 verify(validPartitions, "Partition locations must be valid cluster nodes");
186 }
187 }
188}