package com.voxeo.tropo;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.servlet.ServletConfig;
import org.apache.log4j.Logger;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import com.micromethod.common.util.CodeUtils;
import com.micromethod.common.util.NetworkUtils;
import com.micromethod.common.util.annotation.StringPart;
import com.voxeo.tropo.app.ApplicationManager;
import com.voxeo.tropo.app.MockAppMgr;
import com.voxeo.tropo.util.ConfigurationItem;
public class Configuration {
public static final Logger LOG = Logger.getLogger(Configuration.class);
private static Configuration INSTANCE = null;
private static String LOCAL_ADDRESS = NetworkUtils.getLocalAddress().getHostAddress();
@StringPart
private String _mediaServer = "127.0.0.1";
@StringPart
private int _mediaServerPort = 9974;
@StringPart
@ConfigurationItem
private int maxTimeSpeak = 300000;
@StringPart
@ConfigurationItem
private int maxTimeListen = 60000;
@StringPart
@ConfigurationItem
private String termTimeout = "0";
@StringPart
@ConfigurationItem
private String termChar = "#";
@StringPart
@ConfigurationItem
private String noInputTimeout = "10000";
@StringPart
@ConfigurationItem
private String confidenceLevel = "0.3";
@StringPart
@ConfigurationItem
private String sensitivity = "0.5";
@StringPart
@ConfigurationItem
private String speedVsAccuracy = "0.5";
@StringPart
@ConfigurationItem
private String asrSpeechLanguage = "en-us-prophecy";
@StringPart
@ConfigurationItem
private String ttsSpeechLanguage = "en-US";
@StringPart
@ConfigurationItem
private boolean killOnBargeIn = true;
@StringPart
@ConfigurationItem
private String beepURL = "http://127.0.0.1:8080/beep.wav";
@StringPart
@ConfigurationItem
private String phoneSBC = "sbc-staging-internal.orl.voxeo.net";
@StringPart
@ConfigurationItem
private boolean parseSpeechText = true;
@StringPart
@ConfigurationItem
private boolean hackSDP = true;
@StringPart
@ConfigurationItem
private String mediaAddress = null;
@StringPart
private Map<String, String> _scriptHeaders = new HashMap<String, String>();
@StringPart
private Map<String, Integer> _enginePoolSizes = new HashMap<String, Integer>();
@StringPart
private Class<? extends ApplicationManager> _appManager = MockAppMgr.class;
@StringPart
private Map<String, String> _appManagerParas = new HashMap<String, String>();
@StringPart
@ConfigurationItem
private boolean enableSecurityManager = true;
@StringPart
@ConfigurationItem
private long appMonitorTime = 60000;
@StringPart
@ConfigurationItem
private int threadSize = 400;
@StringPart
private Map<String, Set<String>> sandboxAllow = new HashMap<String, Set<String>>();
@StringPart
private Map<String, Set<String>> sandboxForbid = new HashMap<String, Set<String>>();
public static Configuration get() {
if (INSTANCE == null) {
throw new IllegalArgumentException("Tropo configuratrion has not been initialized.");
}
return INSTANCE;
}
public static void init(final ServletConfig config) throws JDOMException, IOException, ClassNotFoundException {
String xml = config.getInitParameter("configuration");
if (xml == null) {
xml = "/tropo.xml";
}
final InputStream i = Configuration.class.getResourceAsStream(xml);
if (i == null) {
throw new IOException("Unable to find configuration XML: " + xml);
}
try {
INSTANCE = new Configuration(i);
}
finally {
i.close();
}
}
@Override
public String toString() {
return CodeUtils.toStringByAnnotation(this);
}
@SuppressWarnings("unchecked")
private Configuration(final InputStream i) throws JDOMException, IOException, ClassNotFoundException {
_scriptHeaders.put("js", "com/voxeo/tropo/javascript/tropo.js");
_scriptHeaders.put("groovy", "com/voxeo/tropo/groovy/tropo.groovy");
_scriptHeaders.put("jython", "com/voxeo/tropo/jython/tropo.jy");
_scriptHeaders.put("php", "com/voxeo/tropo/php/tropo.php");
_scriptHeaders.put("jruby", "com/voxeo/tropo/jruby/tropo.rb");
final SAXBuilder b = new SAXBuilder();
b.setValidation(false);
final Element f = b.build(i).getRootElement();
enableSecurityManager = Boolean.parseBoolean(f.getAttributeValue("enableSecurityManager"));
final String threads = f.getAttributeValue("threadSize");
if (threads != null && threads.length() > 0) {
threadSize = Integer.parseInt(threads);
}
// security manager
if (enableSecurityManager) {
Element e = f.getChild("sandbox");
if (e != null) {
parseSandbox(e);
}
}
// media server configurations
final Element m = f.getChild("mediaServer");
if (m != null) {
if (m.getAttributeValue("host") != null) {
_mediaServer = m.getAttributeValue("host");
}
if (m.getAttributeValue("port") != null) {
_mediaServerPort = Integer.parseInt(m.getAttributeValue("port"));
}
quickSetValue(this, m);
}
if (mediaAddress == null || mediaAddress.length() == 0) {
if (_mediaServer.equals("127.0.0.1")) {
mediaAddress = LOCAL_ADDRESS;
}
else {
mediaAddress = _mediaServer;
}
}
// app manager configurations
final Element a = f.getChild("appManager");
if (a != null) {
_appManager = (Class<? extends ApplicationManager>) this.getClass().getClassLoader().loadClass(
a.getAttributeValue("class"));
final List<Element> ls = a.getChildren("para");
for (final Element p : ls) {
_appManagerParas.put(p.getAttributeValue("name"), p.getAttributeValue("value"));
}
}
// scripts configurations
final Element s = f.getChild("scripts");
if (s != null) {
final List<Element> ls = s.getChildren("script");
for (final Element p : ls) {
String type = p.getAttributeValue("type");
_scriptHeaders.put(type, p.getAttributeValue("file"));
String size = p.getAttributeValue("enginePoolSize");
if (size != null && size.length() > 0) {
_enginePoolSizes.put(type, Integer.valueOf(size));
}
else {
_enginePoolSizes.put(type, Integer.valueOf(20));
}
}
}
// debug loggging
if (LOG.isDebugEnabled()) {
LOG.debug("Loaded config " + toString());
}
}
/**
* @param _mediaServer
* the _mediaServer to set
*/
public void setMediaServer(final String mediaServer) {
this._mediaServer = mediaServer;
}
/**
* @return the _mediaServer
*/
public String getMediaServer() {
return _mediaServer;
}
/**
* @param _mediaServerPort
* the _mediaServerPort to set
*/
public void setMediaServerPort(final int mediaServerPort) {
this._mediaServerPort = mediaServerPort;
}
/**
* @return the _mediaServerPort
*/
public int getMediaServerPort() {
return _mediaServerPort;
}
/**
* @param _appManager
* the _appManager to set
*/
public void setAppManager(final Class<? extends ApplicationManager> appManager) {
this._appManager = appManager;
}
/**
* @return the _appManager
*/
public Class<? extends ApplicationManager> getAppManager() {
return _appManager;
}
/**
* @param _appManagerParas
* the _appManagerParas to set
*/
public void setAppManagerParas(final Map<String, String> appManagerParas) {
this._appManagerParas = appManagerParas;
}
/**
* @return the _appManagerParas
*/
public Map<String, String> getAppManagerParas() {
return _appManagerParas;
}
public String getScriptHeader(final String type) {
return _scriptHeaders.get(type);
}
public Map<String, Integer> getEnginePoolSizes() {
return _enginePoolSizes;
}
public int getMaxTimeSpeak() {
return maxTimeSpeak;
}
public int getMaxTimeListen() {
return maxTimeListen;
}
public String getTermTimeout() {
return termTimeout;
}
public String getTermChar() {
return termChar;
}
public String getNoInputTimeout() {
return noInputTimeout;
}
public String getConfidenceLevel() {
return confidenceLevel;
}
public String getSensitivity() {
return sensitivity;
}
public String getSpeedVsAccuracy() {
return speedVsAccuracy;
}
public String getAsrSpeechLanguage() {
return asrSpeechLanguage;
}
public String getTtsSpeechLanguage() {
return ttsSpeechLanguage;
}
public boolean isKillOnBargeIn() {
return killOnBargeIn;
}
public String getBeepURL() {
return beepURL;
}
public String getPhoneSBC() {
return phoneSBC;
}
public boolean isParseSpeechText() {
return parseSpeechText;
}
public boolean getHackSDP() {
return hackSDP;
}
public String getMediaAddress() {
return mediaAddress;
}
public String getLocalAddress() {
return LOCAL_ADDRESS;
}
public long getApplicationMonitorTime() {
return appMonitorTime;
}
public void setApplicationMonitorTime(final long time) {
appMonitorTime = time;
}
public int getThreadSize() {
return threadSize;
}
private static void quickSetValue(final Object o, final Element m) {
for (final Field field : o.getClass().getDeclaredFields()) {
if (field.isAnnotationPresent(ConfigurationItem.class)) {
final String name = field.getName();
String value = m.getChildText(name);
if (value != null) {
value = value.trim();
final boolean accessibility = field.isAccessible();
try {
field.setAccessible(true);
final Class<?> type = field.getType();
if (type == int.class) {
field.set(o, Integer.parseInt(value));
}
else if (type == long.class) {
field.set(o, Long.parseLong(value));
}
else if (type == boolean.class) {
field.set(o, Boolean.parseBoolean(value));
}
else {
field.set(o, value);
}
}
catch (final Throwable t) {
LOG.error("", t);
}
finally {
field.setAccessible(accessibility);
}
}
}
}
}
/**
* @return the enableSecurityManager
*/
public boolean isEnableSecurityManager() {
return enableSecurityManager;
}
@SuppressWarnings("unchecked")
public void parseSandbox(Element s){
List<Element> as = s.getChildren("allow");
for(Element a:as){
List<Element> is = a.getChildren("item");
for(Element i:is){
String action = i.getAttributeValue("action");
String target = i.getTextNormalize().toLowerCase();
Set t = sandboxAllow.get(action);
if(t==null){
t=new HashSet();
sandboxAllow.put(action, t);
}
t.add(target);
}
}
as = s.getChildren("forbid");
for(Element a:as){
List<Element> is = a.getChildren("item");
for(Element i:is){
String action = i.getAttributeValue("action");
String target = i.getTextNormalize().toLowerCase();
Set t = sandboxForbid.get(action);
if(t==null){
t=new HashSet();
sandboxForbid.put(action, t);
}
t.add(target);
}
}
}
/**
* @return the sandboxForbid
*/
Map<String, Set<String>> getSandboxForbid() {
return sandboxForbid;
}
/**
* @return the sandboxAllow
*/
Map<String, Set<String>> getSandboxAllow() {
return sandboxAllow;
}
}