/* * Lokomo OneCMDB - An Open Source Software for Configuration * Management of Datacenter Resources * * Copyright (C) 2006 Lokomo Systems AB * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA. * * Lokomo Systems AB can be contacted via e-mail: info@lokomo.com or via * paper mail: Lokomo Systems AB, Sv�rdv�gen 27, SE-182 33 * Danderyd, Sweden. * */ package org.onecmdb.core.internal; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.onecmdb.core.IOneCmdbContext; import org.onecmdb.core.IService; import org.onecmdb.core.ISession; import org.onecmdb.core.tests.profiler.Profiler; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; /** * Configuration: * <ul> * <li>A notification framework</li> * </ul> * */ public class OneCmdb implements IOneCmdbContext, ApplicationContextAware { private List<IService> services; private ApplicationContext applicationContext; private Log log = LogFactory.getLog(this.getClass()); private Long sessionTimeout = null; private Long scanIntervall = null; private SessionCleanerThread sessionCleaner; // {{{ ---| BEAN properties, to satisfy spring |--- public OneCmdb() { } public void setServices(List<IService> services) { this.services = services; } public void setProfiler(boolean value) { Profiler.useProfiler(value); } // }}} public Long getSessionTimeout() { return sessionTimeout; } public void setSessionTimeout(Long sessionTimeout) { this.sessionTimeout = sessionTimeout; } public Long getScanIntervall() { return scanIntervall; } public void setScanIntervall(Long scanIntervall) { this.scanIntervall = scanIntervall; } public void init() { // Initialize all Services. for (IService service : services) { service.init(); } // Start the session cleaner thread. sessionCleaner = new SessionCleanerThread(); if (scanIntervall != null) { sessionCleaner.setScanIntervall(scanIntervall); } if (sessionTimeout != null) { sessionCleaner.setTimeout(sessionTimeout); } // Release the thread. sessionCleaner.start(); log.info("OneCMDB successfully initialized {"); log.info(" CWD=" + System.getProperty("user.dir")); log.info("}"); } public static Log getLogger(Class module) { return LogFactory.getLog(module); } public ISession createSession() { ISession session = (ISession) applicationContext.getBean("session"); return (session); } public IService getService(ISession session, Class<? extends IService> type) { for (final IService svc : this.services) { if (type.isAssignableFrom(svc.getClass())) { // How to handle Session object, all services might need to know // which session is executing the call? return svc; } } return null; } public void close() { log.debug("Closing OneCMDB..."); // Close session cleaner. if (this.sessionCleaner != null) { this.sessionCleaner.terminate(); } for (IService svc : this.services) { try { svc.close(); } catch (Throwable t) { // To be sure to close as much as possible. log.error("Unable to close service <" + svc + ">", t); } } log.info("OneCMDB closed."); } public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { if (this.applicationContext == null) this.applicationContext = applicationContext; } /** * Class to handle timeout of sessions. */ class SessionTS { private ISession session; private long ts; public SessionTS(ISession session) { this.session = session; updateTS(); } public void updateTS() { this.ts = System.currentTimeMillis(); } public long getTS() { return(this.ts); } public ISession getSession() { return(this.session); } } class SessionCleanerThread extends Thread { // Time in ms before a session is logout. // Default is 4 hour. private long sessionTimeout = 4*60*60*1000; private volatile boolean terminate = false; private Log log = LogFactory.getLog(this.getClass()); // How often to scan it. // Default every 10 minute. private long scanIntervall = 10*60*1000; // Default 1 minute. public SessionCleanerThread() { } public void setTimeout(long ts) { if (ts < 1000) { log.info("Session timeout " + ts + " to short!"); return; } this.sessionTimeout = ts; } public void setScanIntervall(long intervall) { this.scanIntervall = intervall; } public void terminate() { this.terminate = true; synchronized(this) { this.notifyAll(); } } public void run() { log.info("Session Cleaner Start: sessionTimeout=" + this.sessionTimeout +", scanIntervall=" + this.scanIntervall); while (!terminate) { try { long currentTs = System.currentTimeMillis(); // Terminated sessions. List<Object> timeouted = new ArrayList<Object>(); for (Object key : sessionMap.keySet()) { SessionTS ts = sessionMap.get(key); if ((ts.getTS() + this.sessionTimeout) < currentTs) { // Log out. timeouted.add(key); } } for (Object key : timeouted) { SessionTS ts = sessionMap.get(key); log.info("Session token <" + key + "> timed out, inactive for (" + (currentTs - ts.getTS()) + "ms)"); removeSession(key); } } catch (Throwable t) { log.error("Session cleaner encountered exception:", t); } finally { synchronized(this) { try { this.wait(scanIntervall); } catch (InterruptedException e) { log.error("Session cleaner got interrupted!."); } } } } log.info("Session Cleaner Terminated"); } } /** * Session handling. */ HashMap<Object, SessionTS> sessionMap = new HashMap<Object, SessionTS>(); public void addSession(Object token, ISession session) { sessionMap.put(token, new SessionTS(session)); } public ISession getSession(Object token) { SessionTS session = sessionMap.get(token); if (session == null) { return(null); } session.updateTS(); return(session.getSession()); } public void removeSession(Object token) { SessionTS session = sessionMap.remove(token); if (session != null) { session.getSession().logout(); } } }