blob: 9b787abba86695618727ad1095b74b7d329dadf6 [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";
50 // FIXME: should not be a colon in the key..... Scott to fix on XOS
51 private static final String KEY_SSID = "service_specific_id:";
52 private static final String KEY_SUB_ID = "subscriber_id";
53
54 private static final int DEMO_SSID = 1234;
55
56 private static final String EMAIL_0 = "john@smith.org";
57 private static final String EMAIL_1 = "john@doe.org";
58
59 private static final String EMAIL = "email";
60 private static final String SSID = "ssid";
61 private static final String SUB_ID = "subId";
62
Simon Hunt09a32db2015-05-21 15:00:42 -070063 private static final String BUNDLE = "bundle";
64 private static final String USERS = "users";
Simon Hunt7d02c082015-05-29 12:17:09 -070065 private static final String LEVEL = "level";
Simon Hunt41b943e2015-05-21 13:52:01 -070066
Simon Huntc686c6a2015-06-05 14:33:30 -070067 private static final Map<Integer, Integer> LOOKUP = new HashMap<>();
68
Simon Huntee6a7372015-05-28 14:04:24 -070069 private int subscriberId;
Simon Huntc686c6a2015-06-05 14:33:30 -070070 private int ssid;
Simon Hunt41b943e2015-05-21 13:52:01 -070071 private Bundle currentBundle;
Simon Hunt87b157c2015-05-22 12:09:59 -070072
Simon Huntb1246412015-06-01 13:37:26 -070073 private final Logger log = LoggerFactory.getLogger(getClass());
74
Simon Hunt87b157c2015-05-22 12:09:59 -070075 // NOTE: use a tree map to maintain sorted order by user ID
76 private final Map<Integer, SubscriberUser> userMap =
77 new TreeMap<Integer, SubscriberUser>();
Simon Hunt41b943e2015-05-21 13:52:01 -070078
79 /**
Simon Huntc686c6a2015-06-05 14:33:30 -070080 * Constructs a model cache, retrieving a mapping of SSID to XOS Subscriber
81 * IDs from the XOS server.
Simon Hunt41b943e2015-05-21 13:52:01 -070082 */
Simon Hunt09a32db2015-05-21 15:00:42 -070083 CordModelCache() {
Simon Huntb1246412015-06-01 13:37:26 -070084 log.info("Initialize model cache");
Simon Huntc686c6a2015-06-05 14:33:30 -070085 ObjectNode map = XosManager.INSTANCE.initXosSubscriberLookups();
86 initLookupMap(map);
87 log.info("{} entries in SSID->SubID lookup map", LOOKUP.size());
88 }
89
90 private void initLookupMap(ObjectNode map) {
91 ArrayNode array = (ArrayNode) map.get(KEY_SSID_MAP);
92 Iterator<JsonNode> iter = array.elements();
93 while (iter.hasNext()) {
94 ObjectNode node = (ObjectNode) iter.next();
95 String ssidStr = node.get(KEY_SSID).asText();
96 int ssid = Integer.valueOf(ssidStr);
97 int subId = node.get(KEY_SUB_ID).asInt();
98 LOOKUP.put(ssid, subId);
99 log.info("... binding SSID {} to sub-id {}", ssid, subId);
100 }
101 }
102
103 private int lookupSubId(int ssid) {
104 Integer subId = LOOKUP.get(ssid);
105 if (subId == null) {
106 log.error("Unmapped SSID: {}", ssid);
107 return 0;
108 }
109 return subId;
110 }
111
112 /**
113 * Initializes the model for the subscriber account associated with
114 * the given email address.
115 *
116 * @param email the email address
117 */
118 void init(String email) {
119 // defaults to the demo account
120 int ssid = DEMO_SSID;
121
122 // obviously not scalable, but good enough for demo code...
123 if (EMAIL_0.equals(email)) {
124 ssid = 0;
125 } else if (EMAIL_1.equals(email)) {
126 ssid = 1;
127 }
128
129 this.ssid = ssid;
130 subscriberId = lookupSubId(ssid);
131 XosManager.INSTANCE.setXosUtilsForSubscriber(subscriberId);
132
133 // if we are using the demo account, tell XOS to reset it...
134 if (ssid == DEMO_SSID) {
135 XosManager.INSTANCE.initDemoSubscriber();
136 }
137
138 // NOTE: I think the following should work for non-DEMO account...
Simon Hunt41b943e2015-05-21 13:52:01 -0700139 currentBundle = new Bundle(BundleFactory.BASIC_BUNDLE);
Simon Hunt7d02c082015-05-29 12:17:09 -0700140 initUsers();
Simon Hunt41b943e2015-05-21 13:52:01 -0700141 }
142
Simon Huntee6a7372015-05-28 14:04:24 -0700143 private void initUsers() {
Simon Hunt7d02c082015-05-29 12:17:09 -0700144 ArrayNode users = XosManager.INSTANCE.getUserList();
Simon Huntc686c6a2015-06-05 14:33:30 -0700145 if (users == null) {
146 log.warn("no user list for SSID {} (subid {})", ssid, subscriberId);
147 return;
148 }
149
Simon Hunt7d02c082015-05-29 12:17:09 -0700150 for (JsonNode u: users) {
151 ObjectNode user = (ObjectNode) u;
152
153 int id = user.get("id").asInt();
154 String name = user.get("name").asText();
155 String mac = user.get("mac").asText();
156 String level = user.get("level").asText();
157
158 // NOTE: We are just storing the current "url-filter" level.
159 // Since we are starting with the BASIC bundle, (that does
160 // not include URL_FILTER), we don't yet have the URL_FILTER
161 // memento in which to store the level.
162 SubscriberUser su = createUser(id, name, mac, level);
163 userMap.put(id, su);
Simon Huntb1246412015-06-01 13:37:26 -0700164 log.info("..caching user {} (id:{})", name, id);
Simon Hunt7d02c082015-05-29 12:17:09 -0700165 }
Simon Hunt41b943e2015-05-21 13:52:01 -0700166 }
167
Simon Hunt7d02c082015-05-29 12:17:09 -0700168 private SubscriberUser createUser(int uid, String name, String mac,
169 String level) {
170 SubscriberUser user = new SubscriberUser(uid, name, mac, level);
Simon Hunt6c2555b2015-05-21 18:17:56 -0700171 for (XosFunction f: currentBundle.functions()) {
172 user.setMemento(f.descriptor(), f.createMemento());
173 }
174 return user;
175 }
176
Simon Hunt41b943e2015-05-21 13:52:01 -0700177 /**
178 * Returns the currently selected bundle.
179 *
180 * @return current bundle
181 */
182 public Bundle getCurrentBundle() {
183 return currentBundle;
184 }
185
186 /**
187 * Sets a new bundle.
188 *
189 * @param bundleId bundle identifier
190 * @throws IllegalArgumentException if bundle ID is unknown
191 */
192 public void setCurrentBundle(String bundleId) {
Simon Huntb1246412015-06-01 13:37:26 -0700193 log.info("set new bundle : {}", bundleId);
Simon Hunt6c2555b2015-05-21 18:17:56 -0700194 BundleDescriptor bd = BundleFactory.bundleFromId(bundleId);
195 currentBundle = new Bundle(bd);
196 // update the user mementos
Simon Hunt87b157c2015-05-22 12:09:59 -0700197 for (SubscriberUser user: userMap.values()) {
Simon Hunt6c2555b2015-05-21 18:17:56 -0700198 user.clearMementos();
199 for (XosFunction f: currentBundle.functions()) {
200 user.setMemento(f.descriptor(), f.createMemento());
Simon Hunt7d02c082015-05-29 12:17:09 -0700201 if (f.descriptor().equals(URL_FILTER)) {
202 applyUrlFilterLevel(user, user.urlFilterLevel());
203 }
Simon Hunt6c2555b2015-05-21 18:17:56 -0700204 }
205 }
206
Simon Hunt7d02c082015-05-29 12:17:09 -0700207 XosManager.INSTANCE.setNewBundle(currentBundle);
Simon Hunt41b943e2015-05-21 13:52:01 -0700208 }
209
Simon Hunt6c2555b2015-05-21 18:17:56 -0700210
Simon Hunt41b943e2015-05-21 13:52:01 -0700211 /**
212 * Returns the list of current users for this subscriber account.
213 *
214 * @return the list of users
215 */
216 public List<SubscriberUser> getUsers() {
Simon Hunt87b157c2015-05-22 12:09:59 -0700217 return ImmutableList.copyOf(userMap.values());
Simon Hunt41b943e2015-05-21 13:52:01 -0700218 }
Simon Hunt09a32db2015-05-21 15:00:42 -0700219
Simon Hunt6c2555b2015-05-21 18:17:56 -0700220 /**
Simon Hunt7d02c082015-05-29 12:17:09 -0700221 * Applies a function parameter change for a user, pushing that
222 * change through to XOS.
Simon Hunt6c2555b2015-05-21 18:17:56 -0700223 *
224 * @param userId user identifier
225 * @param funcId function identifier
226 * @param param function parameter to change
227 * @param value new value for function parameter
228 */
229 public void applyPerUserParam(String userId, String funcId,
230 String param, String value) {
Simon Hunt87b157c2015-05-22 12:09:59 -0700231
Simon Hunt6c2555b2015-05-21 18:17:56 -0700232 int uid = Integer.parseInt(userId);
Simon Hunt87b157c2015-05-22 12:09:59 -0700233 SubscriberUser user = userMap.get(uid);
234 checkNotNull(user, "unknown user id: " + uid);
235
Simon Hunt6c2555b2015-05-21 18:17:56 -0700236 XosFunctionDescriptor xfd =
237 XosFunctionDescriptor.valueOf(funcId.toUpperCase());
Simon Hunt87b157c2015-05-22 12:09:59 -0700238
239 XosFunction func = currentBundle.findFunction(xfd);
240 checkNotNull(func, "function not part of bundle: " + funcId);
Simon Hunt7d02c082015-05-29 12:17:09 -0700241 applyParam(func, user, param, value, true);
Simon Hunt6c2555b2015-05-21 18:17:56 -0700242 }
243
244 // =============
245
Simon Hunt7d02c082015-05-29 12:17:09 -0700246 private void applyUrlFilterLevel(SubscriberUser user, String level) {
247 XosFunction urlFilter = currentBundle.findFunction(URL_FILTER);
248 if (urlFilter != null) {
249 applyParam(urlFilter, user, LEVEL, level, false);
250 }
251 }
252
253 private void applyParam(XosFunction func, SubscriberUser user,
254 String param, String value, boolean punchThrough) {
255 func.applyParam(user, param, value);
256 if (punchThrough) {
257 XosManager.INSTANCE.apply(func, user);
258 }
259 }
260
Simon Hunt09a32db2015-05-21 15:00:42 -0700261 private ArrayNode userJsonArray() {
262 ArrayNode userList = arrayNode();
Simon Hunt87b157c2015-05-22 12:09:59 -0700263 for (SubscriberUser user: userMap.values()) {
Simon Hunt09a32db2015-05-21 15:00:42 -0700264 userList.add(UserFactory.toObjectNode(user));
265 }
266 return userList;
267 }
268
269 // ============= generate JSON for GUI rest calls..
270
Simon Huntee6a7372015-05-28 14:04:24 -0700271 private void addSubId(ObjectNode root) {
272 root.put(SUB_ID, subscriberId);
Simon Huntc686c6a2015-06-05 14:33:30 -0700273 root.put(SSID, ssid);
274 }
275
276
277 /**
278 * Returns response JSON for login request.
279 * <p>
280 * Depending on which email is used, will bind the GUI to the
281 * appropriate XOS Subscriber ID.
282 *
283 * @param email the supplied email
284 * @return JSON acknowledgement
285 */
286 public String jsonLogin(String email) {
287 init(email);
288 ObjectNode root = objectNode();
289 root.put(EMAIL, email);
290 addSubId(root);
291 return root.toString();
Simon Huntee6a7372015-05-28 14:04:24 -0700292 }
293
Simon Hunt09a32db2015-05-21 15:00:42 -0700294 /**
295 * Returns the dashboard page data as JSON.
296 *
297 * @return dashboard page JSON data
298 */
299 public String jsonDashboard() {
300 ObjectNode root = objectNode();
301 root.put(BUNDLE, currentBundle.descriptor().displayName());
302 root.set(USERS, userJsonArray());
Simon Huntee6a7372015-05-28 14:04:24 -0700303 addSubId(root);
Simon Hunt09a32db2015-05-21 15:00:42 -0700304 return root.toString();
305 }
306
307 /**
308 * Returns the bundle page data as JSON.
309 *
310 * @return bundle page JSON data
311 */
312 public String jsonBundle() {
Simon Huntee6a7372015-05-28 14:04:24 -0700313 ObjectNode root = BundleFactory.toObjectNode(currentBundle);
314 addSubId(root);
315 return root.toString();
Simon Hunt09a32db2015-05-21 15:00:42 -0700316 }
317
318 /**
319 * Returns the users page data as JSON.
320 *
321 * @return users page JSON data
322 */
323 public String jsonUsers() {
324 ObjectNode root = objectNode();
325 root.set(USERS, userJsonArray());
Simon Huntee6a7372015-05-28 14:04:24 -0700326 addSubId(root);
Simon Hunt09a32db2015-05-21 15:00:42 -0700327 return root.toString();
328 }
329
330 /**
331 * Singleton instance.
332 */
333 public static final CordModelCache INSTANCE = new CordModelCache();
Simon Hunta29c87b2015-05-21 09:56:19 -0700334}