package com.rayo.server.listener; import java.util.List; import javax.servlet.ServletContext; import org.springframework.web.context.support.WebApplicationContextUtils; import org.springframework.web.context.support.XmlWebApplicationContext; import com.rayo.core.EndCommand; import com.rayo.core.EndEvent; import com.rayo.server.CallActor; import com.rayo.server.CallRegistry; import com.rayo.server.JIDRegistry; import com.voxeo.logging.Loggerf; import com.voxeo.servlet.xmpp.Feature; import com.voxeo.servlet.xmpp.XmppSession; import com.voxeo.servlet.xmpp.XmppSession.Type; import com.voxeo.servlet.xmpp.XmppSessionEvent; import com.voxeo.servlet.xmpp.XmppSessionListener; /** * <p>This session listener acts as a watchdog prevention SIP application session leaks * that may be caused by XMPP clients disconnecting without having released the * active calls.</p> * * <p>Therefore, the session listener will capture session destroy events and it * will check the status of any active calls for the XMPP Session's JID. If any active * call is found then the call will be terminated.</p> * * <p>Resources cleanup can be configured by using the {@link SessionCleanupConfig} configuration * class which is defined in Rayo Server's Spring configuration file.</p> * * @author martin * */ public class RayoSessionListener implements XmppSessionListener { private static final Loggerf logger = Loggerf.getLogger(RayoSessionListener.class); private JIDRegistry jidRegistry; private CallRegistry callRegistry; private SessionCleanupConfig sessionCleanupConfig; @Override public void sessionCreated(XmppSessionEvent xse) { logger.debug("Xmpp Session created"); ServletContext context = xse.getSession().getServletContext(); XmlWebApplicationContext wac = (XmlWebApplicationContext)WebApplicationContextUtils .getRequiredWebApplicationContext(context); callRegistry = wac.getBean(CallRegistry.class); jidRegistry = wac.getBean(JIDRegistry.class); sessionCleanupConfig = wac.getBean(SessionCleanupConfig.class); } @Override public void onFeature(XmppSessionEvent xse, List<Feature> features) { logger.debug("Received feature"); } @Override public void sessionDestroyed(XmppSessionEvent xse) { logger.debug("Xmpp Session destroyed"); XmppSession session = xse.getSession(); if (session != null) { boolean cleanup = (session.getType() == Type.S2S && sessionCleanupConfig.isCleanupS2SResources()) || (session.getType() != Type.S2S && sessionCleanupConfig.isCleanupC2SResources()); if (cleanup) { List<String> callIds = jidRegistry.getCallsByJID(session.getRemoteJID()); for (String id: callIds) { try { CallActor<?> actor = callRegistry.get(id); if (actor != null) { actor.publish(new EndCommand(id, EndEvent.Reason.ERROR)); } } catch (Exception e) { logger.error(e.getMessage(),e); } } } } } public void setJidRegistry(JIDRegistry jidRegistry) { this.jidRegistry = jidRegistry; } public void setCallRegistry(CallRegistry callRegistry) { this.callRegistry = callRegistry; } public void setSessionCleanupConfig(SessionCleanupConfig sessionCleanupConfig) { this.sessionCleanupConfig = sessionCleanupConfig; } }