blob: b70e7cc25e416f197ce160f7f13b8c485304f5aa [file] [log] [blame]
Brian O'Connorcff03322015-02-03 15:28:59 -08001/*
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.net.intent;
17
Ray Milkey65cb59a2015-02-10 15:18:26 -080018import com.google.common.base.MoreObjects;
Brian O'Connorcff03322015-02-03 15:28:59 -080019import com.google.common.collect.ImmutableList;
Brian O'Connor5eb77c82015-03-02 18:09:39 -080020import org.onosproject.cluster.NodeId;
Brian O'Connorcff03322015-02-03 15:28:59 -080021import org.onosproject.store.Timestamp;
Jonathan Hart72175c22015-03-24 18:55:58 -070022import org.slf4j.Logger;
23import org.slf4j.LoggerFactory;
Brian O'Connorcff03322015-02-03 15:28:59 -080024
25import java.util.List;
26import java.util.Objects;
27
Jonathan Hart0d18df32015-03-21 08:42:59 -070028import static com.google.common.base.Preconditions.checkNotNull;
Jonathan Hart72175c22015-03-24 18:55:58 -070029import static org.onosproject.net.intent.IntentState.FAILED;
30import static org.onosproject.net.intent.IntentState.INSTALLED;
31import static org.onosproject.net.intent.IntentState.INSTALLING;
32import static org.onosproject.net.intent.IntentState.PURGE_REQ;
33import static org.onosproject.net.intent.IntentState.WITHDRAWING;
34import static org.onosproject.net.intent.IntentState.WITHDRAWN;
Jonathan Hart0d18df32015-03-21 08:42:59 -070035
Brian O'Connorcff03322015-02-03 15:28:59 -080036/**
37 * A wrapper class that contains an intents, its state, and other metadata for
38 * internal use.
39 */
40public class IntentData { //FIXME need to make this "immutable"
41 // manager should be able to mutate a local copy while processing
Jonathan Hart72175c22015-03-24 18:55:58 -070042
43 private static final Logger log = LoggerFactory.getLogger(IntentData.class);
44
Jonathan Hart0d18df32015-03-21 08:42:59 -070045 private final Intent intent;
Brian O'Connorcff03322015-02-03 15:28:59 -080046
47 private IntentState state;
48 private Timestamp version;
Brian O'Connor5eb77c82015-03-02 18:09:39 -080049 private NodeId origin;
Brian O'Connorcff03322015-02-03 15:28:59 -080050
51 private List<Intent> installables;
52
Jonathan Hart0d18df32015-03-21 08:42:59 -070053 /**
54 * Creates a new intent data object.
55 *
56 * @param intent intent this metadata references
57 * @param state intent state
58 * @param version version of the intent for this key
59 */
Brian O'Connorcff03322015-02-03 15:28:59 -080060 public IntentData(Intent intent, IntentState state, Timestamp version) {
61 this.intent = intent;
62 this.state = state;
63 this.version = version;
64 }
65
Jonathan Hart0d18df32015-03-21 08:42:59 -070066 /**
67 * Copy constructor.
68 *
69 * @param intentData intent data to copy
70 */
71 public IntentData(IntentData intentData) {
72 checkNotNull(intentData);
73
74 intent = intentData.intent;
75 state = intentData.state;
76 version = intentData.version;
77 origin = intentData.origin;
78 installables = intentData.installables;
Brian O'Connorcff03322015-02-03 15:28:59 -080079 }
80
Jonathan Hart0d18df32015-03-21 08:42:59 -070081 // kryo constructor
82 protected IntentData() {
83 intent = null;
84 }
85
86 /**
87 * Returns the intent this metadata references.
88 *
89 * @return intent
90 */
Brian O'Connorcff03322015-02-03 15:28:59 -080091 public Intent intent() {
92 return intent;
93 }
94
Jonathan Hart0d18df32015-03-21 08:42:59 -070095 /**
96 * Returns the state of the intent.
97 *
98 * @return intent state
99 */
Brian O'Connorcff03322015-02-03 15:28:59 -0800100 public IntentState state() {
101 return state;
102 }
103
Jonathan Hart0d18df32015-03-21 08:42:59 -0700104 /**
105 * Returns the intent key.
106 *
107 * @return intent key
108 */
Ray Milkey5b3717e2015-02-05 11:44:08 -0800109 public Key key() {
Brian O'Connorcff03322015-02-03 15:28:59 -0800110 return intent.key();
111 }
112
Jonathan Hart0d18df32015-03-21 08:42:59 -0700113 /**
114 * Returns the version of the intent for this key.
115 *
116 * @return intent version
117 */
Brian O'Connor2ba63fd2015-02-09 22:48:11 -0800118 public Timestamp version() {
119 return version;
120 }
121
Brian O'Connor5eb77c82015-03-02 18:09:39 -0800122 /**
Jonathan Hart0d18df32015-03-21 08:42:59 -0700123 * Sets the origin, which is the node that created the intent.
Brian O'Connor5eb77c82015-03-02 18:09:39 -0800124 *
125 * @param origin origin instance
126 */
127 public void setOrigin(NodeId origin) {
128 this.origin = origin;
129 }
130
Jonathan Hart0d18df32015-03-21 08:42:59 -0700131 /**
132 * Returns the origin node that created this intent.
133 *
134 * @return origin node ID
135 */
Brian O'Connor5eb77c82015-03-02 18:09:39 -0800136 public NodeId origin() {
137 return origin;
138 }
139
Jonathan Hart0d18df32015-03-21 08:42:59 -0700140 /**
141 * Updates the state of the intent to the given new state.
142 *
143 * @param newState new state of the intent
144 */
Brian O'Connorcff03322015-02-03 15:28:59 -0800145 public void setState(IntentState newState) {
146 this.state = newState;
147 }
148
Brian O'Connor2ba63fd2015-02-09 22:48:11 -0800149 /**
150 * Sets the version for this intent data.
151 * <p>
152 * The store should call this method only once when the IntentData is
153 * first passed into the pending map. Ideally, an IntentData is timestamped
154 * on the same thread that the called used to submit the intents.
155 * </p>
156 *
157 * @param version the version/timestamp for this intent data
158 */
159 public void setVersion(Timestamp version) {
160 this.version = version;
161 }
162
Jonathan Hart0d18df32015-03-21 08:42:59 -0700163 /**
164 * Sets the intent installables to the given list of intents.
165 *
166 * @param installables list of installables for this intent
167 */
Brian O'Connorcff03322015-02-03 15:28:59 -0800168 public void setInstallables(List<Intent> installables) {
169 this.installables = ImmutableList.copyOf(installables);
170 }
171
Jonathan Hart0d18df32015-03-21 08:42:59 -0700172 /**
173 * Returns the installables associated with this intent.
174 *
175 * @return list of installable intents
176 */
Brian O'Connorcff03322015-02-03 15:28:59 -0800177 public List<Intent> installables() {
178 return installables;
179 }
180
Jonathan Hart72175c22015-03-24 18:55:58 -0700181 /**
182 * Determines whether an intent data update is allowed. The update must
183 * either have a higher version than the current data, or the state
184 * transition between two updates of the same version must be sane.
185 *
186 * @param currentData existing intent data in the store
187 * @param newData new intent data update proposal
188 * @return true if we can apply the update, otherwise false
189 */
190 public static boolean isUpdateAcceptable(IntentData currentData, IntentData newData) {
191
192 if (currentData == null) {
193 return true;
Sho SHIMIZU2c05f912015-04-10 14:23:16 -0700194 } else if (currentData.version().isOlderThan(newData.version())) {
Jonathan Hart72175c22015-03-24 18:55:58 -0700195 return true;
Sho SHIMIZU2c05f912015-04-10 14:23:16 -0700196 } else if (currentData.version().isNewerThan(newData.version())) {
Jonathan Hart72175c22015-03-24 18:55:58 -0700197 return false;
198 }
199
200 // current and new data versions are the same
201 IntentState currentState = currentData.state();
202 IntentState newState = newData.state();
203
204 switch (newState) {
205 case INSTALLING:
206 if (currentState == INSTALLING) {
207 return false;
208 }
209 // FALLTHROUGH
210 case INSTALLED:
211 if (currentState == INSTALLED) {
212 return false;
213 } else if (currentState == WITHDRAWING || currentState == WITHDRAWN
214 || currentState == PURGE_REQ) {
215 log.warn("Invalid state transition from {} to {} for intent {}",
216 currentState, newState, newData.key());
217 return false;
218 }
219 return true;
220
221 case WITHDRAWING:
222 if (currentState == WITHDRAWING) {
223 return false;
224 }
225 // FALLTHROUGH
226 case WITHDRAWN:
227 if (currentState == WITHDRAWN) {
228 return false;
229 } else if (currentState == INSTALLING || currentState == INSTALLED
230 || currentState == PURGE_REQ) {
231 log.warn("Invalid state transition from {} to {} for intent {}",
232 currentState, newState, newData.key());
233 return false;
234 }
235 return true;
236
237 case FAILED:
238 if (currentState == FAILED) {
239 return false;
240 }
241 return true;
242
243 case PURGE_REQ:
244 return true;
245
246 case COMPILING:
247 case RECOMPILING:
248 case INSTALL_REQ:
249 case WITHDRAW_REQ:
250 default:
251 log.warn("Invalid state {} for intent {}", newState, newData.key());
252 return false;
253 }
254 }
255
Brian O'Connorcff03322015-02-03 15:28:59 -0800256 @Override
257 public int hashCode() {
258 return Objects.hash(intent, version);
259 }
260
261 @Override
262 public boolean equals(Object obj) {
263 if (this == obj) {
264 return true;
265 }
266 if (obj == null || getClass() != obj.getClass()) {
267 return false;
268 }
269 final IntentData other = (IntentData) obj;
270 return Objects.equals(this.intent, other.intent)
271 && Objects.equals(this.version, other.version);
272 }
Ray Milkey65cb59a2015-02-10 15:18:26 -0800273
Jonathan Hart0d18df32015-03-21 08:42:59 -0700274 @Override
Ray Milkey65cb59a2015-02-10 15:18:26 -0800275 public String toString() {
276 return MoreObjects.toStringHelper(getClass())
277 .add("key", key())
278 .add("state", state())
279 .add("version", version())
Ray Milkey9f74c082015-02-11 15:40:16 -0800280 .add("intent", intent())
Jonathan Hart0d18df32015-03-21 08:42:59 -0700281 .add("origin", origin())
Jonathan Hartd0ba2172015-02-11 13:54:33 -0800282 .add("installables", installables())
Ray Milkey65cb59a2015-02-10 15:18:26 -0800283 .toString();
284 }
285
Brian O'Connorcff03322015-02-03 15:28:59 -0800286}