blob: 9b787abba86695618727ad1095b74b7d329dadf6 [file] [log] [blame]
/*
* Copyright 2015 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.onosproject.cord.gui;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.ImmutableList;
import org.onosproject.cord.gui.model.Bundle;
import org.onosproject.cord.gui.model.BundleDescriptor;
import org.onosproject.cord.gui.model.BundleFactory;
import org.onosproject.cord.gui.model.JsonFactory;
import org.onosproject.cord.gui.model.SubscriberUser;
import org.onosproject.cord.gui.model.UserFactory;
import org.onosproject.cord.gui.model.XosFunction;
import org.onosproject.cord.gui.model.XosFunctionDescriptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.onosproject.cord.gui.model.XosFunctionDescriptor.URL_FILTER;
/**
* In memory cache of the model of the subscriber's account.
*/
public class CordModelCache extends JsonFactory {
private static final String KEY_SSID_MAP = "ssidmap";
// FIXME: should not be a colon in the key..... Scott to fix on XOS
private static final String KEY_SSID = "service_specific_id:";
private static final String KEY_SUB_ID = "subscriber_id";
private static final int DEMO_SSID = 1234;
private static final String EMAIL_0 = "john@smith.org";
private static final String EMAIL_1 = "john@doe.org";
private static final String EMAIL = "email";
private static final String SSID = "ssid";
private static final String SUB_ID = "subId";
private static final String BUNDLE = "bundle";
private static final String USERS = "users";
private static final String LEVEL = "level";
private static final Map<Integer, Integer> LOOKUP = new HashMap<>();
private int subscriberId;
private int ssid;
private Bundle currentBundle;
private final Logger log = LoggerFactory.getLogger(getClass());
// NOTE: use a tree map to maintain sorted order by user ID
private final Map<Integer, SubscriberUser> userMap =
new TreeMap<Integer, SubscriberUser>();
/**
* Constructs a model cache, retrieving a mapping of SSID to XOS Subscriber
* IDs from the XOS server.
*/
CordModelCache() {
log.info("Initialize model cache");
ObjectNode map = XosManager.INSTANCE.initXosSubscriberLookups();
initLookupMap(map);
log.info("{} entries in SSID->SubID lookup map", LOOKUP.size());
}
private void initLookupMap(ObjectNode map) {
ArrayNode array = (ArrayNode) map.get(KEY_SSID_MAP);
Iterator<JsonNode> iter = array.elements();
while (iter.hasNext()) {
ObjectNode node = (ObjectNode) iter.next();
String ssidStr = node.get(KEY_SSID).asText();
int ssid = Integer.valueOf(ssidStr);
int subId = node.get(KEY_SUB_ID).asInt();
LOOKUP.put(ssid, subId);
log.info("... binding SSID {} to sub-id {}", ssid, subId);
}
}
private int lookupSubId(int ssid) {
Integer subId = LOOKUP.get(ssid);
if (subId == null) {
log.error("Unmapped SSID: {}", ssid);
return 0;
}
return subId;
}
/**
* Initializes the model for the subscriber account associated with
* the given email address.
*
* @param email the email address
*/
void init(String email) {
// defaults to the demo account
int ssid = DEMO_SSID;
// obviously not scalable, but good enough for demo code...
if (EMAIL_0.equals(email)) {
ssid = 0;
} else if (EMAIL_1.equals(email)) {
ssid = 1;
}
this.ssid = ssid;
subscriberId = lookupSubId(ssid);
XosManager.INSTANCE.setXosUtilsForSubscriber(subscriberId);
// if we are using the demo account, tell XOS to reset it...
if (ssid == DEMO_SSID) {
XosManager.INSTANCE.initDemoSubscriber();
}
// NOTE: I think the following should work for non-DEMO account...
currentBundle = new Bundle(BundleFactory.BASIC_BUNDLE);
initUsers();
}
private void initUsers() {
ArrayNode users = XosManager.INSTANCE.getUserList();
if (users == null) {
log.warn("no user list for SSID {} (subid {})", ssid, subscriberId);
return;
}
for (JsonNode u: users) {
ObjectNode user = (ObjectNode) u;
int id = user.get("id").asInt();
String name = user.get("name").asText();
String mac = user.get("mac").asText();
String level = user.get("level").asText();
// NOTE: We are just storing the current "url-filter" level.
// Since we are starting with the BASIC bundle, (that does
// not include URL_FILTER), we don't yet have the URL_FILTER
// memento in which to store the level.
SubscriberUser su = createUser(id, name, mac, level);
userMap.put(id, su);
log.info("..caching user {} (id:{})", name, id);
}
}
private SubscriberUser createUser(int uid, String name, String mac,
String level) {
SubscriberUser user = new SubscriberUser(uid, name, mac, level);
for (XosFunction f: currentBundle.functions()) {
user.setMemento(f.descriptor(), f.createMemento());
}
return user;
}
/**
* Returns the currently selected bundle.
*
* @return current bundle
*/
public Bundle getCurrentBundle() {
return currentBundle;
}
/**
* Sets a new bundle.
*
* @param bundleId bundle identifier
* @throws IllegalArgumentException if bundle ID is unknown
*/
public void setCurrentBundle(String bundleId) {
log.info("set new bundle : {}", bundleId);
BundleDescriptor bd = BundleFactory.bundleFromId(bundleId);
currentBundle = new Bundle(bd);
// update the user mementos
for (SubscriberUser user: userMap.values()) {
user.clearMementos();
for (XosFunction f: currentBundle.functions()) {
user.setMemento(f.descriptor(), f.createMemento());
if (f.descriptor().equals(URL_FILTER)) {
applyUrlFilterLevel(user, user.urlFilterLevel());
}
}
}
XosManager.INSTANCE.setNewBundle(currentBundle);
}
/**
* Returns the list of current users for this subscriber account.
*
* @return the list of users
*/
public List<SubscriberUser> getUsers() {
return ImmutableList.copyOf(userMap.values());
}
/**
* Applies a function parameter change for a user, pushing that
* change through to XOS.
*
* @param userId user identifier
* @param funcId function identifier
* @param param function parameter to change
* @param value new value for function parameter
*/
public void applyPerUserParam(String userId, String funcId,
String param, String value) {
int uid = Integer.parseInt(userId);
SubscriberUser user = userMap.get(uid);
checkNotNull(user, "unknown user id: " + uid);
XosFunctionDescriptor xfd =
XosFunctionDescriptor.valueOf(funcId.toUpperCase());
XosFunction func = currentBundle.findFunction(xfd);
checkNotNull(func, "function not part of bundle: " + funcId);
applyParam(func, user, param, value, true);
}
// =============
private void applyUrlFilterLevel(SubscriberUser user, String level) {
XosFunction urlFilter = currentBundle.findFunction(URL_FILTER);
if (urlFilter != null) {
applyParam(urlFilter, user, LEVEL, level, false);
}
}
private void applyParam(XosFunction func, SubscriberUser user,
String param, String value, boolean punchThrough) {
func.applyParam(user, param, value);
if (punchThrough) {
XosManager.INSTANCE.apply(func, user);
}
}
private ArrayNode userJsonArray() {
ArrayNode userList = arrayNode();
for (SubscriberUser user: userMap.values()) {
userList.add(UserFactory.toObjectNode(user));
}
return userList;
}
// ============= generate JSON for GUI rest calls..
private void addSubId(ObjectNode root) {
root.put(SUB_ID, subscriberId);
root.put(SSID, ssid);
}
/**
* Returns response JSON for login request.
* <p>
* Depending on which email is used, will bind the GUI to the
* appropriate XOS Subscriber ID.
*
* @param email the supplied email
* @return JSON acknowledgement
*/
public String jsonLogin(String email) {
init(email);
ObjectNode root = objectNode();
root.put(EMAIL, email);
addSubId(root);
return root.toString();
}
/**
* Returns the dashboard page data as JSON.
*
* @return dashboard page JSON data
*/
public String jsonDashboard() {
ObjectNode root = objectNode();
root.put(BUNDLE, currentBundle.descriptor().displayName());
root.set(USERS, userJsonArray());
addSubId(root);
return root.toString();
}
/**
* Returns the bundle page data as JSON.
*
* @return bundle page JSON data
*/
public String jsonBundle() {
ObjectNode root = BundleFactory.toObjectNode(currentBundle);
addSubId(root);
return root.toString();
}
/**
* Returns the users page data as JSON.
*
* @return users page JSON data
*/
public String jsonUsers() {
ObjectNode root = objectNode();
root.set(USERS, userJsonArray());
addSubId(root);
return root.toString();
}
/**
* Singleton instance.
*/
public static final CordModelCache INSTANCE = new CordModelCache();
}