package bsh.servlet; import java.io.*; import javax.servlet.*; import javax.servlet.http.*; import bsh.*; /** This file is part of BeanShell - www.beanshell.org @author Pat Niemeyer */ public class BshServlet extends HttpServlet { static String bshVersion; static String exampleScript = "print(\"hello!\");"; static String getBshVersion() { if ( bshVersion != null ) return bshVersion; /* We have included a getVersion() command to detect the version of bsh. If bsh is packaged in the WAR file it could access it directly as a bsh command. But if bsh is in the app server's classpath it won't see it here, so we will source it directly. This command works around the lack of a coherent version number in the early versions. */ Interpreter bsh = new Interpreter(); try { bsh.eval( new InputStreamReader( BshServlet.class.getResource( "getVersion.bsh").openStream() ) ); bshVersion = (String)bsh.eval( "getVersion()" ); } catch ( Exception e ) { bshVersion = "BeanShell: unknown version"; } return bshVersion; } public void doGet( HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String script = request.getParameter("bsh.script"); String client = request.getParameter("bsh.client"); String output = request.getParameter("bsh.servlet.output"); String captureOutErr = request.getParameter("bsh.servlet.captureOutErr"); boolean capture = false; if ( captureOutErr != null && captureOutErr.equalsIgnoreCase("true") ) capture = true; Object scriptResult = null; Exception scriptError = null; StringBuffer scriptOutput = new StringBuffer(); if ( script != null ) { try { scriptResult = evalScript( script, scriptOutput, capture, request, response ); } catch ( Exception e ) { scriptError = e; } } response.setHeader( "Bsh-Return", String.valueOf(scriptResult) ); if ( (output != null && output.equalsIgnoreCase("raw")) || ( client != null && client.equals("Remote") ) ) sendRaw( request, response, scriptError, scriptResult, scriptOutput ); else sendHTML( request, response, script, scriptError, scriptResult, scriptOutput, capture ); } void sendHTML( HttpServletRequest request, HttpServletResponse response, String script, Exception scriptError, Object scriptResult, StringBuffer scriptOutput, boolean capture ) throws IOException { // Format the output using a simple templating utility SimpleTemplate st = new SimpleTemplate( BshServlet.class.getResource("page.template") ); st.replace( "version", getBshVersion() ); //String requestURI = HttpUtils.getRequestURL( request ).toString() // I was told this should work String requestURI = request.getRequestURI(); st.replace( "servletURL", requestURI ); if ( script != null ) st.replace( "script", script ); else st.replace( "script", exampleScript ); if ( capture ) st.replace( "captureOutErr", "CHECKED" ); else st.replace( "captureOutErr", "" ); if ( script != null ) st.replace( "scriptResult", formatScriptResultHTML( script, scriptResult, scriptError, scriptOutput ) ); response.setContentType("text/html"); PrintWriter out = response.getWriter(); st.write(out); out.flush(); } void sendRaw( HttpServletRequest request, HttpServletResponse response, Exception scriptError, Object scriptResult, StringBuffer scriptOutput ) throws IOException { response.setContentType("text/plain"); PrintWriter out = response.getWriter(); if ( scriptError != null ) out.println( "Script Error:\n"+scriptError ); else out.println( scriptOutput.toString() ); out.flush(); } /** */ String formatScriptResultHTML( String script, Object result, Exception error, StringBuffer scriptOutput ) throws IOException { SimpleTemplate tmplt; if ( error != null ) { tmplt = new SimpleTemplate( getClass().getResource("error.template") ); String errString; if ( error instanceof bsh.EvalError ) { int lineNo = ((EvalError)error).getErrorLineNumber(); String msg = error.getMessage(); int contextLines = 4; errString = escape(msg); if ( lineNo > -1 ) errString += "<hr>" + showScriptContextHTML( script, lineNo, contextLines ); } else errString = escape( error.toString() ); tmplt.replace("error", errString ); } else { tmplt = new SimpleTemplate( getClass().getResource("result.template") ); tmplt.replace( "value", escape(String.valueOf(result)) ); tmplt.replace( "output", escape(scriptOutput.toString()) ); } return tmplt.toString(); } /* Show context number lines of string before and after target line. Add HTML formatting to bold the target line. */ String showScriptContextHTML( String s, int lineNo, int context ) { StringBuffer sb = new StringBuffer(); BufferedReader br = new BufferedReader( new StringReader(s) ); int beginLine = Math.max( 1, lineNo-context ); int endLine = lineNo + context; for( int i=1; i<=lineNo+context+1; i++ ) { if ( i < beginLine ) { try { br.readLine(); } catch ( IOException e ) { throw new RuntimeException( e.toString() ); } continue; } if ( i > endLine ) break; String line; try { line = br.readLine(); } catch ( IOException e ) { throw new RuntimeException( e.toString() ); } if ( line == null ) break; if ( i == lineNo ) sb.append( "<font color=\"red\">"+i+": "+line +"</font><br/>" ); else sb.append( i+": " +line +"<br/>" ); } return sb.toString(); } public void doPost( HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet( request, response ); } Object evalScript( String script, StringBuffer scriptOutput, boolean captureOutErr, HttpServletRequest request, HttpServletResponse response ) throws EvalError { // Create a PrintStream to capture output ByteArrayOutputStream baos = new ByteArrayOutputStream(); PrintStream pout = new PrintStream( baos ); // Create an interpreter instance with a null inputstream, // the capture out/err stream, non-interactive Interpreter bsh = new Interpreter( null, pout, pout, false ); // set up interpreter bsh.set( "bsh.httpServletRequest", request ); bsh.set( "bsh.httpServletResponse", response ); // Eval the text, gathering the return value or any error. Object result = null; String error = null; PrintStream sout = System.out; PrintStream serr = System.err; if ( captureOutErr ) { System.setOut( pout ); System.setErr( pout ); } try { // Eval the user text result = bsh.eval( script ); } finally { if ( captureOutErr ) { System.setOut( sout ); System.setErr( serr ); } } pout.flush(); scriptOutput.append( baos.toString() ); return result; } /** * Convert special characters to entities for XML output */ public static String escape(String value) { String search = "&<>"; String[] replace = {"&", "<", ">"}; StringBuffer buf = new StringBuffer(); for (int i = 0; i < value.length(); i++) { char c = value.charAt(i); int pos = search.indexOf(c); if (pos < 0) buf.append(c); else buf.append(replace[pos]); } return buf.toString(); } }