blob: 59b1d74cba53f9d5c592d1c8c44e669205ebe7bf [file] [log] [blame]
Brian O'Connorb488b192015-02-06 17:58:58 -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.store.intent.impl;
17
18import com.google.common.collect.Maps;
19import org.apache.felix.scr.annotations.Activate;
20import org.apache.felix.scr.annotations.Component;
21import org.apache.felix.scr.annotations.Deactivate;
22import org.apache.felix.scr.annotations.Service;
23import org.onosproject.net.intent.BatchWrite;
24import org.onosproject.net.intent.BatchWrite.Operation;
25import org.onosproject.net.intent.Intent;
26import org.onosproject.net.intent.IntentData;
27import org.onosproject.net.intent.IntentEvent;
Brian O'Connorb488b192015-02-06 17:58:58 -080028import org.onosproject.net.intent.IntentState;
29import org.onosproject.net.intent.IntentStore;
30import org.onosproject.net.intent.IntentStoreDelegate;
31import org.onosproject.net.intent.Key;
32import org.onosproject.store.AbstractStore;
Brian O'Connor2ba63fd2015-02-09 22:48:11 -080033import org.onosproject.store.impl.SystemClockTimestamp;
Brian O'Connorb488b192015-02-06 17:58:58 -080034import org.slf4j.Logger;
35
36import java.util.List;
37import java.util.Map;
Brian O'Connorb488b192015-02-06 17:58:58 -080038import java.util.stream.Collectors;
39
40import static com.google.common.base.Preconditions.checkNotNull;
Ray Milkey9f74c082015-02-11 15:40:16 -080041import static org.onosproject.net.intent.IntentState.*;
Brian O'Connorb488b192015-02-06 17:58:58 -080042import static org.slf4j.LoggerFactory.getLogger;
43
Brian O'Connor2ba63fd2015-02-09 22:48:11 -080044//TODO Note: this store will be removed once the GossipIntentStore is stable
45
Brian O'Connorb488b192015-02-06 17:58:58 -080046@Component(immediate = true)
47@Service
48//FIXME remove this
49public class SimpleIntentStore
50 extends AbstractStore<IntentEvent, IntentStoreDelegate>
51 implements IntentStore {
52
53 private final Logger log = getLogger(getClass());
54
Brian O'Connorb488b192015-02-06 17:58:58 -080055 private final Map<Key, IntentData> current = Maps.newConcurrentMap();
Brian O'Connor2ba63fd2015-02-09 22:48:11 -080056 private final Map<Key, IntentData> pending = Maps.newConcurrentMap();
Brian O'Connorb488b192015-02-06 17:58:58 -080057
Ray Milkey9f74c082015-02-11 15:40:16 -080058 private IntentData copyData(IntentData original) {
59 if (original == null) {
60 return null;
61 }
62 IntentData result =
63 new IntentData(original.intent(), original.state(), original.version());
64
65 if (original.installables() != null) {
66 result.setInstallables(original.installables());
67 }
68 return result;
69 }
70
Brian O'Connorb488b192015-02-06 17:58:58 -080071 @Activate
72 public void activate() {
73 log.info("Started");
74 }
75
76 @Deactivate
77 public void deactivate() {
78 log.info("Stopped");
79 }
80
81 @Override
82 public long getIntentCount() {
83 return current.size();
84 }
85
86 @Override
87 public Iterable<Intent> getIntents() {
88 return current.values().stream()
89 .map(IntentData::intent)
90 .collect(Collectors.toList());
91 }
92
93 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -080094 public IntentState getIntentState(Key intentKey) {
95 IntentData data = current.get(intentKey);
96 return (data != null) ? data.state() : null;
Brian O'Connorb488b192015-02-06 17:58:58 -080097 }
98
99 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800100 public List<Intent> getInstallableIntents(Key intentKey) {
101 // TODO: implement this or delete class
Brian O'Connorb488b192015-02-06 17:58:58 -0800102 return null;
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800103 /*
Brian O'Connorb488b192015-02-06 17:58:58 -0800104 for (IntentData data : current.values()) {
105 if (Objects.equals(data.intent().id(), intentId)) {
106 return data.installables();
107 }
108 }
109 return null;
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800110 */
Brian O'Connorb488b192015-02-06 17:58:58 -0800111 }
112
113 /*
114 * Execute writes in a batch.
115 *
116 * @param batch BatchWrite to execute
117 * @return failed operations
118 */
119 @Override
120 public List<Operation> batchWrite(BatchWrite batch) {
121 throw new UnsupportedOperationException("deprecated");
122 /*
123 if (batch.isEmpty()) {
124 return Collections.emptyList();
125 }
126
127 List<Operation> failed = Lists.newArrayList();
128 for (Operation op : batch.operations()) {
129 switch (op.type()) {
130 case CREATE_INTENT:
131 checkArgument(op.args().size() == 1,
132 "CREATE_INTENT takes 1 argument. %s", op);
133 Intent intent = (Intent) op.args().get(0);
134 // TODO: what if it failed?
135// createIntent(intent); FIXME
136 break;
137
138 case REMOVE_INTENT:
139 checkArgument(op.args().size() == 1,
140 "REMOVE_INTENT takes 1 argument. %s", op);
141 IntentId intentId = (IntentId) op.args().get(0);
142// removeIntent(intentId); FIXME
143 break;
144
145 case REMOVE_INSTALLED:
146 checkArgument(op.args().size() == 1,
147 "REMOVE_INSTALLED takes 1 argument. %s", op);
148 intentId = (IntentId) op.args().get(0);
149 removeInstalledIntents(intentId);
150 break;
151
152 case SET_INSTALLABLE:
153 checkArgument(op.args().size() == 2,
154 "SET_INSTALLABLE takes 2 arguments. %s", op);
155 intentId = (IntentId) op.args().get(0);
156 @SuppressWarnings("unchecked")
157 List<Intent> installableIntents = (List<Intent>) op.args().get(1);
158 setInstallableIntents(intentId, installableIntents);
159 break;
160
161 case SET_STATE:
162 checkArgument(op.args().size() == 2,
163 "SET_STATE takes 2 arguments. %s", op);
164 intent = (Intent) op.args().get(0);
165 IntentState newState = (IntentState) op.args().get(1);
166 setState(intent, newState);
167 break;
168
169 default:
170 break;
171 }
172 }
173 return failed;
174 */
175 }
176
Ray Milkey9f74c082015-02-11 15:40:16 -0800177
178 /**
179 * TODO.
180 * @param currentData
181 * @param newData
182 * @return
183 */
184 private boolean isUpdateAcceptable(IntentData currentData, IntentData newData) {
185
186 if (currentData == null) {
187 return true;
188 } else if (currentData.version().compareTo(newData.version()) < 0) {
189 return true;
190 } else if (currentData.version().compareTo(newData.version()) > 0) {
191 return false;
192 }
193
194 // current and new data versions are the same
195 IntentState currentState = currentData.state();
196 IntentState newState = newData.state();
197
198 switch (newState) {
199 case INSTALLING:
200 if (currentState == INSTALLING) {
201 return false;
202 }
203 // FALLTHROUGH
204 case INSTALLED:
205 if (currentState == INSTALLED) {
206 return false;
207 } else if (currentState == WITHDRAWING || currentState == WITHDRAWN) {
208 log.warn("Invalid state transition from {} to {} for intent {}",
209 currentState, newState, newData.key());
210 return false;
211 }
212 return true;
213
214 case WITHDRAWING:
215 if (currentState == WITHDRAWING) {
216 return false;
217 }
218 // FALLTHOUGH
219 case WITHDRAWN:
220 if (currentState == WITHDRAWN) {
221 return false;
222 } else if (currentState == INSTALLING || currentState == INSTALLED) {
223 log.warn("Invalid state transition from {} to {} for intent {}",
224 currentState, newState, newData.key());
225 return false;
226 }
227 return true;
228
229
230 case FAILED:
231 if (currentState == FAILED) {
232 return false;
233 }
234 return true;
235
236
237 case COMPILING:
238 case RECOMPILING:
239 case INSTALL_REQ:
240 case WITHDRAW_REQ:
241 default:
242 log.warn("Invalid state {} for intent {}", newState, newData.key());
243 return false;
244 }
245 }
246
Brian O'Connorb488b192015-02-06 17:58:58 -0800247 @Override
248 public void write(IntentData newData) {
Brian O'Connor2ba63fd2015-02-09 22:48:11 -0800249 synchronized (this) {
250 // TODO this could be refactored/cleaned up
251 IntentData currentData = current.get(newData.key());
252 IntentData pendingData = pending.get(newData.key());
Ray Milkey9f74c082015-02-11 15:40:16 -0800253
254 if (isUpdateAcceptable(currentData, newData)) {
255 current.put(newData.key(), copyData(newData));
Brian O'Connor2ba63fd2015-02-09 22:48:11 -0800256
257 if (pendingData != null
258 // pendingData version is less than or equal to newData's
259 // Note: a new update for this key could be pending (it's version will be greater)
260 && pendingData.version().compareTo(newData.version()) <= 0) {
261 pending.remove(newData.key());
262 }
263
264 try {
265 notifyDelegate(IntentEvent.getEvent(newData));
266 } catch (IllegalArgumentException e) {
267 //no-op
268 log.trace("ignore this exception: {}", e);
269 }
270 }
Brian O'Connorb488b192015-02-06 17:58:58 -0800271 }
272 }
273
274 @Override
275 public void batchWrite(Iterable<IntentData> updates) {
276 for (IntentData data : updates) {
277 write(data);
278 }
279 }
280
281 @Override
282 public Intent getIntent(Key key) {
283 IntentData data = current.get(key);
284 return (data != null) ? data.intent() : null;
285 }
286
Brian O'Connorb488b192015-02-06 17:58:58 -0800287 @Override
Ray Milkey9f74c082015-02-11 15:40:16 -0800288 public IntentData getIntentData(Key key) {
289 return copyData(current.get(key));
290 }
291
292 @Override
Brian O'Connorb488b192015-02-06 17:58:58 -0800293 public void addPending(IntentData data) {
Ray Milkey9f74c082015-02-11 15:40:16 -0800294 if (data.version() == null) { // recompiled intents will already have a version
Brian O'Connor47bc8552015-02-11 11:03:32 -0800295 data.setVersion(new SystemClockTimestamp());
296 }
Brian O'Connor2ba63fd2015-02-09 22:48:11 -0800297 synchronized (this) {
298 IntentData existingData = pending.get(data.key());
299 if (existingData == null ||
300 // existing version is strictly less than data's version
301 // Note: if they are equal, we already have the update
302 // TODO maybe we should still make this <= to be safe?
303 existingData.version().compareTo(data.version()) < 0) {
304 pending.put(data.key(), data);
305 checkNotNull(delegate, "Store delegate is not set")
306 .process(data);
307 notifyDelegate(IntentEvent.getEvent(data));
308 } else {
309 log.debug("IntentData {} is older than existing: {}",
310 data, existingData);
311 }
312 //TODO consider also checking the current map at this point
313 }
Brian O'Connorb488b192015-02-06 17:58:58 -0800314 }
315
Brian O'Connorb488b192015-02-06 17:58:58 -0800316 @Override
317 public boolean isMaster(Intent intent) {
318 return true;
319 }
320}