package com.github.bjuvensjo.rsimulator.http; import groovy.lang.Binding; import groovy.util.GroovyScriptEngine; import java.io.File; import java.io.IOException; import java.nio.file.Path; import java.util.HashMap; import java.util.Map; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import com.github.bjuvensjo.rsimulator.core.SimulatorResponse; import com.github.bjuvensjo.rsimulator.http.config.Constants; import com.github.bjuvensjo.rsimulator.http.config.GlobalConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author Anders Bälter */ public class ScriptFilter implements Filter { private static final String ROOT_PATH = "rootPath"; private static final String USE_ROOT_RELATIVE_PATH = "rootRelativePath"; private static final String REQUEST = "request"; private static final String RESPONSE = "response"; private static final String SIMULATOR_RESPONSE = "simulatorResponse"; private static final String GROOVY_PATTERN = com.github.bjuvensjo.rsimulator.core.config.Constants.REQUEST + ".*"; private Logger log = LoggerFactory.getLogger(ScriptFilter.class); @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { log.debug("doFilter"); if (shouldApplyFilter(request)) { log.debug("ApplyingScripts"); Map<String, Object> vars = new HashMap<String, Object>(); vars.put(REQUEST, request); vars.put(RESPONSE, response); vars.put(ROOT_PATH, GlobalConfig.rootPath); vars.put(USE_ROOT_RELATIVE_PATH, GlobalConfig.useRootRelativePath); applyScript(Scope.GLOBAL_REQUEST, vars); request.setAttribute(Constants.ROOT_PATH, vars.get(ROOT_PATH)); request.setAttribute(Constants.USE_ROOT_RELATIVE_PATH, vars.get(USE_ROOT_RELATIVE_PATH)); chain.doFilter(request, response); vars.put(SIMULATOR_RESPONSE, request.getAttribute(Constants.SIMULATOR_RESPONSE)); applyScript(Scope.LOCAL_RESPONSE, vars); applyScript(Scope.GLOBAL_RESPONSE, vars); } else { chain.doFilter(request, response); } } @Override public void destroy() { } private boolean shouldApplyFilter(ServletRequest request) { String theRootPath = request.getParameter(Constants.ROOT_PATH); String theUseRootRelativePath = request.getParameter(Constants.USE_ROOT_RELATIVE_PATH); return (theRootPath == null && theUseRootRelativePath == null); } private void applyScript(Scope type, Map<String, Object> vars) { try { String root = null; String script = null; switch (type) { case GLOBAL_REQUEST: root = GlobalConfig.rootPath; script = "GlobalServletRequest.groovy"; break; case GLOBAL_RESPONSE: root = GlobalConfig.rootPath; script = "GlobalServletResponse.groovy"; break; case LOCAL_RESPONSE: SimulatorResponse simulatorResponse = (SimulatorResponse) vars.get(SIMULATOR_RESPONSE); if (simulatorResponse != null && simulatorResponse.getMatchingRequest() != null) { Path matchingRequest = simulatorResponse.getMatchingRequest(); root = matchingRequest.getParent().toAbsolutePath().toString(); script = matchingRequest.getFileName().toString().replaceAll(GROOVY_PATTERN, "Servlet.groovy"); } break; default: break; } File file = new File(new StringBuilder().append(root).append(File.separator).append(script).toString()); if (file.exists()) { log.debug("Applying script {} of type: {}, with vars: {}", new Object[]{file, type, vars}); String[] roots = new String[]{root}; GroovyScriptEngine gse = new GroovyScriptEngine(roots); Binding binding = new Binding(); binding.setVariable("vars", vars); gse.run(script, binding); log.debug("Applied script {} of type: {}, and updated vars are: {}", new Object[]{file, type, vars}); } else { log.debug("When applying script of type {}, script path {} is not an existing file", type, root); } } catch (Exception e) { log.error("Script error.", e); } } private static enum Scope { GLOBAL_REQUEST, GLOBAL_RESPONSE, LOCAL_RESPONSE } }