blob: dd1e42b72207a47cb0b5e75a21c3aac77b0443bb [file] [log] [blame]
Simon Hunta29c87b2015-05-21 09:56:19 -07001/*
2 * Copyright 2015 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 *
16 */
17
18package org.onosproject.cord.gui;
19
Simon Hunt7d02c082015-05-29 12:17:09 -070020import com.fasterxml.jackson.databind.JsonNode;
Simon Hunt09a32db2015-05-21 15:00:42 -070021import com.fasterxml.jackson.databind.node.ArrayNode;
22import com.fasterxml.jackson.databind.node.ObjectNode;
Simon Hunt41b943e2015-05-21 13:52:01 -070023import com.google.common.collect.ImmutableList;
24import org.onosproject.cord.gui.model.Bundle;
25import org.onosproject.cord.gui.model.BundleDescriptor;
26import org.onosproject.cord.gui.model.BundleFactory;
Simon Hunt09a32db2015-05-21 15:00:42 -070027import org.onosproject.cord.gui.model.JsonFactory;
Simon Hunt41b943e2015-05-21 13:52:01 -070028import org.onosproject.cord.gui.model.SubscriberUser;
Simon Hunt09a32db2015-05-21 15:00:42 -070029import org.onosproject.cord.gui.model.UserFactory;
Simon Hunt6c2555b2015-05-21 18:17:56 -070030import org.onosproject.cord.gui.model.XosFunction;
31import org.onosproject.cord.gui.model.XosFunctionDescriptor;
Simon Huntb1246412015-06-01 13:37:26 -070032import org.slf4j.Logger;
33import org.slf4j.LoggerFactory;
Simon Hunt41b943e2015-05-21 13:52:01 -070034
Simon Huntc686c6a2015-06-05 14:33:30 -070035import java.util.HashMap;
36import java.util.Iterator;
Simon Hunt41b943e2015-05-21 13:52:01 -070037import java.util.List;
Simon Hunt87b157c2015-05-22 12:09:59 -070038import java.util.Map;
39import java.util.TreeMap;
40
41import static com.google.common.base.Preconditions.checkNotNull;
Simon Hunt7d02c082015-05-29 12:17:09 -070042import static org.onosproject.cord.gui.model.XosFunctionDescriptor.URL_FILTER;
Simon Hunt41b943e2015-05-21 13:52:01 -070043
Simon Hunta29c87b2015-05-21 09:56:19 -070044/**
45 * In memory cache of the model of the subscriber's account.
46 */
Simon Hunt09a32db2015-05-21 15:00:42 -070047public class CordModelCache extends JsonFactory {
48
Simon Huntc686c6a2015-06-05 14:33:30 -070049 private static final String KEY_SSID_MAP = "ssidmap";
Simon Hunt2739e6f82015-06-05 16:27:45 -070050 private static final String KEY_SSID = "service_specific_id";
Simon Huntc686c6a2015-06-05 14:33:30 -070051 private static final String KEY_SUB_ID = "subscriber_id";
52
53 private static final int DEMO_SSID = 1234;
54
55 private static final String EMAIL_0 = "john@smith.org";
56 private static final String EMAIL_1 = "john@doe.org";
57
58 private static final String EMAIL = "email";
59 private static final String SSID = "ssid";
60 private static final String SUB_ID = "subId";
61
Simon Hunt09a32db2015-05-21 15:00:42 -070062 private static final String BUNDLE = "bundle";
63 private static final String USERS = "users";
Simon Hunt7d02c082015-05-29 12:17:09 -070064 private static final String LEVEL = "level";
Simon Huntc296d2c2015-06-08 12:54:57 -070065 private static final String LOGOUT = "logout";
Simon Hunt41b943e2015-05-21 13:52:01 -070066
Bri Prebilic Cole8b66a852015-06-10 17:15:10 -070067 private static final String BUNDLE_NAME = BUNDLE + "_name";
68 private static final String BUNDLE_DESC = BUNDLE + "_desc";
69
Simon Huntc686c6a2015-06-05 14:33:30 -070070 private static final Map<Integer, Integer> LOOKUP = new HashMap<>();
71
Simon Huntc296d2c2015-06-08 12:54:57 -070072 private String email = null;
Simon Huntee6a7372015-05-28 14:04:24 -070073 private int subscriberId;
Simon Huntc686c6a2015-06-05 14:33:30 -070074 private int ssid;
Simon Hunt41b943e2015-05-21 13:52:01 -070075 private Bundle currentBundle;
Simon Hunt87b157c2015-05-22 12:09:59 -070076
Simon Huntb1246412015-06-01 13:37:26 -070077 private final Logger log = LoggerFactory.getLogger(getClass());
78
Simon Hunt87b157c2015-05-22 12:09:59 -070079 // NOTE: use a tree map to maintain sorted order by user ID
80 private final Map<Integer, SubscriberUser> userMap =
81 new TreeMap<Integer, SubscriberUser>();
Simon Hunt41b943e2015-05-21 13:52:01 -070082
83 /**
Simon Huntc686c6a2015-06-05 14:33:30 -070084 * Constructs a model cache, retrieving a mapping of SSID to XOS Subscriber
85 * IDs from the XOS server.
Simon Hunt41b943e2015-05-21 13:52:01 -070086 */
Simon Hunt09a32db2015-05-21 15:00:42 -070087 CordModelCache() {
Simon Huntb1246412015-06-01 13:37:26 -070088 log.info("Initialize model cache");
Simon Huntc686c6a2015-06-05 14:33:30 -070089 ObjectNode map = XosManager.INSTANCE.initXosSubscriberLookups();
90 initLookupMap(map);
91 log.info("{} entries in SSID->SubID lookup map", LOOKUP.size());
92 }
93
94 private void initLookupMap(ObjectNode map) {
95 ArrayNode array = (ArrayNode) map.get(KEY_SSID_MAP);
96 Iterator<JsonNode> iter = array.elements();
Simon Hunt2739e6f82015-06-05 16:27:45 -070097 StringBuilder msg = new StringBuilder();
Simon Huntc686c6a2015-06-05 14:33:30 -070098 while (iter.hasNext()) {
99 ObjectNode node = (ObjectNode) iter.next();
Simon Hunt42366082015-06-08 09:57:05 -0700100 String ssidStr = node.get(KEY_SSID).asText();
Simon Huntc686c6a2015-06-05 14:33:30 -0700101 int ssid = Integer.valueOf(ssidStr);
102 int subId = node.get(KEY_SUB_ID).asInt();
103 LOOKUP.put(ssid, subId);
Simon Hunt2739e6f82015-06-05 16:27:45 -0700104 msg.append(String.format("\n..binding SSID %s to sub-id %s", ssid, subId));
Simon Huntc686c6a2015-06-05 14:33:30 -0700105 }
Simon Hunt2739e6f82015-06-05 16:27:45 -0700106 log.info(msg.toString());
Simon Huntc686c6a2015-06-05 14:33:30 -0700107 }
108
109 private int lookupSubId(int ssid) {
110 Integer subId = LOOKUP.get(ssid);
111 if (subId == null) {
112 log.error("Unmapped SSID: {}", ssid);
113 return 0;
114 }
115 return subId;
116 }
117
118 /**
119 * Initializes the model for the subscriber account associated with
120 * the given email address.
121 *
122 * @param email the email address
123 */
124 void init(String email) {
125 // defaults to the demo account
126 int ssid = DEMO_SSID;
127
Simon Huntc296d2c2015-06-08 12:54:57 -0700128 this.email = email;
129
Simon Huntc686c6a2015-06-05 14:33:30 -0700130 // obviously not scalable, but good enough for demo code...
131 if (EMAIL_0.equals(email)) {
132 ssid = 0;
133 } else if (EMAIL_1.equals(email)) {
134 ssid = 1;
135 }
136
137 this.ssid = ssid;
138 subscriberId = lookupSubId(ssid);
139 XosManager.INSTANCE.setXosUtilsForSubscriber(subscriberId);
140
Jonathan Harte099f2b2015-06-11 17:33:00 -0700141 // call the initdemo API to ensure users are populated in XOS
142 XosManager.INSTANCE.initDemoSubscriber();
Simon Huntc686c6a2015-06-05 14:33:30 -0700143
144 // NOTE: I think the following should work for non-DEMO account...
Simon Hunt41b943e2015-05-21 13:52:01 -0700145 currentBundle = new Bundle(BundleFactory.BASIC_BUNDLE);
Simon Hunt7d02c082015-05-29 12:17:09 -0700146 initUsers();
Simon Hunt41b943e2015-05-21 13:52:01 -0700147 }
148
Simon Huntee6a7372015-05-28 14:04:24 -0700149 private void initUsers() {
Simon Huntc296d2c2015-06-08 12:54:57 -0700150 // start with a clean slate
151 userMap.clear();
152
Simon Hunt7d02c082015-05-29 12:17:09 -0700153 ArrayNode users = XosManager.INSTANCE.getUserList();
Simon Huntc686c6a2015-06-05 14:33:30 -0700154 if (users == null) {
155 log.warn("no user list for SSID {} (subid {})", ssid, subscriberId);
156 return;
157 }
158
Simon Huntc296d2c2015-06-08 12:54:57 -0700159 StringBuilder sb = new StringBuilder();
Simon Hunt7d02c082015-05-29 12:17:09 -0700160 for (JsonNode u: users) {
161 ObjectNode user = (ObjectNode) u;
162
163 int id = user.get("id").asInt();
164 String name = user.get("name").asText();
165 String mac = user.get("mac").asText();
166 String level = user.get("level").asText();
167
168 // NOTE: We are just storing the current "url-filter" level.
169 // Since we are starting with the BASIC bundle, (that does
170 // not include URL_FILTER), we don't yet have the URL_FILTER
171 // memento in which to store the level.
172 SubscriberUser su = createUser(id, name, mac, level);
173 userMap.put(id, su);
Simon Huntc296d2c2015-06-08 12:54:57 -0700174 sb.append(String.format("\n..cache user %s [%d], %s, %s",
175 name, id, mac, level));
Simon Hunt7d02c082015-05-29 12:17:09 -0700176 }
Simon Huntc296d2c2015-06-08 12:54:57 -0700177 log.info(sb.toString());
Simon Hunt41b943e2015-05-21 13:52:01 -0700178 }
179
Simon Hunt7d02c082015-05-29 12:17:09 -0700180 private SubscriberUser createUser(int uid, String name, String mac,
181 String level) {
182 SubscriberUser user = new SubscriberUser(uid, name, mac, level);
Simon Hunt6c2555b2015-05-21 18:17:56 -0700183 for (XosFunction f: currentBundle.functions()) {
184 user.setMemento(f.descriptor(), f.createMemento());
185 }
186 return user;
187 }
188
Simon Hunt41b943e2015-05-21 13:52:01 -0700189 /**
190 * Returns the currently selected bundle.
191 *
192 * @return current bundle
193 */
194 public Bundle getCurrentBundle() {
195 return currentBundle;
196 }
197
198 /**
199 * Sets a new bundle.
200 *
201 * @param bundleId bundle identifier
202 * @throws IllegalArgumentException if bundle ID is unknown
203 */
204 public void setCurrentBundle(String bundleId) {
Simon Huntb1246412015-06-01 13:37:26 -0700205 log.info("set new bundle : {}", bundleId);
Simon Hunt6c2555b2015-05-21 18:17:56 -0700206 BundleDescriptor bd = BundleFactory.bundleFromId(bundleId);
207 currentBundle = new Bundle(bd);
208 // update the user mementos
Simon Hunt87b157c2015-05-22 12:09:59 -0700209 for (SubscriberUser user: userMap.values()) {
Simon Hunt6c2555b2015-05-21 18:17:56 -0700210 user.clearMementos();
211 for (XosFunction f: currentBundle.functions()) {
212 user.setMemento(f.descriptor(), f.createMemento());
Simon Hunt7d02c082015-05-29 12:17:09 -0700213 if (f.descriptor().equals(URL_FILTER)) {
214 applyUrlFilterLevel(user, user.urlFilterLevel());
215 }
Simon Hunt6c2555b2015-05-21 18:17:56 -0700216 }
217 }
218
Simon Hunt7d02c082015-05-29 12:17:09 -0700219 XosManager.INSTANCE.setNewBundle(currentBundle);
Simon Hunt41b943e2015-05-21 13:52:01 -0700220 }
221
Simon Hunt6c2555b2015-05-21 18:17:56 -0700222
Simon Hunt41b943e2015-05-21 13:52:01 -0700223 /**
224 * Returns the list of current users for this subscriber account.
225 *
226 * @return the list of users
227 */
228 public List<SubscriberUser> getUsers() {
Simon Hunt87b157c2015-05-22 12:09:59 -0700229 return ImmutableList.copyOf(userMap.values());
Simon Hunt41b943e2015-05-21 13:52:01 -0700230 }
Simon Hunt09a32db2015-05-21 15:00:42 -0700231
Simon Hunt6c2555b2015-05-21 18:17:56 -0700232 /**
Simon Hunt7d02c082015-05-29 12:17:09 -0700233 * Applies a function parameter change for a user, pushing that
234 * change through to XOS.
Simon Hunt6c2555b2015-05-21 18:17:56 -0700235 *
236 * @param userId user identifier
237 * @param funcId function identifier
238 * @param param function parameter to change
239 * @param value new value for function parameter
240 */
241 public void applyPerUserParam(String userId, String funcId,
242 String param, String value) {
Simon Hunt87b157c2015-05-22 12:09:59 -0700243
Simon Hunt6c2555b2015-05-21 18:17:56 -0700244 int uid = Integer.parseInt(userId);
Simon Hunt87b157c2015-05-22 12:09:59 -0700245 SubscriberUser user = userMap.get(uid);
246 checkNotNull(user, "unknown user id: " + uid);
247
Simon Hunt6c2555b2015-05-21 18:17:56 -0700248 XosFunctionDescriptor xfd =
249 XosFunctionDescriptor.valueOf(funcId.toUpperCase());
Simon Hunt87b157c2015-05-22 12:09:59 -0700250
251 XosFunction func = currentBundle.findFunction(xfd);
252 checkNotNull(func, "function not part of bundle: " + funcId);
Simon Hunt7d02c082015-05-29 12:17:09 -0700253 applyParam(func, user, param, value, true);
Simon Hunt6c2555b2015-05-21 18:17:56 -0700254 }
255
256 // =============
257
Simon Hunt7d02c082015-05-29 12:17:09 -0700258 private void applyUrlFilterLevel(SubscriberUser user, String level) {
259 XosFunction urlFilter = currentBundle.findFunction(URL_FILTER);
260 if (urlFilter != null) {
261 applyParam(urlFilter, user, LEVEL, level, false);
262 }
263 }
264
265 private void applyParam(XosFunction func, SubscriberUser user,
266 String param, String value, boolean punchThrough) {
267 func.applyParam(user, param, value);
268 if (punchThrough) {
269 XosManager.INSTANCE.apply(func, user);
270 }
271 }
272
Simon Hunt09a32db2015-05-21 15:00:42 -0700273 private ArrayNode userJsonArray() {
274 ArrayNode userList = arrayNode();
Simon Hunt87b157c2015-05-22 12:09:59 -0700275 for (SubscriberUser user: userMap.values()) {
Simon Hunt09a32db2015-05-21 15:00:42 -0700276 userList.add(UserFactory.toObjectNode(user));
277 }
278 return userList;
279 }
280
281 // ============= generate JSON for GUI rest calls..
282
Simon Huntee6a7372015-05-28 14:04:24 -0700283 private void addSubId(ObjectNode root) {
284 root.put(SUB_ID, subscriberId);
Simon Huntc686c6a2015-06-05 14:33:30 -0700285 root.put(SSID, ssid);
Simon Huntc296d2c2015-06-08 12:54:57 -0700286 root.put(EMAIL, email);
Simon Huntc686c6a2015-06-05 14:33:30 -0700287 }
288
289
290 /**
291 * Returns response JSON for login request.
292 * <p>
293 * Depending on which email is used, will bind the GUI to the
294 * appropriate XOS Subscriber ID.
295 *
296 * @param email the supplied email
297 * @return JSON acknowledgement
298 */
Simon Hunt6f0afae2015-06-08 21:40:41 -0700299 public synchronized String jsonLogin(String email) {
Simon Huntc296d2c2015-06-08 12:54:57 -0700300 log.info("jsonLogin(\"{}\")", email);
Simon Huntc686c6a2015-06-05 14:33:30 -0700301 init(email);
302 ObjectNode root = objectNode();
Simon Huntc686c6a2015-06-05 14:33:30 -0700303 addSubId(root);
304 return root.toString();
Simon Huntee6a7372015-05-28 14:04:24 -0700305 }
306
Simon Hunt09a32db2015-05-21 15:00:42 -0700307 /**
308 * Returns the dashboard page data as JSON.
309 *
310 * @return dashboard page JSON data
311 */
Simon Hunt6f0afae2015-06-08 21:40:41 -0700312 public synchronized String jsonDashboard() {
Simon Huntc296d2c2015-06-08 12:54:57 -0700313 log.info("jsonDashboard()");
314
315 if (email == null) {
316 return jsonLogout();
317 }
318
Bri Prebilic Cole8b66a852015-06-10 17:15:10 -0700319 BundleDescriptor bundleDescriptor = currentBundle.descriptor();
Simon Hunt09a32db2015-05-21 15:00:42 -0700320 ObjectNode root = objectNode();
Bri Prebilic Cole8b66a852015-06-10 17:15:10 -0700321 root.put(BUNDLE_NAME, bundleDescriptor.displayName());
322 root.put(BUNDLE_DESC, bundleDescriptor.description());
Simon Hunt09a32db2015-05-21 15:00:42 -0700323 root.set(USERS, userJsonArray());
Simon Huntee6a7372015-05-28 14:04:24 -0700324 addSubId(root);
Simon Hunt09a32db2015-05-21 15:00:42 -0700325 return root.toString();
326 }
327
328 /**
329 * Returns the bundle page data as JSON.
330 *
331 * @return bundle page JSON data
332 */
Simon Hunt6f0afae2015-06-08 21:40:41 -0700333 public synchronized String jsonBundle() {
Simon Huntc296d2c2015-06-08 12:54:57 -0700334 log.info("jsonBundle()");
335
336 if (email == null) {
337 return jsonLogout();
338 }
339
Simon Huntee6a7372015-05-28 14:04:24 -0700340 ObjectNode root = BundleFactory.toObjectNode(currentBundle);
341 addSubId(root);
342 return root.toString();
Simon Hunt09a32db2015-05-21 15:00:42 -0700343 }
344
345 /**
346 * Returns the users page data as JSON.
347 *
348 * @return users page JSON data
349 */
Simon Hunt6f0afae2015-06-08 21:40:41 -0700350 public synchronized String jsonUsers() {
Simon Huntc296d2c2015-06-08 12:54:57 -0700351 log.info("jsonUsers()");
352
353 if (email == null) {
354 return jsonLogout();
355 }
356
Simon Hunt09a32db2015-05-21 15:00:42 -0700357 ObjectNode root = objectNode();
358 root.set(USERS, userJsonArray());
Simon Huntee6a7372015-05-28 14:04:24 -0700359 addSubId(root);
Simon Hunt09a32db2015-05-21 15:00:42 -0700360 return root.toString();
361 }
362
363 /**
Simon Huntc296d2c2015-06-08 12:54:57 -0700364 * Returns logout acknowledgement as JSON.
365 *
366 * @return logout acknowledgement
367 */
Simon Hunt6f0afae2015-06-08 21:40:41 -0700368 public synchronized String jsonLogout() {
Simon Huntc296d2c2015-06-08 12:54:57 -0700369 log.info("jsonLogout()");
370 ObjectNode root = objectNode().put(LOGOUT, true);
371 addSubId(root);
372
373 email = null; // signifies no one logged in
374
375 return root.toString();
376 }
377
378 /**
Simon Hunt09a32db2015-05-21 15:00:42 -0700379 * Singleton instance.
380 */
381 public static final CordModelCache INSTANCE = new CordModelCache();
Simon Hunta29c87b2015-05-21 09:56:19 -0700382}