/*
* 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;
}
}