blob: 349749e4419b1b8d6883677142e9bca105cb94cb [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<>();
21 private final Map<IntentId, List<InstallableIntent>> 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<>();
Brian O'Connor66630c82014-10-02 21:08:19 -070025 private final Map<Class<? extends InstallableIntent>, IntentInstaller<? extends InstallableIntent>> installers
26 = 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 {
43 List<InstallableIntent> installable = compileIntent(intent);
44 installIntents(intent, installable);
45 } 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 {
58 List<InstallableIntent> installable = getInstallable(intent.getId());
59 uninstallIntents(intent, installable);
60 } 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
77 private <T extends InstallableIntent> IntentInstaller<T> getInstaller(T intent) {
78 @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
87 private <T extends Intent> List<InstallableIntent> compileIntent(T intent) {
88 try {
89 // For the fake, we compile using a single level pass
90 List<InstallableIntent> installable = new ArrayList<>();
91 for (Intent compiled : getCompiler(intent).compile(intent)) {
92 installable.add((InstallableIntent) compiled);
93 }
94 setState(intent, IntentState.COMPILED);
95 return installable;
96 } catch (IntentException e) {
97 setState(intent, IntentState.FAILED);
98 throw e;
99 }
100 }
101
102 private void installIntents(Intent intent, List<InstallableIntent> installable) {
103 try {
104 for (InstallableIntent ii : installable) {
105 registerSubclassInstallerIfNeeded(ii);
106 getInstaller(ii).install(ii);
107 }
108 setState(intent, IntentState.INSTALLED);
109 putInstallable(intent.getId(), installable);
110 } catch (IntentException e) {
111 setState(intent, IntentState.FAILED);
112 throw e;
113 }
114 }
115
116 private void uninstallIntents(Intent intent, List<InstallableIntent> installable) {
117 try {
118 for (InstallableIntent ii : installable) {
119 getInstaller(ii).uninstall(ii);
120 }
121 setState(intent, IntentState.WITHDRAWN);
122 removeInstallable(intent.getId());
123 } catch (IntentException e) {
124 setState(intent, IntentState.FAILED);
125 throw e;
126 }
127 }
128
Brian O'Connorf3d06162014-10-02 15:54:12 -0700129 // Sets the internal state for the given intent and dispatches an event
130 private void setState(Intent intent, IntentState state) {
131 IntentState previous = intentStates.get(intent.getId());
132 intentStates.put(intent.getId(), state);
133 dispatch(new IntentEvent(intent, state, previous, System.currentTimeMillis()));
134 }
135
136 private void putInstallable(IntentId id, List<InstallableIntent> installable) {
137 installables.put(id, installable);
138 }
139
140 private void removeInstallable(IntentId id) {
141 installables.remove(id);
142 }
143
144 private List<InstallableIntent> getInstallable(IntentId id) {
145 List<InstallableIntent> installable = installables.get(id);
146 if (installable != null) {
147 return installable;
148 } else {
149 return Collections.emptyList();
150 }
151 }
152
153 @Override
154 public void submit(Intent intent) {
155 intents.put(intent.getId(), intent);
156 setState(intent, IntentState.SUBMITTED);
157 executeSubmit(intent);
158 }
159
160 @Override
161 public void withdraw(Intent intent) {
162 intents.remove(intent.getId());
163 setState(intent, IntentState.WITHDRAWING);
164 executeWithdraw(intent);
165 }
166
167 @Override
168 public void execute(IntentOperations operations) {
169 // TODO: implement later
170 }
171
172 @Override
173 public Set<Intent> getIntents() {
174 return Collections.unmodifiableSet(new HashSet<>(intents.values()));
175 }
176
177 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700178 public long getIntentCount() {
179 return intents.size();
180 }
181
182 @Override
Brian O'Connorf3d06162014-10-02 15:54:12 -0700183 public Intent getIntent(IntentId id) {
184 return intents.get(id);
185 }
186
187 @Override
188 public IntentState getIntentState(IntentId id) {
189 return intentStates.get(id);
190 }
191
192 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700193 public void addListener(IntentListener listener) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700194 listeners.add(listener);
195 }
196
197 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700198 public void removeListener(IntentListener listener) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700199 listeners.remove(listener);
200 }
201
202 private void dispatch(IntentEvent event) {
Brian O'Connor66630c82014-10-02 21:08:19 -0700203 for (IntentListener listener : listeners) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700204 listener.event(event);
205 }
206 }
207
208 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700209 public <T extends Intent> void registerCompiler(Class<T> cls,
210 IntentCompiler<T> compiler) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700211 compilers.put(cls, compiler);
212 }
213
214 @Override
215 public <T extends Intent> void unregisterCompiler(Class<T> cls) {
216 compilers.remove(cls);
217 }
218
219 @Override
220 public Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> getCompilers() {
221 return Collections.unmodifiableMap(compilers);
222 }
223
224 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700225 public <T extends InstallableIntent> void registerInstaller(Class<T> cls,
226 IntentInstaller<T> installer) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700227 installers.put(cls, installer);
228 }
229
230 @Override
231 public <T extends InstallableIntent> void unregisterInstaller(Class<T> cls) {
232 installers.remove(cls);
233 }
234
235 @Override
236 public Map<Class<? extends InstallableIntent>,
Brian O'Connor66630c82014-10-02 21:08:19 -0700237 IntentInstaller<? extends InstallableIntent>> getInstallers() {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700238 return Collections.unmodifiableMap(installers);
239 }
240
241 private void registerSubclassCompilerIfNeeded(Intent intent) {
242 if (!compilers.containsKey(intent.getClass())) {
243 Class<?> cls = intent.getClass();
244 while (cls != Object.class) {
245 // As long as we're within the Intent class descendants
246 if (Intent.class.isAssignableFrom(cls)) {
247 IntentCompiler<?> compiler = compilers.get(cls);
248 if (compiler != null) {
249 compilers.put(intent.getClass(), compiler);
250 return;
251 }
252 }
253 cls = cls.getSuperclass();
254 }
255 }
256 }
257
258 private void registerSubclassInstallerIfNeeded(InstallableIntent intent) {
259 if (!installers.containsKey(intent.getClass())) {
260 Class<?> cls = intent.getClass();
261 while (cls != Object.class) {
Brian O'Connor66630c82014-10-02 21:08:19 -0700262 // As long as we're within the InstallableIntent class
263 // descendants
Brian O'Connorf3d06162014-10-02 15:54:12 -0700264 if (InstallableIntent.class.isAssignableFrom(cls)) {
265 IntentInstaller<?> installer = installers.get(cls);
266 if (installer != null) {
267 installers.put(intent.getClass(), installer);
268 return;
269 }
270 }
271 cls = cls.getSuperclass();
272 }
273 }
274 }
275
276}