package com.hammurapi.web;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.ConcurrentHashMap;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.codehaus.commons.compiler.CompileException;
import org.codehaus.janino.ScriptEvaluator;

/**
 * Renders Java files. Java file shall contain code of void method which takes HttpServletRequest request, HttpServletResponse response, and 
 * JavaServlet servlet parameters.
 * I.e. file content == doGet/doPost method body with additional servlet parameter.
 */
public class JavaServlet extends HttpServlet {
	private static final long serialVersionUID = 2L;
	private ConcurrentHashMap<String, ScriptEvaluator> evaluators; 

	@Override
	public void init(ServletConfig config) throws ServletException {
		super.init(config);
		// Set cache-evaluators init parameter to false during development for live updates
		// and to true in deployed applications.
		if ("true".equals(config.getInitParameter("cache-evaluators"))) {
			evaluators = new ConcurrentHashMap<String, ScriptEvaluator>();
		}
	}
       
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {        
        String uri = request.getRequestURI();
        ScriptEvaluator se = null;
        if (evaluators!=null) {
        	se = evaluators.get(uri);
        }
        if (se==null) {
        	try {
	        	se = new ScriptEvaluator(
	        			uri,
	        			getServletContext().getResourceAsStream(uri), 
	        			void.class, 
	        			new String[] {"request", "response", "servlet"}, 
	        			new Class[] {HttpServletRequest.class, HttpServletResponse.class, JavaServlet.class},
	        			new Class[] {IOException.class, ServletException.class},
	        			getClass().getClassLoader());
	        	
	        	if (evaluators!=null) {
	        		evaluators.put(uri, se);
	        	}
        	} catch (CompileException e) {
        		throw new ServletException("Compilation of "+uri+" failed: "+e, e);
        	}
        }
        
        try {
        	se.evaluate(new Object[] {request, response, this});
        } catch (InvocationTargetException ite) {
        	Throwable cause = ite.getCause();
        	if (cause instanceof IOException) {
        		throw (IOException) cause;
        	}
        	if (cause instanceof ServletException) {
        		throw (ServletException) cause;
        	}
        	throw new ServletException("Evaluation of "+uri+" failed: "+(cause==null ? ite : cause), ite);
        }
    }

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doGet(request, response);
	}
		
}
