/* * Copyright 2006-2010 Daniel Henninger. All rights reserved. * * This software is published under the terms of the GNU Public License (GPL), * a copy of which is included in this distribution. */ package net.sf.kraken.session; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import net.sf.kraken.BaseTransport; import net.sf.kraken.roster.TransportBuddy; import org.jivesoftware.util.NotFoundException; import org.jivesoftware.openfire.SessionManager; import org.jivesoftware.openfire.XMPPServer; import org.xmpp.packet.JID; /** * Manages sessions with legacy transports implementations. * * Keeps track of all of the active sessions with the various transports. * Only one expected to be associated with a single transport instance. * * @author Daniel Henninger */ public class TransportSessionManager<B extends TransportBuddy> { /** * Container for all active sessions. */ private ConcurrentHashMap<JID,TransportSession<B>> activeSessions = new ConcurrentHashMap<JID,TransportSession<B>>(); /** * Timer to check for orphaned sessions. */ private Timer timer = new Timer(); /** * Interval at which sessions are reaped. */ private int reaperInterval = 300000; // 5 minutes /** * How long a detached session is allowed to be suspended before it is cleaned up. */ private int detachTimeout = 60000; // 10 minutes /** * The actual repear task. */ private SessionReaper sessionReaper; /** * The transport we are associated with. */ BaseTransport<B> transport; /** * Creates the transport session manager instance and initializes. * * @param transport Transport associated with this session manager. */ public TransportSessionManager(BaseTransport<B> transport) { this.transport = transport; sessionReaper = new SessionReaper(); timer.schedule(sessionReaper, reaperInterval, reaperInterval); } /** * Shuts down the session manager. */ public void shutdown() { sessionReaper.cancel(); timer.cancel(); } /** * Retrieve the session instance for a given JID. * * Ignores the resource part of the jid. * * @param jid JID of the instance to be retrieved. * @throws NotFoundException if the given jid is not found. * @return TransportSession instance requested. */ public TransportSession<B> getSession(JID jid) throws NotFoundException { TransportSession<B> session = activeSessions.get(new JID(jid.toBareJID())); if (session == null) { throw new NotFoundException("Could not find session requested."); } return session; } /** * retrieves the session instance for a given user. * * @param username Username of the instance to be retrieved. * @throws NotFoundException if the given username is not found. * @return TransportSession instance requested. */ public TransportSession<B> getSession(String username) throws NotFoundException { TransportSession<B> session = activeSessions.get(XMPPServer.getInstance().createJID(username, null)); if (session == null) { throw new NotFoundException("Could not find session requested."); } return session; } /** * Stores a new session instance with the legacy service. * * Expects to be given a JID and a pre-created session. Ignores the * resource part of the JID. * * @param jid JID information used to track the session. * @param session TransportSession associated with the jid. */ public void storeSession(JID jid, TransportSession<B> session) { activeSessions.put(new JID(jid.toBareJID()), session); getTransport().getSessionRouter().addSession(getTransport().getType().toString(), jid.toBareJID()); } /** * Removes a session instance with the legacy service. * * Expects to be given a JID which indicates which session we are * removing. * * @param jid JID to be removed. */ public void removeSession(JID jid) { TransportSession<B> session = activeSessions.remove(new JID(jid.toBareJID())); if (session != null) { session.getBuddyManager().sendOfflineForAllAvailablePresences(jid); } getTransport().getSessionRouter().removeSession(getTransport().getType().toString(), jid.toBareJID()); } /** * Retrieves a collection of all active sessions. * * @return List of active sessions. */ public Collection<TransportSession<B>> getSessions() { return activeSessions.values(); } /** * Bury any transport sessions that no longer have an associated xmpp session. */ private class SessionReaper extends TimerTask { /** * Kill any session that has been orphaned. */ @Override public void run() { cleanupOrphanedSessions(); } } /** * Compares active xmpp sessions with active transport sessions and buries the orphaned. */ private void cleanupOrphanedSessions() { SessionManager sessionManager = SessionManager.getInstance(); for (TransportSession<B> session : getSessions()) { if ((session.getDetachTimestamp() == 0 || new Date().getTime() - session.getDetachTimestamp() > detachTimeout) && sessionManager.getSessionCount(session.getJID().getNode()) == 0) { transport.registrationLoggedOut(session); } } } /** * Retrieves the transport this session manager is associated with. * * @return transport associated with this session manager. */ public BaseTransport<B> getTransport() { return this.transport; } }