package com.voxeo.tropo.app; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.util.HashMap; import java.util.Map; import java.util.Properties; import javax.script.Compilable; import javax.script.CompiledScript; import javax.script.ScriptEngine; import javax.script.ScriptException; import javax.servlet.http.HttpServletRequest; import javax.servlet.sip.SipServletRequest; import org.apache.log4j.Logger; import com.voxeo.tropo.Configuration; import com.voxeo.tropo.util.ChainedReader; import com.voxeo.tropo.util.Utils; @SuppressWarnings("serial") public class SimpleApplication extends AbstractApplication implements LocalApplication { private static final Logger LOG = Logger.getLogger(SimpleApplication.class); protected CompiledScript _compiledScript = null; protected String _baseDir; protected Object _waitLock = new Object(); // characters for each script languages protected static Map<String, String> CommentCharacterMap = new HashMap<String, String>(); static { CommentCharacterMap.put("js", " //"); // add some space for readable CommentCharacterMap.put("jruby", " #"); CommentCharacterMap.put("jython", " #"); CommentCharacterMap.put("groovy", " //"); CommentCharacterMap.put("php", " //"); } public SimpleApplication(final LocalApplicationManager mgr, final ApplicationURL url, final String type, final int aid, final String appId, final Properties params) throws InvalidApplicationException { super(mgr, url, type, aid, appId, params); _baseDir = Utils.getAppDir() + System.getProperty("file.separator") + String.valueOf(getAccountID()); // + System.getProperty("file.separator"); /* * TODO: when to delete this directory ???. Considering in hosting with a * cluster. */ File dir = new File(_baseDir); if (!dir.exists()) { if (!dir.mkdirs()) { LOG.error("Erron in creating directory: " + _baseDir); } } setLogContext(null); // _engine = mgr.getScriptEngine(type); // if (_engine == null) { // LOG.error("No scripting engine is available for type :" + getType()); // throw new InvalidApplicationException("No scripting engine is available for type :" + getType()); // } LOG.info(toString() + " has been created."); } public void execute(final SipServletRequest invite) throws ScriptException, IOException { setLogContext(invite); try { final CompiledScript script = getCompiledScript(); final ApplicationInstance inst = new SimpleInstance(invite, script, this); ((LocalApplicationManager)_mgr).execute(inst); } catch (final ScriptException e) { LOG.error(Utils.buildScriptExceptionMessage(this, "compilation", e), e); throw e; } catch (final FileNotFoundException e) { LOG.error(this + " can not find the script: " + e.getMessage(), e); throw e; } catch (final IOException e) { LOG.error(this + " can not read the script: " + e.getMessage(), e); throw e; } catch (final Throwable e) { LOG.error(this + " has unknown errors: " + e.getMessage(), e); throw new RuntimeException(e); } } public void execute(final HttpServletRequest req) throws ScriptException, IOException { setLogContext(req); try { final CompiledScript script = getCompiledScript(); final ApplicationInstance inst = new SimpleInstance(req, script, this); ((LocalApplicationManager)_mgr).execute(inst); } catch (final ScriptException e) { LOG.error(Utils.buildScriptExceptionMessage(this, "compilation", e), e); throw e; } catch (final FileNotFoundException e) { LOG.error(this + " can not find the script: " + e.getMessage(), e); throw e; } catch (final IOException e) { LOG.error(this + " can not read the script: " + e.getMessage(), e); throw e; } catch (final Throwable e) { LOG.error(this + " has unknown errors: " + e.getMessage(), e); throw new RuntimeException(e); } } public synchronized CompiledScript getCompiledScript() throws ScriptException, IOException { if (_compiledScript == null) { try { _compiledScript = createScript(true); } catch (final ApplicationURL.UnmodifiedException e) { throw new RuntimeException(); // should never happen } } else { try { _compiledScript = createScript(false); } catch (final ApplicationURL.UnmodifiedException e) { // if (LOG.isDebugEnabled()) { // LOG.debug("Script is unchanged."); // } } } return _compiledScript; } protected CompiledScript createScript(final boolean force) throws ScriptException, IOException, ApplicationURL.UnmodifiedException { LocalApplicationManager mgr = (LocalApplicationManager)getManager(); final String source = getScriptContent(force); ScriptEngine engine = mgr.getScriptEngine(_type); CompiledScript compiledScript = null; if (engine instanceof Compilable) { compiledScript = ((Compilable) engine).compile(source); } else { compiledScript = new SimulatedCompiledScript(mgr, source, getType()); } mgr.putScriptEngine(_type, engine); return compiledScript; } public void dispose() { _compiledScript = null; } public Reader getScriptReader(final boolean force) throws IOException, ApplicationURL.UnmodifiedException { final Reader header = new InputStreamReader(Application.class.getClassLoader().getResourceAsStream( Configuration.get().getScriptHeader(getType()))); return new ChainedReader(header, new InputStreamReader(getURL().openStream(force))); } protected String getScriptContent(final boolean force) throws IOException, ApplicationURL.UnmodifiedException { final StringBuffer b = new StringBuffer(); final BufferedReader r = new BufferedReader(getScriptReader(force)); long lineNo = 0; try { String l = r.readLine(); boolean userCode = false; while (l != null) { ++lineNo; b.append(l.concat("\r\n")); if (userCode) { LOG.info(l.concat(CommentCharacterMap.get(_type)).concat(" line ").concat(String.valueOf(lineNo))); } if (!userCode && l.indexOf("end shim of") > -1) { userCode = true; } l = r.readLine(); } } finally { r.close(); } return b.toString(); } public String getBaseDir() { return _baseDir; } }