blob: f0334aa458a44fbff4ef8a4241b80fb3343b7adb [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
Madan Jampaniab7e7cd2016-01-14 14:02:32 -080023import org.apache.commons.collections.CollectionUtils;
24
Madan Jampaniec1df022015-10-13 21:23:03 -070025import static com.google.common.base.Preconditions.checkNotNull;
26import static com.google.common.base.Verify.verifyNotNull;
27import static com.google.common.base.Verify.verify;
28
29import com.google.common.base.MoreObjects;
30import com.google.common.collect.Collections2;
31import com.google.common.collect.ImmutableSet;
David K. Bainbridgee676dab2015-10-23 16:13:07 -070032import com.google.common.collect.Sets;
Madan Jampaniec1df022015-10-13 21:23:03 -070033
34/**
35 * Cluster metadata.
36 * <p>
Madan Jampaniab7e7cd2016-01-14 14:02:32 -080037 * Metadata specifies how a ONOS cluster is constituted and is made up of the collection
Madan Jampaniec1df022015-10-13 21:23:03 -070038 * of {@link org.onosproject.cluster.ControllerNode nodes} and the collection of data
39 * {@link org.onosproject.cluster.Partition partitions}.
40 */
41public final class ClusterMetadata {
42
Ayaka Koshibe3ddb7b22015-12-10 17:32:59 -080043 // Name to use when the ClusterMetadataService is in transient state
44 public static final String NO_NAME = "";
45
Madan Jampaniec1df022015-10-13 21:23:03 -070046 private String name;
47 private Set<ControllerNode> nodes;
48 private Set<Partition> partitions;
49
50 /**
51 * Returns a new cluster metadata builder.
52 * @return The cluster metadata builder.
53 */
54 public static Builder builder() {
55 return new Builder();
56 }
57
58 /**
59 * Returns the name of the cluster.
60 *
61 * @return cluster name
62 */
63 public String getName() {
64 return this.name;
65 }
66
67 /**
68 * Returns the collection of {@link org.onosproject.cluster.ControllerNode nodes} that make up the cluster.
69 * @return cluster nodes
70 */
71 public Collection<ControllerNode> getNodes() {
72 return this.nodes;
73 }
74
75 /**
Madan Jampaniab7e7cd2016-01-14 14:02:32 -080076 * Returns the collection of {@link org.onosproject.cluster.Partition partitions} that make
77 * up the cluster.
Madan Jampaniec1df022015-10-13 21:23:03 -070078 * @return collection of partitions.
79 */
80 public Collection<Partition> getPartitions() {
81 return this.partitions;
82 }
83
84 @Override
85 public String toString() {
86 return MoreObjects.toStringHelper(ClusterMetadata.class)
87 .add("name", name)
88 .add("nodes", nodes)
89 .add("partitions", partitions)
90 .toString();
91 }
92
David K. Bainbridgee676dab2015-10-23 16:13:07 -070093 @Override
94 public int hashCode() {
95 return Arrays.deepHashCode(new Object[] {name, nodes, partitions});
96 }
97
98 /*
Madan Jampaniab7e7cd2016-01-14 14:02:32 -080099 * Provide a deep equality check of the cluster metadata (non-Javadoc)
David K. Bainbridgee676dab2015-10-23 16:13:07 -0700100 *
101 * @see java.lang.Object#equals(java.lang.Object)
102 */
103 @Override
104 public boolean equals(Object object) {
105
106 if (!ClusterMetadata.class.isInstance(object)) {
107 return false;
108 }
109 ClusterMetadata that = (ClusterMetadata) object;
110
111 if (!this.name.equals(that.name) || this.nodes.size() != that.nodes.size()
112 || this.partitions.size() != that.partitions.size()) {
113 return false;
114 }
115
116 return Sets.symmetricDifference(this.nodes, that.nodes).isEmpty()
117 && Sets.symmetricDifference(this.partitions, that.partitions).isEmpty();
118 }
119
Madan Jampaniec1df022015-10-13 21:23:03 -0700120 /**
121 * Builder for a {@link ClusterMetadata} instance.
122 */
123 public static class Builder {
124
125 private final ClusterMetadata metadata;
126
127 public Builder() {
128 metadata = new ClusterMetadata();
129 }
130
131 /**
132 * Sets the cluster name, returning the cluster metadata builder for method chaining.
133 * @param name cluster name
134 * @return this cluster metadata builder
135 */
136 public Builder withName(String name) {
137 metadata.name = checkNotNull(name);
138 return this;
139 }
140
141 /**
142 * Sets the collection of cluster nodes, returning the cluster metadata builder for method chaining.
143 * @param controllerNodes collection of cluster nodes
144 * @return this cluster metadata builder
145 */
146 public Builder withControllerNodes(Collection<ControllerNode> controllerNodes) {
147 metadata.nodes = ImmutableSet.copyOf(checkNotNull(controllerNodes));
148 return this;
149 }
150
151 /**
Madan Jampaniab7e7cd2016-01-14 14:02:32 -0800152 * Sets the partitions, returning the cluster metadata builder for method chaining.
Madan Jampaniec1df022015-10-13 21:23:03 -0700153 * @param partitions collection of partitions
154 * @return this cluster metadata builder
155 */
156 public Builder withPartitions(Collection<Partition> partitions) {
157 metadata.partitions = ImmutableSet.copyOf(checkNotNull(partitions));
158 return this;
159 }
160
161 /**
162 * Builds the cluster metadata.
163 * @return cluster metadata
164 * @throws com.google.common.base.VerifyException VerifyException if the metadata is misconfigured
165 */
166 public ClusterMetadata build() {
167 verifyMetadata();
168 return metadata;
169 }
170
171 /**
172 * Validates the constructed metadata for semantic correctness.
173 * @throws VerifyException if the metadata is misconfigured.
174 */
175 private void verifyMetadata() {
176 verifyNotNull(metadata.getName(), "Cluster name must be specified");
Madan Jampanif6c6a302016-01-18 14:33:45 -0800177 verify(CollectionUtils.isNotEmpty(metadata.getNodes()), "Cluster nodes must be specified");
178 verify(CollectionUtils.isNotEmpty(metadata.getPartitions()), "Cluster partitions must be specified");
Madan Jampaniec1df022015-10-13 21:23:03 -0700179
180 // verify that partitions are constituted from valid cluster nodes.
181 boolean validPartitions = Collections2.transform(metadata.getNodes(), ControllerNode::id)
David K. Bainbridgee676dab2015-10-23 16:13:07 -0700182 .containsAll(metadata.getPartitions()
183 .stream()
184 .flatMap(r -> r.getMembers().stream())
185 .collect(Collectors.toSet()));
Madan Jampaniec1df022015-10-13 21:23:03 -0700186 verify(validPartitions, "Partition locations must be valid cluster nodes");
187 }
188 }
Madan Jampanif6c6a302016-01-18 14:33:45 -0800189}