blob: 5020459e4e9e28dffbe47f2a8bf58fb5d85b4f2e [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;
12
13/**
Brian O'Connor66630c82014-10-02 21:08:19 -070014 * Fake implementation of the intent service to assist in developing tests of
15 * the interface contract.
Brian O'Connorf3d06162014-10-02 15:54:12 -070016 */
17public class FakeIntentManager implements TestableIntentService {
18
19 private final Map<IntentId, Intent> intents = new HashMap<>();
20 private final Map<IntentId, IntentState> intentStates = new HashMap<>();
Thomas Vachuskac96058a2014-10-20 23:00:16 -070021 private final Map<IntentId, List<Intent>> installables = new HashMap<>();
Brian O'Connor66630c82014-10-02 21:08:19 -070022 private final Set<IntentListener> listeners = new HashSet<>();
Brian O'Connorf3d06162014-10-02 15:54:12 -070023
24 private final Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> compilers = new HashMap<>();
Thomas Vachuskac96058a2014-10-20 23:00:16 -070025 private final Map<Class<? extends Intent>, IntentInstaller<? extends Intent>> installers
Brian O'Connor66630c82014-10-02 21:08:19 -070026 = new HashMap<>();
Brian O'Connorf3d06162014-10-02 15:54:12 -070027
28 private final ExecutorService executor = Executors.newSingleThreadExecutor();
29 private final List<IntentException> exceptions = new ArrayList<>();
30
31 @Override
32 public List<IntentException> getExceptions() {
33 return exceptions;
34 }
35
36 // Provides an out-of-thread simulation of intent submit life-cycle
37 private void executeSubmit(final Intent intent) {
38 registerSubclassCompilerIfNeeded(intent);
39 executor.execute(new Runnable() {
40 @Override
41 public void run() {
42 try {
tom85258ee2014-10-07 00:10:02 -070043 executeCompilingPhase(intent);
Brian O'Connorf3d06162014-10-02 15:54:12 -070044 } catch (IntentException e) {
45 exceptions.add(e);
46 }
47 }
48 });
49 }
50
51 // Provides an out-of-thread simulation of intent withdraw life-cycle
52 private void executeWithdraw(final Intent intent) {
53 executor.execute(new Runnable() {
54 @Override
55 public void run() {
56 try {
Thomas Vachuskac96058a2014-10-20 23:00:16 -070057 List<Intent> installable = getInstallable(intent.id());
tom85258ee2014-10-07 00:10:02 -070058 executeWithdrawingPhase(intent, installable);
Brian O'Connorf3d06162014-10-02 15:54:12 -070059 } catch (IntentException e) {
60 exceptions.add(e);
61 }
62
63 }
64 });
65 }
66
67 private <T extends Intent> IntentCompiler<T> getCompiler(T intent) {
68 @SuppressWarnings("unchecked")
69 IntentCompiler<T> compiler = (IntentCompiler<T>) compilers.get(intent.getClass());
70 if (compiler == null) {
71 throw new IntentException("no compiler for class " + intent.getClass());
72 }
73 return compiler;
74 }
75
Thomas Vachuskac96058a2014-10-20 23:00:16 -070076 private <T extends Intent> IntentInstaller<T> getInstaller(T intent) {
Brian O'Connorf3d06162014-10-02 15:54:12 -070077 @SuppressWarnings("unchecked")
Brian O'Connor66630c82014-10-02 21:08:19 -070078 IntentInstaller<T> installer = (IntentInstaller<T>) installers.get(intent
79 .getClass());
Brian O'Connorf3d06162014-10-02 15:54:12 -070080 if (installer == null) {
81 throw new IntentException("no installer for class " + intent.getClass());
82 }
83 return installer;
84 }
85
tom85258ee2014-10-07 00:10:02 -070086 private <T extends Intent> void executeCompilingPhase(T intent) {
87 setState(intent, IntentState.COMPILING);
Brian O'Connorf3d06162014-10-02 15:54:12 -070088 try {
89 // For the fake, we compile using a single level pass
Thomas Vachuskac96058a2014-10-20 23:00:16 -070090 List<Intent> installable = new ArrayList<>();
Brian O'Connorf3d06162014-10-02 15:54:12 -070091 for (Intent compiled : getCompiler(intent).compile(intent)) {
Thomas Vachuskac96058a2014-10-20 23:00:16 -070092 installable.add((Intent) compiled);
Brian O'Connorf3d06162014-10-02 15:54:12 -070093 }
tom85258ee2014-10-07 00:10:02 -070094 executeInstallingPhase(intent, installable);
95
Brian O'Connorf3d06162014-10-02 15:54:12 -070096 } catch (IntentException e) {
97 setState(intent, IntentState.FAILED);
tom85258ee2014-10-07 00:10:02 -070098 dispatch(new IntentEvent(IntentEvent.Type.FAILED, intent));
Brian O'Connorf3d06162014-10-02 15:54:12 -070099 }
100 }
101
tom85258ee2014-10-07 00:10:02 -0700102 private void executeInstallingPhase(Intent intent,
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700103 List<Intent> installable) {
tom85258ee2014-10-07 00:10:02 -0700104 setState(intent, IntentState.INSTALLING);
Brian O'Connorf3d06162014-10-02 15:54:12 -0700105 try {
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700106 for (Intent ii : installable) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700107 registerSubclassInstallerIfNeeded(ii);
108 getInstaller(ii).install(ii);
109 }
110 setState(intent, IntentState.INSTALLED);
tom85258ee2014-10-07 00:10:02 -0700111 putInstallable(intent.id(), installable);
112 dispatch(new IntentEvent(IntentEvent.Type.INSTALLED, intent));
113
Brian O'Connorf3d06162014-10-02 15:54:12 -0700114 } catch (IntentException e) {
115 setState(intent, IntentState.FAILED);
tom85258ee2014-10-07 00:10:02 -0700116 dispatch(new IntentEvent(IntentEvent.Type.FAILED, intent));
Brian O'Connorf3d06162014-10-02 15:54:12 -0700117 }
118 }
119
tom85258ee2014-10-07 00:10:02 -0700120 private void executeWithdrawingPhase(Intent intent,
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700121 List<Intent> installable) {
tom85258ee2014-10-07 00:10:02 -0700122 setState(intent, IntentState.WITHDRAWING);
Brian O'Connorf3d06162014-10-02 15:54:12 -0700123 try {
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700124 for (Intent ii : installable) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700125 getInstaller(ii).uninstall(ii);
126 }
tom85258ee2014-10-07 00:10:02 -0700127 removeInstallable(intent.id());
Brian O'Connorf3d06162014-10-02 15:54:12 -0700128 setState(intent, IntentState.WITHDRAWN);
tom85258ee2014-10-07 00:10:02 -0700129 dispatch(new IntentEvent(IntentEvent.Type.WITHDRAWN, intent));
Brian O'Connorf3d06162014-10-02 15:54:12 -0700130 } catch (IntentException e) {
tom53945d52014-10-07 11:01:36 -0700131 // FIXME: Rework this to always go from WITHDRAWING to WITHDRAWN!
Brian O'Connorf3d06162014-10-02 15:54:12 -0700132 setState(intent, IntentState.FAILED);
tom85258ee2014-10-07 00:10:02 -0700133 dispatch(new IntentEvent(IntentEvent.Type.FAILED, intent));
Brian O'Connorf3d06162014-10-02 15:54:12 -0700134 }
135 }
136
Brian O'Connorf3d06162014-10-02 15:54:12 -0700137 // Sets the internal state for the given intent and dispatches an event
138 private void setState(Intent intent, IntentState state) {
tom85258ee2014-10-07 00:10:02 -0700139 intentStates.put(intent.id(), state);
Brian O'Connorf3d06162014-10-02 15:54:12 -0700140 }
141
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700142 private void putInstallable(IntentId id, List<Intent> installable) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700143 installables.put(id, installable);
144 }
145
146 private void removeInstallable(IntentId id) {
147 installables.remove(id);
148 }
149
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700150 private List<Intent> getInstallable(IntentId id) {
151 List<Intent> installable = installables.get(id);
Brian O'Connorf3d06162014-10-02 15:54:12 -0700152 if (installable != null) {
153 return installable;
154 } else {
155 return Collections.emptyList();
156 }
157 }
158
159 @Override
160 public void submit(Intent intent) {
tom85258ee2014-10-07 00:10:02 -0700161 intents.put(intent.id(), intent);
Brian O'Connorf3d06162014-10-02 15:54:12 -0700162 setState(intent, IntentState.SUBMITTED);
tom85258ee2014-10-07 00:10:02 -0700163 dispatch(new IntentEvent(IntentEvent.Type.SUBMITTED, intent));
Brian O'Connorf3d06162014-10-02 15:54:12 -0700164 executeSubmit(intent);
165 }
166
167 @Override
168 public void withdraw(Intent intent) {
tom85258ee2014-10-07 00:10:02 -0700169 intents.remove(intent.id());
Brian O'Connorf3d06162014-10-02 15:54:12 -0700170 executeWithdraw(intent);
171 }
172
173 @Override
174 public void execute(IntentOperations operations) {
175 // TODO: implement later
176 }
177
178 @Override
179 public Set<Intent> getIntents() {
180 return Collections.unmodifiableSet(new HashSet<>(intents.values()));
181 }
182
183 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700184 public long getIntentCount() {
185 return intents.size();
186 }
187
188 @Override
Brian O'Connorf3d06162014-10-02 15:54:12 -0700189 public Intent getIntent(IntentId id) {
190 return intents.get(id);
191 }
192
193 @Override
194 public IntentState getIntentState(IntentId id) {
195 return intentStates.get(id);
196 }
197
198 @Override
Thomas Vachuska10d4abc2014-10-21 12:47:26 -0700199 public List<Intent> getInstallableIntents(IntentId intentId) {
200 return installables.get(intentId);
201 }
202
203 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700204 public void addListener(IntentListener listener) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700205 listeners.add(listener);
206 }
207
208 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700209 public void removeListener(IntentListener listener) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700210 listeners.remove(listener);
211 }
212
213 private void dispatch(IntentEvent event) {
Brian O'Connor66630c82014-10-02 21:08:19 -0700214 for (IntentListener listener : listeners) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700215 listener.event(event);
216 }
217 }
218
219 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700220 public <T extends Intent> void registerCompiler(Class<T> cls,
221 IntentCompiler<T> compiler) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700222 compilers.put(cls, compiler);
223 }
224
225 @Override
226 public <T extends Intent> void unregisterCompiler(Class<T> cls) {
227 compilers.remove(cls);
228 }
229
230 @Override
231 public Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> getCompilers() {
232 return Collections.unmodifiableMap(compilers);
233 }
234
235 @Override
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700236 public <T extends Intent> void registerInstaller(Class<T> cls,
Brian O'Connor66630c82014-10-02 21:08:19 -0700237 IntentInstaller<T> installer) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700238 installers.put(cls, installer);
239 }
240
241 @Override
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700242 public <T extends Intent> void unregisterInstaller(Class<T> cls) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700243 installers.remove(cls);
244 }
245
246 @Override
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700247 public Map<Class<? extends Intent>,
248 IntentInstaller<? extends Intent>> getInstallers() {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700249 return Collections.unmodifiableMap(installers);
250 }
251
252 private void registerSubclassCompilerIfNeeded(Intent intent) {
253 if (!compilers.containsKey(intent.getClass())) {
254 Class<?> cls = intent.getClass();
255 while (cls != Object.class) {
256 // As long as we're within the Intent class descendants
257 if (Intent.class.isAssignableFrom(cls)) {
258 IntentCompiler<?> compiler = compilers.get(cls);
259 if (compiler != null) {
260 compilers.put(intent.getClass(), compiler);
261 return;
262 }
263 }
264 cls = cls.getSuperclass();
265 }
266 }
267 }
268
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700269 private void registerSubclassInstallerIfNeeded(Intent intent) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700270 if (!installers.containsKey(intent.getClass())) {
271 Class<?> cls = intent.getClass();
272 while (cls != Object.class) {
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700273 // As long as we're within the Intent class
Brian O'Connor66630c82014-10-02 21:08:19 -0700274 // descendants
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700275 if (Intent.class.isAssignableFrom(cls)) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700276 IntentInstaller<?> installer = installers.get(cls);
277 if (installer != null) {
278 installers.put(intent.getClass(), installer);
279 return;
280 }
281 }
282 cls = cls.getSuperclass();
283 }
284 }
285 }
286
287}