blob: cb982ba6fe8428e226254a6e9d996c7b774fa1ea [file] [log] [blame]
Brian O'Connorf3d06162014-10-02 15:54:12 -07001package org.onlab.onos.net.intent;
2
3import java.util.ArrayList;
4import java.util.Collections;
5import java.util.HashMap;
6import java.util.HashSet;
7import java.util.List;
8import java.util.Map;
9import java.util.Set;
10import java.util.concurrent.ExecutorService;
11import java.util.concurrent.Executors;
Thomas Vachuska1fb982f2014-10-22 14:09:17 -070012import java.util.concurrent.Future;
Brian O'Connorf3d06162014-10-02 15:54:12 -070013
14/**
Brian O'Connor66630c82014-10-02 21:08:19 -070015 * Fake implementation of the intent service to assist in developing tests of
16 * the interface contract.
Brian O'Connorf3d06162014-10-02 15:54:12 -070017 */
18public class FakeIntentManager implements TestableIntentService {
19
20 private final Map<IntentId, Intent> intents = new HashMap<>();
21 private final Map<IntentId, IntentState> intentStates = new HashMap<>();
Thomas Vachuskac96058a2014-10-20 23:00:16 -070022 private final Map<IntentId, List<Intent>> installables = new HashMap<>();
Brian O'Connor66630c82014-10-02 21:08:19 -070023 private final Set<IntentListener> listeners = new HashSet<>();
Brian O'Connorf3d06162014-10-02 15:54:12 -070024
25 private final Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> compilers = new HashMap<>();
Thomas Vachuskac96058a2014-10-20 23:00:16 -070026 private final Map<Class<? extends Intent>, IntentInstaller<? extends Intent>> installers
Brian O'Connor66630c82014-10-02 21:08:19 -070027 = new HashMap<>();
Brian O'Connorf3d06162014-10-02 15:54:12 -070028
29 private final ExecutorService executor = Executors.newSingleThreadExecutor();
30 private final List<IntentException> exceptions = new ArrayList<>();
31
32 @Override
33 public List<IntentException> getExceptions() {
34 return exceptions;
35 }
36
37 // Provides an out-of-thread simulation of intent submit life-cycle
38 private void executeSubmit(final Intent intent) {
39 registerSubclassCompilerIfNeeded(intent);
40 executor.execute(new Runnable() {
41 @Override
42 public void run() {
43 try {
tom85258ee2014-10-07 00:10:02 -070044 executeCompilingPhase(intent);
Brian O'Connorf3d06162014-10-02 15:54:12 -070045 } catch (IntentException e) {
46 exceptions.add(e);
47 }
48 }
49 });
50 }
51
52 // Provides an out-of-thread simulation of intent withdraw life-cycle
53 private void executeWithdraw(final Intent intent) {
54 executor.execute(new Runnable() {
55 @Override
56 public void run() {
57 try {
Thomas Vachuskac96058a2014-10-20 23:00:16 -070058 List<Intent> installable = getInstallable(intent.id());
tom85258ee2014-10-07 00:10:02 -070059 executeWithdrawingPhase(intent, installable);
Brian O'Connorf3d06162014-10-02 15:54:12 -070060 } catch (IntentException e) {
61 exceptions.add(e);
62 }
63
64 }
65 });
66 }
67
68 private <T extends Intent> IntentCompiler<T> getCompiler(T intent) {
69 @SuppressWarnings("unchecked")
70 IntentCompiler<T> compiler = (IntentCompiler<T>) compilers.get(intent.getClass());
71 if (compiler == null) {
72 throw new IntentException("no compiler for class " + intent.getClass());
73 }
74 return compiler;
75 }
76
Thomas Vachuskac96058a2014-10-20 23:00:16 -070077 private <T extends Intent> IntentInstaller<T> getInstaller(T intent) {
Brian O'Connorf3d06162014-10-02 15:54:12 -070078 @SuppressWarnings("unchecked")
Brian O'Connor66630c82014-10-02 21:08:19 -070079 IntentInstaller<T> installer = (IntentInstaller<T>) installers.get(intent
80 .getClass());
Brian O'Connorf3d06162014-10-02 15:54:12 -070081 if (installer == null) {
82 throw new IntentException("no installer for class " + intent.getClass());
83 }
84 return installer;
85 }
86
tom85258ee2014-10-07 00:10:02 -070087 private <T extends Intent> void executeCompilingPhase(T intent) {
88 setState(intent, IntentState.COMPILING);
Brian O'Connorf3d06162014-10-02 15:54:12 -070089 try {
90 // For the fake, we compile using a single level pass
Thomas Vachuskac96058a2014-10-20 23:00:16 -070091 List<Intent> installable = new ArrayList<>();
Brian O'Connorf3d06162014-10-02 15:54:12 -070092 for (Intent compiled : getCompiler(intent).compile(intent)) {
Thomas Vachuskac96058a2014-10-20 23:00:16 -070093 installable.add((Intent) compiled);
Brian O'Connorf3d06162014-10-02 15:54:12 -070094 }
tom85258ee2014-10-07 00:10:02 -070095 executeInstallingPhase(intent, installable);
96
Brian O'Connorf3d06162014-10-02 15:54:12 -070097 } catch (IntentException e) {
98 setState(intent, IntentState.FAILED);
tom85258ee2014-10-07 00:10:02 -070099 dispatch(new IntentEvent(IntentEvent.Type.FAILED, intent));
Brian O'Connorf3d06162014-10-02 15:54:12 -0700100 }
101 }
102
tom85258ee2014-10-07 00:10:02 -0700103 private void executeInstallingPhase(Intent intent,
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700104 List<Intent> installable) {
tom85258ee2014-10-07 00:10:02 -0700105 setState(intent, IntentState.INSTALLING);
Brian O'Connorf3d06162014-10-02 15:54:12 -0700106 try {
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700107 for (Intent ii : installable) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700108 registerSubclassInstallerIfNeeded(ii);
109 getInstaller(ii).install(ii);
110 }
111 setState(intent, IntentState.INSTALLED);
tom85258ee2014-10-07 00:10:02 -0700112 putInstallable(intent.id(), installable);
113 dispatch(new IntentEvent(IntentEvent.Type.INSTALLED, intent));
114
Brian O'Connorf3d06162014-10-02 15:54:12 -0700115 } catch (IntentException e) {
116 setState(intent, IntentState.FAILED);
tom85258ee2014-10-07 00:10:02 -0700117 dispatch(new IntentEvent(IntentEvent.Type.FAILED, intent));
Brian O'Connorf3d06162014-10-02 15:54:12 -0700118 }
119 }
120
tom85258ee2014-10-07 00:10:02 -0700121 private void executeWithdrawingPhase(Intent intent,
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700122 List<Intent> installable) {
tom85258ee2014-10-07 00:10:02 -0700123 setState(intent, IntentState.WITHDRAWING);
Brian O'Connorf3d06162014-10-02 15:54:12 -0700124 try {
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700125 for (Intent ii : installable) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700126 getInstaller(ii).uninstall(ii);
127 }
tom85258ee2014-10-07 00:10:02 -0700128 removeInstallable(intent.id());
Brian O'Connorf3d06162014-10-02 15:54:12 -0700129 setState(intent, IntentState.WITHDRAWN);
tom85258ee2014-10-07 00:10:02 -0700130 dispatch(new IntentEvent(IntentEvent.Type.WITHDRAWN, intent));
Brian O'Connorf3d06162014-10-02 15:54:12 -0700131 } catch (IntentException e) {
tom53945d52014-10-07 11:01:36 -0700132 // FIXME: Rework this to always go from WITHDRAWING to WITHDRAWN!
Brian O'Connorf3d06162014-10-02 15:54:12 -0700133 setState(intent, IntentState.FAILED);
tom85258ee2014-10-07 00:10:02 -0700134 dispatch(new IntentEvent(IntentEvent.Type.FAILED, intent));
Brian O'Connorf3d06162014-10-02 15:54:12 -0700135 }
136 }
137
Brian O'Connorf3d06162014-10-02 15:54:12 -0700138 // Sets the internal state for the given intent and dispatches an event
139 private void setState(Intent intent, IntentState state) {
tom85258ee2014-10-07 00:10:02 -0700140 intentStates.put(intent.id(), state);
Brian O'Connorf3d06162014-10-02 15:54:12 -0700141 }
142
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700143 private void putInstallable(IntentId id, List<Intent> installable) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700144 installables.put(id, installable);
145 }
146
147 private void removeInstallable(IntentId id) {
148 installables.remove(id);
149 }
150
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700151 private List<Intent> getInstallable(IntentId id) {
152 List<Intent> installable = installables.get(id);
Brian O'Connorf3d06162014-10-02 15:54:12 -0700153 if (installable != null) {
154 return installable;
155 } else {
156 return Collections.emptyList();
157 }
158 }
159
160 @Override
161 public void submit(Intent intent) {
tom85258ee2014-10-07 00:10:02 -0700162 intents.put(intent.id(), intent);
Brian O'Connorf3d06162014-10-02 15:54:12 -0700163 setState(intent, IntentState.SUBMITTED);
tom85258ee2014-10-07 00:10:02 -0700164 dispatch(new IntentEvent(IntentEvent.Type.SUBMITTED, intent));
Brian O'Connorf3d06162014-10-02 15:54:12 -0700165 executeSubmit(intent);
166 }
167
168 @Override
169 public void withdraw(Intent intent) {
tom85258ee2014-10-07 00:10:02 -0700170 intents.remove(intent.id());
Brian O'Connorf3d06162014-10-02 15:54:12 -0700171 executeWithdraw(intent);
172 }
173
174 @Override
Thomas Vachuska83e090e2014-10-22 14:25:35 -0700175 public void replace(IntentId oldIntentId, Intent newIntent) {
176 // TODO: implement later
177 }
178
179 @Override
Thomas Vachuska1fb982f2014-10-22 14:09:17 -0700180 public Future<IntentOperations> execute(IntentOperations operations) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700181 // TODO: implement later
Thomas Vachuska1fb982f2014-10-22 14:09:17 -0700182 return null;
Brian O'Connorf3d06162014-10-02 15:54:12 -0700183 }
184
185 @Override
186 public Set<Intent> getIntents() {
187 return Collections.unmodifiableSet(new HashSet<>(intents.values()));
188 }
189
190 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700191 public long getIntentCount() {
192 return intents.size();
193 }
194
195 @Override
Brian O'Connorf3d06162014-10-02 15:54:12 -0700196 public Intent getIntent(IntentId id) {
197 return intents.get(id);
198 }
199
200 @Override
201 public IntentState getIntentState(IntentId id) {
202 return intentStates.get(id);
203 }
204
205 @Override
Thomas Vachuska10d4abc2014-10-21 12:47:26 -0700206 public List<Intent> getInstallableIntents(IntentId intentId) {
207 return installables.get(intentId);
208 }
209
210 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700211 public void addListener(IntentListener listener) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700212 listeners.add(listener);
213 }
214
215 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700216 public void removeListener(IntentListener listener) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700217 listeners.remove(listener);
218 }
219
220 private void dispatch(IntentEvent event) {
Brian O'Connor66630c82014-10-02 21:08:19 -0700221 for (IntentListener listener : listeners) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700222 listener.event(event);
223 }
224 }
225
226 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700227 public <T extends Intent> void registerCompiler(Class<T> cls,
228 IntentCompiler<T> compiler) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700229 compilers.put(cls, compiler);
230 }
231
232 @Override
233 public <T extends Intent> void unregisterCompiler(Class<T> cls) {
234 compilers.remove(cls);
235 }
236
237 @Override
238 public Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> getCompilers() {
239 return Collections.unmodifiableMap(compilers);
240 }
241
242 @Override
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700243 public <T extends Intent> void registerInstaller(Class<T> cls,
Brian O'Connor66630c82014-10-02 21:08:19 -0700244 IntentInstaller<T> installer) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700245 installers.put(cls, installer);
246 }
247
248 @Override
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700249 public <T extends Intent> void unregisterInstaller(Class<T> cls) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700250 installers.remove(cls);
251 }
252
253 @Override
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700254 public Map<Class<? extends Intent>,
255 IntentInstaller<? extends Intent>> getInstallers() {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700256 return Collections.unmodifiableMap(installers);
257 }
258
259 private void registerSubclassCompilerIfNeeded(Intent intent) {
260 if (!compilers.containsKey(intent.getClass())) {
261 Class<?> cls = intent.getClass();
262 while (cls != Object.class) {
263 // As long as we're within the Intent class descendants
264 if (Intent.class.isAssignableFrom(cls)) {
265 IntentCompiler<?> compiler = compilers.get(cls);
266 if (compiler != null) {
267 compilers.put(intent.getClass(), compiler);
268 return;
269 }
270 }
271 cls = cls.getSuperclass();
272 }
273 }
274 }
275
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700276 private void registerSubclassInstallerIfNeeded(Intent intent) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700277 if (!installers.containsKey(intent.getClass())) {
278 Class<?> cls = intent.getClass();
279 while (cls != Object.class) {
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700280 // As long as we're within the Intent class
Brian O'Connor66630c82014-10-02 21:08:19 -0700281 // descendants
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700282 if (Intent.class.isAssignableFrom(cls)) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700283 IntentInstaller<?> installer = installers.get(cls);
284 if (installer != null) {
285 installers.put(intent.getClass(), installer);
286 return;
287 }
288 }
289 cls = cls.getSuperclass();
290 }
291 }
292 }
293
294}