blob: dca55d1d94fd4dee79b65731816fb1c21068f36b [file] [log] [blame]
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07001/*
2 * Copyright 2014 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 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.net.intent;
Brian O'Connorf3d06162014-10-02 15:54:12 -070017
18import java.util.ArrayList;
19import java.util.Collections;
20import java.util.HashMap;
21import java.util.HashSet;
22import java.util.List;
23import java.util.Map;
24import java.util.Set;
25import java.util.concurrent.ExecutorService;
26import java.util.concurrent.Executors;
27
28/**
Brian O'Connor66630c82014-10-02 21:08:19 -070029 * Fake implementation of the intent service to assist in developing tests of
30 * the interface contract.
Brian O'Connorf3d06162014-10-02 15:54:12 -070031 */
32public class FakeIntentManager implements TestableIntentService {
33
Ray Milkey4f5d93e2015-02-10 17:04:10 -080034 private final Map<Key, Intent> intents = new HashMap<>();
35 private final Map<Key, IntentState> intentStates = new HashMap<>();
36 private final Map<Key, List<Intent>> installables = new HashMap<>();
Brian O'Connor66630c82014-10-02 21:08:19 -070037 private final Set<IntentListener> listeners = new HashSet<>();
Brian O'Connorf3d06162014-10-02 15:54:12 -070038
39 private final Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> compilers = new HashMap<>();
Thomas Vachuskac96058a2014-10-20 23:00:16 -070040 private final Map<Class<? extends Intent>, IntentInstaller<? extends Intent>> installers
Brian O'Connor66630c82014-10-02 21:08:19 -070041 = new HashMap<>();
Brian O'Connorf3d06162014-10-02 15:54:12 -070042
43 private final ExecutorService executor = Executors.newSingleThreadExecutor();
44 private final List<IntentException> exceptions = new ArrayList<>();
45
46 @Override
47 public List<IntentException> getExceptions() {
48 return exceptions;
49 }
50
51 // Provides an out-of-thread simulation of intent submit life-cycle
52 private void executeSubmit(final Intent intent) {
53 registerSubclassCompilerIfNeeded(intent);
54 executor.execute(new Runnable() {
55 @Override
56 public void run() {
57 try {
tom85258ee2014-10-07 00:10:02 -070058 executeCompilingPhase(intent);
Brian O'Connorf3d06162014-10-02 15:54:12 -070059 } catch (IntentException e) {
60 exceptions.add(e);
61 }
62 }
63 });
64 }
65
66 // Provides an out-of-thread simulation of intent withdraw life-cycle
67 private void executeWithdraw(final Intent intent) {
68 executor.execute(new Runnable() {
69 @Override
70 public void run() {
71 try {
Ray Milkey4f5d93e2015-02-10 17:04:10 -080072 List<Intent> installable = getInstallable(intent.key());
tom85258ee2014-10-07 00:10:02 -070073 executeWithdrawingPhase(intent, installable);
Brian O'Connorf3d06162014-10-02 15:54:12 -070074 } catch (IntentException e) {
75 exceptions.add(e);
76 }
77
78 }
79 });
80 }
81
82 private <T extends Intent> IntentCompiler<T> getCompiler(T intent) {
83 @SuppressWarnings("unchecked")
84 IntentCompiler<T> compiler = (IntentCompiler<T>) compilers.get(intent.getClass());
85 if (compiler == null) {
86 throw new IntentException("no compiler for class " + intent.getClass());
87 }
88 return compiler;
89 }
90
Thomas Vachuskac96058a2014-10-20 23:00:16 -070091 private <T extends Intent> IntentInstaller<T> getInstaller(T intent) {
Brian O'Connorf3d06162014-10-02 15:54:12 -070092 @SuppressWarnings("unchecked")
Brian O'Connor66630c82014-10-02 21:08:19 -070093 IntentInstaller<T> installer = (IntentInstaller<T>) installers.get(intent
94 .getClass());
Brian O'Connorf3d06162014-10-02 15:54:12 -070095 if (installer == null) {
96 throw new IntentException("no installer for class " + intent.getClass());
97 }
98 return installer;
99 }
100
tom85258ee2014-10-07 00:10:02 -0700101 private <T extends Intent> void executeCompilingPhase(T intent) {
102 setState(intent, IntentState.COMPILING);
Brian O'Connorf3d06162014-10-02 15:54:12 -0700103 try {
104 // For the fake, we compile using a single level pass
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700105 List<Intent> installable = new ArrayList<>();
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700106 for (Intent compiled : getCompiler(intent).compile(intent, null, null)) {
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700107 installable.add((Intent) compiled);
Brian O'Connorf3d06162014-10-02 15:54:12 -0700108 }
tom85258ee2014-10-07 00:10:02 -0700109 executeInstallingPhase(intent, installable);
110
Brian O'Connorf3d06162014-10-02 15:54:12 -0700111 } catch (IntentException e) {
112 setState(intent, IntentState.FAILED);
tom85258ee2014-10-07 00:10:02 -0700113 dispatch(new IntentEvent(IntentEvent.Type.FAILED, intent));
Brian O'Connorf3d06162014-10-02 15:54:12 -0700114 }
115 }
116
tom85258ee2014-10-07 00:10:02 -0700117 private void executeInstallingPhase(Intent intent,
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700118 List<Intent> installable) {
tom85258ee2014-10-07 00:10:02 -0700119 setState(intent, IntentState.INSTALLING);
Brian O'Connorf3d06162014-10-02 15:54:12 -0700120 try {
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700121 for (Intent ii : installable) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700122 registerSubclassInstallerIfNeeded(ii);
123 getInstaller(ii).install(ii);
124 }
125 setState(intent, IntentState.INSTALLED);
Ray Milkey4f5d93e2015-02-10 17:04:10 -0800126 putInstallable(intent.key(), installable);
tom85258ee2014-10-07 00:10:02 -0700127 dispatch(new IntentEvent(IntentEvent.Type.INSTALLED, intent));
128
Brian O'Connorf3d06162014-10-02 15:54:12 -0700129 } catch (IntentException e) {
130 setState(intent, IntentState.FAILED);
tom85258ee2014-10-07 00:10:02 -0700131 dispatch(new IntentEvent(IntentEvent.Type.FAILED, intent));
Brian O'Connorf3d06162014-10-02 15:54:12 -0700132 }
133 }
134
tom85258ee2014-10-07 00:10:02 -0700135 private void executeWithdrawingPhase(Intent intent,
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700136 List<Intent> installable) {
tom85258ee2014-10-07 00:10:02 -0700137 setState(intent, IntentState.WITHDRAWING);
Brian O'Connorf3d06162014-10-02 15:54:12 -0700138 try {
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700139 for (Intent ii : installable) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700140 getInstaller(ii).uninstall(ii);
141 }
Ray Milkey4f5d93e2015-02-10 17:04:10 -0800142 removeInstallable(intent.key());
Brian O'Connorf3d06162014-10-02 15:54:12 -0700143 setState(intent, IntentState.WITHDRAWN);
tom85258ee2014-10-07 00:10:02 -0700144 dispatch(new IntentEvent(IntentEvent.Type.WITHDRAWN, intent));
Brian O'Connorf3d06162014-10-02 15:54:12 -0700145 } catch (IntentException e) {
tom53945d52014-10-07 11:01:36 -0700146 // FIXME: Rework this to always go from WITHDRAWING to WITHDRAWN!
Brian O'Connorf3d06162014-10-02 15:54:12 -0700147 setState(intent, IntentState.FAILED);
tom85258ee2014-10-07 00:10:02 -0700148 dispatch(new IntentEvent(IntentEvent.Type.FAILED, intent));
Brian O'Connorf3d06162014-10-02 15:54:12 -0700149 }
150 }
151
Brian O'Connorf3d06162014-10-02 15:54:12 -0700152 // Sets the internal state for the given intent and dispatches an event
153 private void setState(Intent intent, IntentState state) {
Ray Milkey4f5d93e2015-02-10 17:04:10 -0800154 intentStates.put(intent.key(), state);
Brian O'Connorf3d06162014-10-02 15:54:12 -0700155 }
156
Ray Milkey4f5d93e2015-02-10 17:04:10 -0800157 private void putInstallable(Key key, List<Intent> installable) {
158 installables.put(key, installable);
Brian O'Connorf3d06162014-10-02 15:54:12 -0700159 }
160
Ray Milkey4f5d93e2015-02-10 17:04:10 -0800161 private void removeInstallable(Key key) {
162 installables.remove(key);
Brian O'Connorf3d06162014-10-02 15:54:12 -0700163 }
164
Ray Milkey4f5d93e2015-02-10 17:04:10 -0800165 private List<Intent> getInstallable(Key key) {
166 List<Intent> installable = installables.get(key);
Brian O'Connorf3d06162014-10-02 15:54:12 -0700167 if (installable != null) {
168 return installable;
169 } else {
170 return Collections.emptyList();
171 }
172 }
173
174 @Override
175 public void submit(Intent intent) {
Ray Milkey4f5d93e2015-02-10 17:04:10 -0800176 intents.put(intent.key(), intent);
Brian O'Connor7a71d5d2014-12-02 00:12:27 -0800177 setState(intent, IntentState.INSTALL_REQ);
178 dispatch(new IntentEvent(IntentEvent.Type.INSTALL_REQ, intent));
Brian O'Connorf3d06162014-10-02 15:54:12 -0700179 executeSubmit(intent);
180 }
181
182 @Override
183 public void withdraw(Intent intent) {
Ray Milkey4f5d93e2015-02-10 17:04:10 -0800184 intents.remove(intent.key());
Brian O'Connorf3d06162014-10-02 15:54:12 -0700185 executeWithdraw(intent);
186 }
187
188 @Override
Ray Milkey8c6d00e2015-03-13 14:14:34 -0700189 public void purge(Intent intent) {
190 IntentState currentState = intentStates.get(intent.key());
191 if (currentState == IntentState.WITHDRAWN
192 || currentState == IntentState.FAILED) {
193 intents.remove(intent.key());
194 installables.remove(intent.key());
195 intentStates.remove(intent.key());
196 }
197 }
198
199 @Override
Brian O'Connorf3d06162014-10-02 15:54:12 -0700200 public Set<Intent> getIntents() {
201 return Collections.unmodifiableSet(new HashSet<>(intents.values()));
202 }
203
204 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700205 public long getIntentCount() {
206 return intents.size();
207 }
208
209 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800210 public Intent getIntent(Key intentKey) {
211 return intents.get(intentKey);
Brian O'Connorf3d06162014-10-02 15:54:12 -0700212 }
213
214 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800215 public IntentState getIntentState(Key intentKey) {
216 return intentStates.get(intentKey);
Brian O'Connorf3d06162014-10-02 15:54:12 -0700217 }
218
219 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800220 public List<Intent> getInstallableIntents(Key intentKey) {
221 return installables.get(intentKey);
Thomas Vachuska10d4abc2014-10-21 12:47:26 -0700222 }
223
224 @Override
Jonathan Hart13d3dd92015-02-25 16:09:42 -0800225 public boolean isLocal(Key intentKey) {
226 return true;
227 }
228
229 @Override
230 public Iterable<Intent> getPending() {
231 return Collections.emptyList();
232 }
233
234 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700235 public void addListener(IntentListener listener) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700236 listeners.add(listener);
237 }
238
239 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700240 public void removeListener(IntentListener listener) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700241 listeners.remove(listener);
242 }
243
244 private void dispatch(IntentEvent event) {
Brian O'Connor66630c82014-10-02 21:08:19 -0700245 for (IntentListener listener : listeners) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700246 listener.event(event);
247 }
248 }
249
250 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700251 public <T extends Intent> void registerCompiler(Class<T> cls,
252 IntentCompiler<T> compiler) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700253 compilers.put(cls, compiler);
254 }
255
256 @Override
257 public <T extends Intent> void unregisterCompiler(Class<T> cls) {
258 compilers.remove(cls);
259 }
260
261 @Override
262 public Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> getCompilers() {
263 return Collections.unmodifiableMap(compilers);
264 }
265
266 @Override
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700267 public <T extends Intent> void registerInstaller(Class<T> cls,
Brian O'Connor66630c82014-10-02 21:08:19 -0700268 IntentInstaller<T> installer) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700269 installers.put(cls, installer);
270 }
271
272 @Override
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700273 public <T extends Intent> void unregisterInstaller(Class<T> cls) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700274 installers.remove(cls);
275 }
276
277 @Override
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700278 public Map<Class<? extends Intent>,
279 IntentInstaller<? extends Intent>> getInstallers() {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700280 return Collections.unmodifiableMap(installers);
281 }
282
283 private void registerSubclassCompilerIfNeeded(Intent intent) {
284 if (!compilers.containsKey(intent.getClass())) {
285 Class<?> cls = intent.getClass();
286 while (cls != Object.class) {
287 // As long as we're within the Intent class descendants
288 if (Intent.class.isAssignableFrom(cls)) {
289 IntentCompiler<?> compiler = compilers.get(cls);
290 if (compiler != null) {
291 compilers.put(intent.getClass(), compiler);
292 return;
293 }
294 }
295 cls = cls.getSuperclass();
296 }
297 }
298 }
299
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700300 private void registerSubclassInstallerIfNeeded(Intent intent) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700301 if (!installers.containsKey(intent.getClass())) {
302 Class<?> cls = intent.getClass();
303 while (cls != Object.class) {
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700304 // As long as we're within the Intent class
Brian O'Connor66630c82014-10-02 21:08:19 -0700305 // descendants
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700306 if (Intent.class.isAssignableFrom(cls)) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700307 IntentInstaller<?> installer = installers.get(cls);
308 if (installer != null) {
309 installers.put(intent.getClass(), installer);
310 return;
311 }
312 }
313 cls = cls.getSuperclass();
314 }
315 }
316 }
317
318}