blob: 02e8975e28ec4ba806bf58dbb7c62c06d4c0d73c [file] [log] [blame]
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2014-present Open Networking Laboratory
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07003 *
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<>();
Brian O'Connorf3d06162014-10-02 15:54:12 -070040
41 private final ExecutorService executor = Executors.newSingleThreadExecutor();
42 private final List<IntentException> exceptions = new ArrayList<>();
43
44 @Override
45 public List<IntentException> getExceptions() {
46 return exceptions;
47 }
48
49 // Provides an out-of-thread simulation of intent submit life-cycle
50 private void executeSubmit(final Intent intent) {
51 registerSubclassCompilerIfNeeded(intent);
Sho SHIMIZU74626412015-09-11 11:46:27 -070052 executor.execute(() -> {
53 try {
54 executeCompilingPhase(intent);
55 } catch (IntentException e) {
56 exceptions.add(e);
Brian O'Connorf3d06162014-10-02 15:54:12 -070057 }
58 });
59 }
60
61 // Provides an out-of-thread simulation of intent withdraw life-cycle
62 private void executeWithdraw(final Intent intent) {
Sho SHIMIZU74626412015-09-11 11:46:27 -070063 executor.execute(() -> {
64 try {
65 List<Intent> installable = getInstallable(intent.key());
66 executeWithdrawingPhase(intent, installable);
67 } catch (IntentException e) {
68 exceptions.add(e);
Brian O'Connorf3d06162014-10-02 15:54:12 -070069 }
70 });
71 }
72
73 private <T extends Intent> IntentCompiler<T> getCompiler(T intent) {
74 @SuppressWarnings("unchecked")
75 IntentCompiler<T> compiler = (IntentCompiler<T>) compilers.get(intent.getClass());
76 if (compiler == null) {
77 throw new IntentException("no compiler for class " + intent.getClass());
78 }
79 return compiler;
80 }
81
tom85258ee2014-10-07 00:10:02 -070082 private <T extends Intent> void executeCompilingPhase(T intent) {
83 setState(intent, IntentState.COMPILING);
Brian O'Connorf3d06162014-10-02 15:54:12 -070084 try {
85 // For the fake, we compile using a single level pass
Thomas Vachuskac96058a2014-10-20 23:00:16 -070086 List<Intent> installable = new ArrayList<>();
Sho SHIMIZUec07ffd2016-02-22 20:45:21 -080087 for (Intent compiled : getCompiler(intent).compile(intent, null)) {
Sho SHIMIZUd82a4e62015-09-09 14:53:46 -070088 installable.add(compiled);
Brian O'Connorf3d06162014-10-02 15:54:12 -070089 }
tom85258ee2014-10-07 00:10:02 -070090 executeInstallingPhase(intent, installable);
91
Brian O'Connorf3d06162014-10-02 15:54:12 -070092 } catch (IntentException e) {
93 setState(intent, IntentState.FAILED);
tom85258ee2014-10-07 00:10:02 -070094 dispatch(new IntentEvent(IntentEvent.Type.FAILED, intent));
Brian O'Connorf3d06162014-10-02 15:54:12 -070095 }
96 }
97
tom85258ee2014-10-07 00:10:02 -070098 private void executeInstallingPhase(Intent intent,
Thomas Vachuskac96058a2014-10-20 23:00:16 -070099 List<Intent> installable) {
tom85258ee2014-10-07 00:10:02 -0700100 setState(intent, IntentState.INSTALLING);
Brian O'Connorf3d06162014-10-02 15:54:12 -0700101 try {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700102 setState(intent, IntentState.INSTALLED);
Ray Milkey4f5d93e2015-02-10 17:04:10 -0800103 putInstallable(intent.key(), installable);
tom85258ee2014-10-07 00:10:02 -0700104 dispatch(new IntentEvent(IntentEvent.Type.INSTALLED, intent));
105
Brian O'Connorf3d06162014-10-02 15:54:12 -0700106 } catch (IntentException e) {
107 setState(intent, IntentState.FAILED);
tom85258ee2014-10-07 00:10:02 -0700108 dispatch(new IntentEvent(IntentEvent.Type.FAILED, intent));
Brian O'Connorf3d06162014-10-02 15:54:12 -0700109 }
110 }
111
tom85258ee2014-10-07 00:10:02 -0700112 private void executeWithdrawingPhase(Intent intent,
Thomas Vachuskac96058a2014-10-20 23:00:16 -0700113 List<Intent> installable) {
tom85258ee2014-10-07 00:10:02 -0700114 setState(intent, IntentState.WITHDRAWING);
Brian O'Connorf3d06162014-10-02 15:54:12 -0700115 try {
Ray Milkey4f5d93e2015-02-10 17:04:10 -0800116 removeInstallable(intent.key());
Brian O'Connorf3d06162014-10-02 15:54:12 -0700117 setState(intent, IntentState.WITHDRAWN);
tom85258ee2014-10-07 00:10:02 -0700118 dispatch(new IntentEvent(IntentEvent.Type.WITHDRAWN, intent));
Brian O'Connorf3d06162014-10-02 15:54:12 -0700119 } catch (IntentException e) {
tom53945d52014-10-07 11:01:36 -0700120 // FIXME: Rework this to always go from WITHDRAWING to WITHDRAWN!
Brian O'Connorf3d06162014-10-02 15:54:12 -0700121 setState(intent, IntentState.FAILED);
tom85258ee2014-10-07 00:10:02 -0700122 dispatch(new IntentEvent(IntentEvent.Type.FAILED, intent));
Brian O'Connorf3d06162014-10-02 15:54:12 -0700123 }
124 }
125
Brian O'Connorf3d06162014-10-02 15:54:12 -0700126 // Sets the internal state for the given intent and dispatches an event
127 private void setState(Intent intent, IntentState state) {
Ray Milkey4f5d93e2015-02-10 17:04:10 -0800128 intentStates.put(intent.key(), state);
Brian O'Connorf3d06162014-10-02 15:54:12 -0700129 }
130
Ray Milkey4f5d93e2015-02-10 17:04:10 -0800131 private void putInstallable(Key key, List<Intent> installable) {
132 installables.put(key, installable);
Brian O'Connorf3d06162014-10-02 15:54:12 -0700133 }
134
Ray Milkey4f5d93e2015-02-10 17:04:10 -0800135 private void removeInstallable(Key key) {
136 installables.remove(key);
Brian O'Connorf3d06162014-10-02 15:54:12 -0700137 }
138
Ray Milkey4f5d93e2015-02-10 17:04:10 -0800139 private List<Intent> getInstallable(Key key) {
140 List<Intent> installable = installables.get(key);
Brian O'Connorf3d06162014-10-02 15:54:12 -0700141 if (installable != null) {
142 return installable;
143 } else {
144 return Collections.emptyList();
145 }
146 }
147
148 @Override
149 public void submit(Intent intent) {
Ray Milkey4f5d93e2015-02-10 17:04:10 -0800150 intents.put(intent.key(), intent);
Brian O'Connor7a71d5d2014-12-02 00:12:27 -0800151 setState(intent, IntentState.INSTALL_REQ);
152 dispatch(new IntentEvent(IntentEvent.Type.INSTALL_REQ, intent));
Brian O'Connorf3d06162014-10-02 15:54:12 -0700153 executeSubmit(intent);
154 }
155
156 @Override
157 public void withdraw(Intent intent) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700158 executeWithdraw(intent);
159 }
160
161 @Override
Ray Milkey8c6d00e2015-03-13 14:14:34 -0700162 public void purge(Intent intent) {
163 IntentState currentState = intentStates.get(intent.key());
164 if (currentState == IntentState.WITHDRAWN
165 || currentState == IntentState.FAILED) {
166 intents.remove(intent.key());
167 installables.remove(intent.key());
168 intentStates.remove(intent.key());
Brian Stanke11f6d532016-07-05 16:17:59 -0400169 dispatch(new IntentEvent(IntentEvent.Type.PURGED, intent));
Ray Milkey8c6d00e2015-03-13 14:14:34 -0700170 }
171 }
172
173 @Override
Brian O'Connorf3d06162014-10-02 15:54:12 -0700174 public Set<Intent> getIntents() {
175 return Collections.unmodifiableSet(new HashSet<>(intents.values()));
176 }
177
178 @Override
Brian O'Connor38224302016-08-02 22:03:01 -0700179 public void addPending(IntentData intentData) {
180 throw new UnsupportedOperationException();
181 }
182
183 @Override
Thomas Vachuskac46af202015-06-03 16:43:27 -0700184 public Iterable<IntentData> getIntentData() {
185 throw new UnsupportedOperationException();
186 }
187
188 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700189 public long getIntentCount() {
190 return intents.size();
191 }
192
193 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800194 public Intent getIntent(Key intentKey) {
195 return intents.get(intentKey);
Brian O'Connorf3d06162014-10-02 15:54:12 -0700196 }
197
198 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800199 public IntentState getIntentState(Key intentKey) {
200 return intentStates.get(intentKey);
Brian O'Connorf3d06162014-10-02 15:54:12 -0700201 }
202
203 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800204 public List<Intent> getInstallableIntents(Key intentKey) {
205 return installables.get(intentKey);
Thomas Vachuska10d4abc2014-10-21 12:47:26 -0700206 }
207
208 @Override
Jonathan Hart13d3dd92015-02-25 16:09:42 -0800209 public boolean isLocal(Key intentKey) {
210 return true;
211 }
212
213 @Override
214 public Iterable<Intent> getPending() {
215 return Collections.emptyList();
216 }
217
218 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700219 public void addListener(IntentListener listener) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700220 listeners.add(listener);
221 }
222
223 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700224 public void removeListener(IntentListener listener) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700225 listeners.remove(listener);
226 }
227
228 private void dispatch(IntentEvent event) {
Brian O'Connor66630c82014-10-02 21:08:19 -0700229 for (IntentListener listener : listeners) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700230 listener.event(event);
231 }
232 }
233
234 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700235 public <T extends Intent> void registerCompiler(Class<T> cls,
236 IntentCompiler<T> compiler) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700237 compilers.put(cls, compiler);
238 }
239
240 @Override
241 public <T extends Intent> void unregisterCompiler(Class<T> cls) {
242 compilers.remove(cls);
243 }
244
245 @Override
246 public Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> getCompilers() {
247 return Collections.unmodifiableMap(compilers);
248 }
249
Brian O'Connorf3d06162014-10-02 15:54:12 -0700250 private void registerSubclassCompilerIfNeeded(Intent intent) {
251 if (!compilers.containsKey(intent.getClass())) {
252 Class<?> cls = intent.getClass();
253 while (cls != Object.class) {
254 // As long as we're within the Intent class descendants
255 if (Intent.class.isAssignableFrom(cls)) {
256 IntentCompiler<?> compiler = compilers.get(cls);
257 if (compiler != null) {
258 compilers.put(intent.getClass(), compiler);
259 return;
260 }
261 }
262 cls = cls.getSuperclass();
263 }
264 }
265 }
Brian O'Connorf3d06162014-10-02 15:54:12 -0700266}