/**
* Copyright 2012 Voxbone SA/NV
*
* 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 org.ifsoft.sip;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import javax.sip.address.SipURI;
import org.slf4j.*;
import org.slf4j.Logger;
import org.apache.xml.serialize.OutputFormat;
import org.apache.xml.serialize.XMLSerializer;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
/**
* Table to track all active SIP Events dialogs
*
*/
public class SipSubscriptionManager
{
private static final Logger Log = LoggerFactory.getLogger(SipSubscriptionManager.class);
// Outbound subscriptions
static Hashtable<String, List<SipSubscription>> subscriptions = new Hashtable<String, List<SipSubscription>>();
// Inbound subscriptions
static Hashtable<String, List<SipSubscription>> watchers = new Hashtable<String, List<SipSubscription>>();
private static String spoolPath = null;
public static void configure(Properties properties) {
spoolPath = properties.getProperty("com.voxbone.kelpie.spool_directory", "/var/spool/kelpie");
}
public static void addSubscriber(String user, SipSubscription subscription)
{
synchronized (subscriptions)
{
if (subscriptions.get(user) == null)
{
subscriptions.put(user, new LinkedList<SipSubscription>());
}
subscriptions.get(user).add(subscription);
subscription.schedule();
try
{
saveSubscription(subscription);
}
catch (IOException e)
{
Log.error("Error persisting new subscription", e);
}
catch (SAXException e)
{
Log.error("Error persisting new subscription", e);
}
}
}
public static void addWatcher(String user, SipSubscription subscription)
{
synchronized (watchers)
{
if (watchers.get(user) == null)
{
watchers.put(user, new LinkedList<SipSubscription>());
}
watchers.get(user).add(subscription);
try
{
saveWatcher(subscription);
}
catch (IOException e)
{
Log.error("Error persisting new watcher", e);
}
catch (SAXException e)
{
Log.error("Error persisting new watcher", e);
}
}
}
public static SipSubscription getWatcherByCallID(String user, String callId)
{
synchronized (watchers)
{
List<SipSubscription> subs = watchers.get(user);
if (subs == null)
{
return null;
}
for (SipSubscription sub : subs)
{
if (callId.equals(sub.callId))
{
return sub;
}
}
}
return null;
}
public static SipSubscription getSubscriptionByCallID(String user, String callId)
{
synchronized (subscriptions)
{
List<SipSubscription> subs = subscriptions.get(user);
if (subs == null)
{
return null;
}
for (SipSubscription sub : subs)
{
if (callId.equals(sub.callId))
{
return sub;
}
}
}
return null;
}
public static SipSubscription getSubscription(String user, String dest)
{
synchronized (subscriptions)
{
List<SipSubscription> subs = subscriptions.get(user);
if (subs!=null)
{
for (SipSubscription sub : subs)
{
String subDest = ((SipURI) sub.remoteParty.getURI()).getUser();
if (subDest.equals(dest))
{
return sub;
}
}
}
}
return null;
}
public static void removeWatcher(String user, SipSubscription subscription)
{
synchronized (watchers)
{
List<SipSubscription> subs = watchers.get(user);
subs.remove(subscription);
deleteWatcher(subscription);
}
}
public static SipSubscription getWatcher(String user, String dest)
{
synchronized (watchers)
{
List<SipSubscription> subs = watchers.get(user);
if (subs!=null)
{
for (SipSubscription sub : subs)
{
String subDest = ((SipURI) sub.remoteParty.getURI()).getUser();
if (subDest.equals(dest))
{
return sub;
}
}
}
}
return null;
}
public static SipSubscription removeSubscription(String user, String dest)
{
synchronized (subscriptions)
{
List<SipSubscription> subs = subscriptions.get(user);
if (subs!=null)
{
for (SipSubscription sub : subs)
{
String subDest = ((SipURI) sub.remoteParty.getURI()).getUser();
if (subDest.equals(dest))
{
sub.cancel();
subs.remove(sub);
deleteSubscription(sub);
return sub;
}
}
}
}
return null;
}
public static SipSubscription removeSubscriptionByCallID(String user, String callID)
{
synchronized (subscriptions)
{
List<SipSubscription> subs = subscriptions.get(user);
if (subs!=null)
{
for (SipSubscription sub : subs)
{
if (sub.callId.equals(callID))
{
sub.cancel();
subs.remove(sub);
deleteSubscription(sub);
return sub;
}
}
}
}
return null;
}
public static void saveSubscription(SipSubscription sub) throws IOException, SAXException
{
String filename = spoolPath + "/subscriptions/" + ((SipURI) sub.localParty.getURI()).getUser() + "_" + sub.callId;
FileOutputStream fs = new FileOutputStream(new File(filename));
OutputFormat of = new OutputFormat("XML", "ISO-8859-1", true);
of.setIndent(1);
of.setIndenting(true);
XMLSerializer serializer = new XMLSerializer(fs, of);
ContentHandler hd = serializer.asContentHandler();
hd.startDocument();
hd.startElement("", "", "SUBSCRIPTION", null);
sub.buildSubscriptionXML(hd);
hd.endElement("", "", "SUBSCRIPTION");
hd.endDocument();
fs.close();
}
public static void saveWatcher(SipSubscription sub) throws IOException, SAXException
{
String filename = spoolPath + "/watchers/" + ((SipURI) sub.localParty.getURI()).getUser() + "_" + sub.callId;
FileOutputStream fs = new FileOutputStream(new File(filename));
OutputFormat of = new OutputFormat("XML", "ISO-8859-1", true);
of.setIndent(1);
of.setIndenting(true);
XMLSerializer serializer = new XMLSerializer(fs, of);
ContentHandler hd = serializer.asContentHandler();
hd.startDocument();
hd.startElement("", "", "SUBSCRIPTION", null);
sub.buildSubscriptionXML(hd);
hd.endElement("", "", "SUBSCRIPTION");
hd.endDocument();
fs.close();
}
public static void deleteSubscription(SipSubscription sub)
{
try {
String filename = spoolPath + "/subscriptions/" + ((SipURI) sub.localParty.getURI()).getUser() + "_" + sub.callId;
File file = new File(filename);
file.delete();
} catch(Exception ioe) {
System.err.println( ioe.getMessage() + "Error deleting!");
}
}
public static void deleteWatcher(SipSubscription sub)
{
try {
String filename = spoolPath + "/watchers/" + ((SipURI) sub.localParty.getURI()).getUser() + "_" + sub.callId;
File file = new File(filename);
file.delete();
} catch(Exception ioe) {
System.err.println( ioe.getMessage() + "Error deleting!");
}
}
public static void loadData()
{
long now = System.currentTimeMillis();
String dirName = spoolPath + "/subscriptions/";
File dirFile = new File(dirName);
String [] children = dirFile.list();
for (String child : children)
{
SipSubscription sub = new SipSubscription(dirName + child);
if (sub != null)
{
if (now < sub.expires)
{
String user = ((SipURI) sub.localParty.getURI()).getUser();
Log.info("adding subscriber for " + user);
synchronized (subscriptions)
{
if (subscriptions.get(user) == null)
{
subscriptions.put(user, new LinkedList<SipSubscription>());
}
subscriptions.get(user).add(sub);
long nextCall = sub.expires - now - (1800 * 1000);
if (nextCall < 0)
{
nextCall = 0;
}
sub.schedule(nextCall);
}
}
else
{
Log.error("Skipping already expired subscription");
try
{
deleteSubscription(sub);
}
catch(Exception e)
{
Log.error("Error Deleting subscription");
}
}
}
}
dirName = spoolPath + "/watchers/";
dirFile = new File(dirName);
children = dirFile.list();
for (String child : children)
{
SipSubscription sub = new SipSubscription(dirName + child);
if (now < sub.expires)
{
String user = ((SipURI) sub.localParty.getURI()).getUser();
Log.info("adding watcher for " + user);
synchronized (watchers)
{
if (watchers.get(user) == null)
{
watchers.put(user, new LinkedList<SipSubscription>());
}
watchers.get(user).add(sub);
}
}
else
{
Log.error("Skipping already expired watcher");
deleteWatcher(sub);
}
}
}
}