package com.voxeo.tropo.app;
import java.io.File;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryUsage;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.WeakHashMap;
import java.util.concurrent.atomic.AtomicLong;
import javax.servlet.ServletContext;
import javax.servlet.sip.SipFactory;
import javax.servlet.sip.URI;
import org.apache.log4j.Logger;
import com.voxeo.sipmethod.mrcp.client.Endpoint;
import com.voxeo.sipmethod.mrcp.client.MrcpClient;
import com.voxeo.sipmethod.mrcp.client.MrcpFactory;
import com.voxeo.tropo.Configuration;
import com.voxeo.tropo.ServletContextConstants;
import com.voxeo.tropo.util.Utils;
public abstract class AbstractApplicationManager implements ApplicationManager {
private static final Logger LOG = Logger.getLogger(AbstractApplicationManager.class);
protected static ApplicationManager APP_MGR = null;
protected SipFactory _sipFactory;
protected MrcpFactory _mrcpFactory;
protected ServletContext _context;
protected Map<Object, Application> _cache;
protected String _appJarUrl;
protected String _tropoVersionNo;
protected String _tropoBuildDate;
protected String _tropoBuildNo;
protected ThreadMXBean _tmx;;
protected MemoryMXBean _mmx;
protected Date _startTime;
public void init(final ServletContext context, final Map<String, String> paras) {
_startTime = new Date();
_context = context;
_sipFactory = (SipFactory) context.getAttribute(ServletContextConstants.SIP_FACTORY);
_mrcpFactory = (MrcpFactory) context.getAttribute(ServletContextConstants.MRCP_FACTORY);
_appJarUrl = _context.getRealPath("/") + "WEB-INF" + File.separator + "lib" + File.separator + "tropo.jar";
_cache = Collections.synchronizedMap(new WeakHashMap<Object, Application>());
_tmx = ManagementFactory.getThreadMXBean();
_mmx = ManagementFactory.getMemoryMXBean();
try {
_tropoBuildDate = Utils.getManifestAttribute(_appJarUrl, "Build-Date");
}
catch (final IOException t) {
LOG.error(t.toString(), t);
_tropoBuildDate = "Unknown";
}
try {
_tropoVersionNo = Utils.getManifestAttribute(_appJarUrl, "Version-No");
}
catch (final IOException t) {
LOG.error(t.toString(), t);
_tropoVersionNo = "Unknown";
}
try {
_tropoBuildNo = Utils.getManifestAttribute(_appJarUrl, "Build-No");
}
catch (final IOException t) {
LOG.error(t.toString(), t);
_tropoBuildNo = "Unknown";
}
LOG.info(toString() + " / " + getVersionNo() + " / " + getBuildNo());
}
public SipFactory getSipFactory() {
return _sipFactory;
}
public MrcpFactory getMrcpFactory() {
return _mrcpFactory;
}
protected Application getCached(final Object key) {
return _cache.get(key);
}
protected void putCached(final Object key, final Application app) {
_cache.put(key, app);
}
protected void clearCached(final Application app) {
for(Iterator<Map.Entry<Object, Application>> i = _cache.entrySet().iterator(); i.hasNext();) {
Map.Entry<Object, Application> entry = i.next();
if (app.equals(entry.getValue())) {
i.remove();
}
}
}
public Application get(final URI uri) throws InvalidApplicationException, RedirectException {
Application app = getCached(uri);
if (LOG.isDebugEnabled()) {
LOG.debug(toString() + " found app=" + app + " for url=" + uri + ",_cache.size=" + _cache.size());
}
if (app == null) {
app = findApplication(uri);
putCached(uri, app);
if (LOG.isDebugEnabled()) {
LOG.debug(toString() + " cached app=" + app + " for url=" + uri + ",_cache.size=" + _cache.size());
}
}
else {
Utils.setLogContext(app, null);
LOG.info(app + " has been found.");
}
return app;
}
public Application get(final String token, final Properties params) throws InvalidApplicationException, RedirectException {
Application app = getCached(token);
if (LOG.isDebugEnabled()) {
LOG.debug("Mgr Found app=" + app + " for token=" + token + ",_cache.size=" + _cache.size());
}
if (app == null) {
app = findApplication(token, params);
if (LOG.isDebugEnabled()) {
LOG.debug("Mgr Cached app=" + app + " for token=" + token + ",_cache.size=" + _cache.size());
}
}
else {
Utils.setLogContext(app, null);
LOG.info(app + " has been found.");
}
return app;
}
protected abstract Application findApplication(URI uri) throws InvalidApplicationException, RedirectException;
protected abstract Application findApplication(String token, Properties params) throws InvalidApplicationException, RedirectException;
public void dispose() {
for (final Application app : _cache.values()) {
app.dispose();
}
_cache.clear();
}
public ThreadInfo[] getDeadLocks() {
final long[] ids = _tmx.findDeadlockedThreads();
if (ids != null) {
return _tmx.getThreadInfo(ids, true, true);
}
else {
return null;
}
}
public MemoryUsage getMemoryUsage() {
return _mmx.getHeapMemoryUsage();
}
private AtomicLong _newCalls = new AtomicLong(0);
private AtomicLong _endCalls = new AtomicLong(0);
public void incCallCounter() {
_newCalls.incrementAndGet();
}
public void decCallCounter() {
_endCalls.incrementAndGet();
}
public long getActiveCalls() {
return _newCalls.get() - _endCalls.get();
}
public long getTotalCalls() {
return _newCalls.get();
}
public String getVersionNo() {
return _tropoVersionNo;
}
public String getBuildNo() {
return _tropoBuildNo;
}
public String getBuildDate() {
return _tropoBuildDate;
}
// only the file name of the log, without path info
public Collection<String> listTropoLogNames() {
final File r = new File(_context.getRealPath("/") + "logs");
final File[] fs = r.listFiles();
final List<String> l = new ArrayList<String>();
for (final File f : fs) {
if (f.isFile()) {
l.add(f.getName());
}
}
return l;
}
public Collection<String> listSIPMethodLogNames() {
final File r = new File(_context.getRealPath("/") + "slogs");
final File[] fs = r.listFiles();
final List<String> l = new ArrayList<String>();
for (final File f : fs) {
if (f.isFile()) {
l.add(f.getName());
}
}
return l;
}
public boolean isMrcpServerConnected() {
try {
final MrcpClient client = _mrcpFactory.createMrcpClient(new Endpoint("", 1, null), Configuration.get()
.getMediaAddress(), Configuration.get().getMediaServerPort(), new Properties());
client.getAsrSession();
client.getAsrSession().unjoin();
client.getAsrSession().disconnect();
client.getAsrSession().invalidate();
return true;
}
catch (final Throwable t) {
return false;
}
}
public Date getSystemStartTime() {
return _startTime;
}
public static void load(Configuration c, ServletContext ctx) throws Exception {
final Class<? extends ApplicationManager> a = c.getAppManager();
Method m = a.getMethod("initialization", ServletContext.class);
m.invoke(null, ctx);
}
public static synchronized void initialization(final ServletContext ctx) throws InstantiationException, IllegalAccessException {
if (APP_MGR == null) {
final Class<? extends ApplicationManager> a = Configuration.get().getAppManager();
LOG.info("Initializing Application Manager [" + a + "] ...");
APP_MGR = a.newInstance();
APP_MGR.init(ctx, Configuration.get().getAppManagerParas());
ctx.setAttribute(ServletContextConstants.APP_MANAGER, APP_MGR);
if (APP_MGR instanceof ApplicationMonitor) {
ctx.setAttribute(ServletContextConstants.APP_MONITOR, APP_MGR);
}
}
}
}