/* * #! * Ontopia Navigator * #- * Copyright (C) 2001 - 2013 The Ontopia Project * #- * 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 net.ontopia.topicmaps.nav2.impl.framework; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Map; import java.io.Serializable; import net.ontopia.topicmaps.nav.context.UserFilterContextStore; import net.ontopia.topicmaps.nav2.core.NavigatorConfigurationIF; import net.ontopia.topicmaps.nav2.core.UserIF; import net.ontopia.utils.HistoryMap; import net.ontopia.utils.OntopiaRuntimeException; import net.ontopia.utils.RingBuffer; import org.apache.commons.collections4.map.LRUMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * INTERNAL: implementation of UserIF for holding data relevant to one * user session. */ public class User implements UserIF, Serializable { private static Logger logger = LoggerFactory.getLogger(User.class.getName()); private static final int DEFAULT_MAX_BUNDLES = 5; // max working bundles per user private static final int DEFAULT_BUNDLE_EXPIRY = 1800; // user bundle expiry time protected String id; protected String model; protected String view; protected String skin; // these are marked as transient, which means that when the User // object has been stored in the server's persistent session store // and resurrected from there, they will all be null. the rest of // the class is coded to handle the case where these are initialized // as null. (the loss of the actual data is no problem.) see issue 135 // https://github.com/ontopia/ontopia/issues/135 protected transient UserFilterContextStore filterContext; protected transient HistoryMap history; protected transient RingBuffer log; protected transient Map workingBundles; // Time stamps for the workingBundles. protected transient Map timeStamps; // Number of seconds before bundles are expired. protected long bundleExpiryAge; // Initial number of seconds before bundles are expired. protected final long initialBundleExpiryAge; // How many working bundles is the max, according to config? protected final int max_bundles; /** * default constructor using a common user id. */ public User() { this(COMMON_USER, null); } public User(NavigatorConfigurationIF navConf) { this(COMMON_USER, navConf); } public User(String userId, NavigatorConfigurationIF navConf) { if (userId == null) userId = COMMON_USER; this.id = userId; // how many bundles? max_bundles = navConf.getProperty("maxUserBundles", DEFAULT_MAX_BUNDLES); logger.debug("max_bundles: " + max_bundles); // set default values setMVS(DEFAULT_MODEL, DEFAULT_VIEW, DEFAULT_SKIN); // bundle expiry time? bundleExpiryAge = navConf.getProperty("userBundleExpiryTime", DEFAULT_BUNDLE_EXPIRY); initialBundleExpiryAge = bundleExpiryAge; } public String getId() { return id; } // --- filterContext accessor methods public UserFilterContextStore getFilterContext() { if (filterContext == null) filterContext = new UserFilterContextStore(); return filterContext; } // -- history public HistoryMap getHistory() { if (history == null) history = new HistoryMap(); return history; } public void setHistory(HistoryMap history) { this.history = history; } // -- logs public Logger getLogger() { throw new OntopiaRuntimeException("This method has been disabled. Please contact <support@ontopia.net> if you were using it."); } public List getLogMessages() { synchronized (this) { if (log == null) log = new RingBuffer(); return log.getElements(); } } public void addLogMessage(String message) { synchronized (this) { if (log == null) log = new RingBuffer(); log.addElement(message); } } public void clearLog() { synchronized (this) { if (log == null) log = new RingBuffer(); log.clear(); } } // -- working bundles public synchronized void addWorkingBundle(String bundle_id, Object object) { removeOldWorkingBundles(bundle_id); if (timeStamps == null) timeStamps = new LRUMap(max_bundles); timeStamps.put(object, new Date()); if (workingBundles == null) workingBundles = new LRUMap(max_bundles); workingBundles.put(bundle_id, object); } public synchronized Object getWorkingBundle(String bundle_id) { removeOldWorkingBundles(bundle_id); if (bundle_id == null) return null; if (workingBundles == null) workingBundles = new LRUMap(max_bundles); return workingBundles.get(bundle_id); } public synchronized void removeWorkingBundle(String bundle_id) { removeOldWorkingBundles(bundle_id); if (workingBundles == null) workingBundles = new LRUMap(max_bundles); workingBundles.remove(bundle_id); } /** * INTERNAL: Remove (expire) any actions that are older than * bundleExpiryAge seconds. * @param keepBundle Doesn't remove the bundle with this ID. */ private void removeOldWorkingBundles(String keepBundle) { if (workingBundles == null) return; // nothing to remove logger.debug("Removing working bundles older than " + bundleExpiryAge + " seconds; now at " + workingBundles.size() + " bundles"); long expiryTime = new Date().getTime() - (bundleExpiryAge * 1000); Iterator bundleIterator = workingBundles.entrySet().iterator(); while (bundleIterator.hasNext()) { Map.Entry currentEntry = (Map.Entry)bundleIterator.next(); String currentKey = (String)currentEntry.getKey(); Object currentBundle = currentEntry.getValue(); Date bundledate = ((Date)timeStamps.get(currentBundle)); if ((bundledate == null || bundledate.getTime() < expiryTime) && !currentKey.equals(keepBundle)) { bundleIterator.remove(); timeStamps.remove(currentKey); logger.debug("Expired working bundle with id \"" + currentKey + "\"," + " since it's older than " + bundleExpiryAge + " seconds."); } } } /** * INTERNAL: Sets bundleExpiryAge to a given value. * @param bundleExpiryAge age in seconds until bundles expire. */ public synchronized void setBundleExpiryAge(long bundleExpiryAge) { logger.debug("Setting bundleExpiryAge to " + bundleExpiryAge + " seconds."); this.bundleExpiryAge = bundleExpiryAge; } /** * INTERNAL: Resets bundleExpiryAge to its initial value. */ public synchronized void resetBundleExpiryAge() { logger.debug("Setting bundleExpiryAge to the initial value of " + initialBundleExpiryAge + " seconds."); bundleExpiryAge = initialBundleExpiryAge; } // --- Model methods public void setModel(String model) { this.model = model; } public String getModel() { return model; } // --- View methods public void setView(String view) { this.view = view; } public String getView() { return view; } // --- Skin methods public void setSkin(String skin) { this.skin = skin; } public String getSkin() { return skin; } // convenience method public void setMVS(String model, String view, String skin) { this.model = model; this.view = view; this.skin = skin; } }