blob: 9f4755ae81488a9e06da3e1a8ff82f2b54953f03 [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'Connorf3d06162014-10-02 15:54:12 -070016package org.onlab.onos.net.intent;
17
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;
Thomas Vachuska1fb982f2014-10-22 14:09:17 -070027import java.util.concurrent.Future;
Brian O'Connorf3d06162014-10-02 15:54:12 -070028
29/**
Brian O'Connor66630c82014-10-02 21:08:19 -070030 * Fake implementation of the intent service to assist in developing tests of
31 * the interface contract.
Brian O'Connorf3d06162014-10-02 15:54:12 -070032 */
33public class FakeIntentManager implements TestableIntentService {
34
35 private final Map<IntentId, Intent> intents = new HashMap<>();
36 private final Map<IntentId, IntentState> intentStates = new HashMap<>();
Thomas Vachuskac96058a2014-10-20 23:00:16 -070037 private final Map<IntentId, List<Intent>> installables = new HashMap<>();
Brian O'Connor66630c82014-10-02 21:08:19 -070038 private final Set<IntentListener> listeners = new HashSet<>();
Brian O'Connorf3d06162014-10-02 15:54:12 -070039
40 private final Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> compilers = new HashMap<>();
Thomas Vachuskac96058a2014-10-20 23:00:16 -070041 private final Map<Class<? extends Intent>, IntentInstaller<? extends Intent>> installers
Brian O'Connor66630c82014-10-02 21:08:19 -070042 = new HashMap<>();
Brian O'Connorf3d06162014-10-02 15:54:12 -070043
44 private final ExecutorService executor = Executors.newSingleThreadExecutor();
45 private final List<IntentException> exceptions = new ArrayList<>();
46
47 @Override
48 public List<IntentException> getExceptions() {
49 return exceptions;
50 }
51
52 // Provides an out-of-thread simulation of intent submit life-cycle
53 private void executeSubmit(final Intent intent) {
54 registerSubclassCompilerIfNeeded(intent);
55 executor.execute(new Runnable() {
56 @Override
57 public void run() {
58 try {
tom85258ee2014-10-07 00:10:02 -070059 executeCompilingPhase(intent);
Brian O'Connorf3d06162014-10-02 15:54:12 -070060 } catch (IntentException e) {
61 exceptions.add(e);
62 }
63 }
64 });
65 }
66
67 // Provides an out-of-thread simulation of intent withdraw life-cycle
68 private void executeWithdraw(final Intent intent) {
69 executor.execute(new Runnable() {
70 @Override
71 public void run() {
72 try {
Thomas Vachuskac96058a2014-10-20 23:00:16 -070073 List<Intent> installable = getInstallable(intent.id());
tom85258ee2014-10-07 00:10:02 -070074 executeWithdrawingPhase(intent, installable);
Brian O'Connorf3d06162014-10-02 15:54:12 -070075 } catch (IntentException e) {
76 exceptions.add(e);
77 }
78
79 }
80 });
81 }
82
83 private <T extends Intent> IntentCompiler<T> getCompiler(T intent) {
84 @SuppressWarnings("unchecked")
85 IntentCompiler<T> compiler = (IntentCompiler<T>) compilers.get(intent.getClass());
86 if (compiler == null) {
87 throw new IntentException("no compiler for class " + intent.getClass());
88 }
89 return compiler;
90 }
91
Thomas Vachuskac96058a2014-10-20 23:00:16 -070092 private <T extends Intent> IntentInstaller<T> getInstaller(T intent) {
Brian O'Connorf3d06162014-10-02 15:54:12 -070093 @SuppressWarnings("unchecked")
Brian O'Connor66630c82014-10-02 21:08:19 -070094 IntentInstaller<T> installer = (IntentInstaller<T>) installers.get(intent
95 .getClass());
Brian O'Connorf3d06162014-10-02 15:54:12 -070096 if (installer == null) {
97 throw new IntentException("no installer for class " + intent.getClass());
98 }
99 return installer;
100 }
101
tom85258ee2014-10-07 00:10:02 -0700102 private <T extends Intent> void executeCompilingPhase(T intent) {
103 setState(intent, IntentState.COMPILING);
Brian O'Connorf3d06162014-10-02 15:54:12 -0700104 try {
105 // For the fake, we compile using a single level pass
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700106 List<Intent> installable = new ArrayList<>();
Brian O'Connorf3d06162014-10-02 15:54:12 -0700107 for (Intent compiled : getCompiler(intent).compile(intent)) {
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700108 installable.add((Intent) compiled);
Brian O'Connorf3d06162014-10-02 15:54:12 -0700109 }
tom85258ee2014-10-07 00:10:02 -0700110 executeInstallingPhase(intent, installable);
111
Brian O'Connorf3d06162014-10-02 15:54:12 -0700112 } catch (IntentException e) {
113 setState(intent, IntentState.FAILED);
tom85258ee2014-10-07 00:10:02 -0700114 dispatch(new IntentEvent(IntentEvent.Type.FAILED, intent));
Brian O'Connorf3d06162014-10-02 15:54:12 -0700115 }
116 }
117
tom85258ee2014-10-07 00:10:02 -0700118 private void executeInstallingPhase(Intent intent,
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700119 List<Intent> installable) {
tom85258ee2014-10-07 00:10:02 -0700120 setState(intent, IntentState.INSTALLING);
Brian O'Connorf3d06162014-10-02 15:54:12 -0700121 try {
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700122 for (Intent ii : installable) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700123 registerSubclassInstallerIfNeeded(ii);
124 getInstaller(ii).install(ii);
125 }
126 setState(intent, IntentState.INSTALLED);
tom85258ee2014-10-07 00:10:02 -0700127 putInstallable(intent.id(), installable);
128 dispatch(new IntentEvent(IntentEvent.Type.INSTALLED, intent));
129
Brian O'Connorf3d06162014-10-02 15:54:12 -0700130 } catch (IntentException e) {
131 setState(intent, IntentState.FAILED);
tom85258ee2014-10-07 00:10:02 -0700132 dispatch(new IntentEvent(IntentEvent.Type.FAILED, intent));
Brian O'Connorf3d06162014-10-02 15:54:12 -0700133 }
134 }
135
tom85258ee2014-10-07 00:10:02 -0700136 private void executeWithdrawingPhase(Intent intent,
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700137 List<Intent> installable) {
tom85258ee2014-10-07 00:10:02 -0700138 setState(intent, IntentState.WITHDRAWING);
Brian O'Connorf3d06162014-10-02 15:54:12 -0700139 try {
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700140 for (Intent ii : installable) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700141 getInstaller(ii).uninstall(ii);
142 }
tom85258ee2014-10-07 00:10:02 -0700143 removeInstallable(intent.id());
Brian O'Connorf3d06162014-10-02 15:54:12 -0700144 setState(intent, IntentState.WITHDRAWN);
tom85258ee2014-10-07 00:10:02 -0700145 dispatch(new IntentEvent(IntentEvent.Type.WITHDRAWN, intent));
Brian O'Connorf3d06162014-10-02 15:54:12 -0700146 } catch (IntentException e) {
tom53945d52014-10-07 11:01:36 -0700147 // FIXME: Rework this to always go from WITHDRAWING to WITHDRAWN!
Brian O'Connorf3d06162014-10-02 15:54:12 -0700148 setState(intent, IntentState.FAILED);
tom85258ee2014-10-07 00:10:02 -0700149 dispatch(new IntentEvent(IntentEvent.Type.FAILED, intent));
Brian O'Connorf3d06162014-10-02 15:54:12 -0700150 }
151 }
152
Brian O'Connorf3d06162014-10-02 15:54:12 -0700153 // Sets the internal state for the given intent and dispatches an event
154 private void setState(Intent intent, IntentState state) {
tom85258ee2014-10-07 00:10:02 -0700155 intentStates.put(intent.id(), state);
Brian O'Connorf3d06162014-10-02 15:54:12 -0700156 }
157
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700158 private void putInstallable(IntentId id, List<Intent> installable) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700159 installables.put(id, installable);
160 }
161
162 private void removeInstallable(IntentId id) {
163 installables.remove(id);
164 }
165
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700166 private List<Intent> getInstallable(IntentId id) {
167 List<Intent> installable = installables.get(id);
Brian O'Connorf3d06162014-10-02 15:54:12 -0700168 if (installable != null) {
169 return installable;
170 } else {
171 return Collections.emptyList();
172 }
173 }
174
175 @Override
176 public void submit(Intent intent) {
tom85258ee2014-10-07 00:10:02 -0700177 intents.put(intent.id(), intent);
Brian O'Connorf3d06162014-10-02 15:54:12 -0700178 setState(intent, IntentState.SUBMITTED);
tom85258ee2014-10-07 00:10:02 -0700179 dispatch(new IntentEvent(IntentEvent.Type.SUBMITTED, intent));
Brian O'Connorf3d06162014-10-02 15:54:12 -0700180 executeSubmit(intent);
181 }
182
183 @Override
184 public void withdraw(Intent intent) {
tom85258ee2014-10-07 00:10:02 -0700185 intents.remove(intent.id());
Brian O'Connorf3d06162014-10-02 15:54:12 -0700186 executeWithdraw(intent);
187 }
188
189 @Override
Thomas Vachuska83e090e2014-10-22 14:25:35 -0700190 public void replace(IntentId oldIntentId, Intent newIntent) {
191 // TODO: implement later
192 }
193
194 @Override
Thomas Vachuska1fb982f2014-10-22 14:09:17 -0700195 public Future<IntentOperations> execute(IntentOperations operations) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700196 // TODO: implement later
Thomas Vachuska1fb982f2014-10-22 14:09:17 -0700197 return null;
Brian O'Connorf3d06162014-10-02 15:54:12 -0700198 }
199
200 @Override
201 public Set<Intent> getIntents() {
202 return Collections.unmodifiableSet(new HashSet<>(intents.values()));
203 }
204
205 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700206 public long getIntentCount() {
207 return intents.size();
208 }
209
210 @Override
Brian O'Connorf3d06162014-10-02 15:54:12 -0700211 public Intent getIntent(IntentId id) {
212 return intents.get(id);
213 }
214
215 @Override
216 public IntentState getIntentState(IntentId id) {
217 return intentStates.get(id);
218 }
219
220 @Override
Thomas Vachuska10d4abc2014-10-21 12:47:26 -0700221 public List<Intent> getInstallableIntents(IntentId intentId) {
222 return installables.get(intentId);
223 }
224
225 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700226 public void addListener(IntentListener listener) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700227 listeners.add(listener);
228 }
229
230 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700231 public void removeListener(IntentListener listener) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700232 listeners.remove(listener);
233 }
234
235 private void dispatch(IntentEvent event) {
Brian O'Connor66630c82014-10-02 21:08:19 -0700236 for (IntentListener listener : listeners) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700237 listener.event(event);
238 }
239 }
240
241 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700242 public <T extends Intent> void registerCompiler(Class<T> cls,
243 IntentCompiler<T> compiler) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700244 compilers.put(cls, compiler);
245 }
246
247 @Override
248 public <T extends Intent> void unregisterCompiler(Class<T> cls) {
249 compilers.remove(cls);
250 }
251
252 @Override
253 public Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> getCompilers() {
254 return Collections.unmodifiableMap(compilers);
255 }
256
257 @Override
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700258 public <T extends Intent> void registerInstaller(Class<T> cls,
Brian O'Connor66630c82014-10-02 21:08:19 -0700259 IntentInstaller<T> installer) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700260 installers.put(cls, installer);
261 }
262
263 @Override
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700264 public <T extends Intent> void unregisterInstaller(Class<T> cls) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700265 installers.remove(cls);
266 }
267
268 @Override
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700269 public Map<Class<? extends Intent>,
270 IntentInstaller<? extends Intent>> getInstallers() {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700271 return Collections.unmodifiableMap(installers);
272 }
273
274 private void registerSubclassCompilerIfNeeded(Intent intent) {
275 if (!compilers.containsKey(intent.getClass())) {
276 Class<?> cls = intent.getClass();
277 while (cls != Object.class) {
278 // As long as we're within the Intent class descendants
279 if (Intent.class.isAssignableFrom(cls)) {
280 IntentCompiler<?> compiler = compilers.get(cls);
281 if (compiler != null) {
282 compilers.put(intent.getClass(), compiler);
283 return;
284 }
285 }
286 cls = cls.getSuperclass();
287 }
288 }
289 }
290
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700291 private void registerSubclassInstallerIfNeeded(Intent intent) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700292 if (!installers.containsKey(intent.getClass())) {
293 Class<?> cls = intent.getClass();
294 while (cls != Object.class) {
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700295 // As long as we're within the Intent class
Brian O'Connor66630c82014-10-02 21:08:19 -0700296 // descendants
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700297 if (Intent.class.isAssignableFrom(cls)) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700298 IntentInstaller<?> installer = installers.get(cls);
299 if (installer != null) {
300 installers.put(intent.getClass(), installer);
301 return;
302 }
303 }
304 cls = cls.getSuperclass();
305 }
306 }
307 }
308
309}