package org.autoplot.servlet; import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintStream; import java.io.PrintWriter; import java.lang.reflect.Array; import java.net.UnknownHostException; import java.nio.file.Paths; import java.util.Date; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import java.util.Map.Entry; import java.util.logging.FileHandler; import java.util.logging.Formatter; import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.LogRecord; import java.util.logging.Logger; import javax.imageio.ImageIO; 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.autoplot.ApplicationModel; import org.autoplot.JythonUtil; import org.autoplot.ScriptContext; import static org.autoplot.ScriptContext.waitUntilIdle; import org.autoplot.datasource.DataSetURI; import org.autoplot.datasource.DataSourceUtil; import org.autoplot.datasource.URISplit; import org.autoplot.dom.Application; import org.autoplot.jythonsupport.JythonRefactory; import org.autoplot.jythonsupport.Param; import org.autoplot.scriptconsole.DumpRteExceptionHandler; import org.autoplot.scriptconsole.LoggingOutputStream; import org.das2.datum.Datum; import org.das2.datum.TimeParser; import org.das2.datum.TimeUtil; import org.das2.datum.Units; import org.das2.graph.DasCanvas; import org.das2.util.DasPNGConstants; import org.das2.util.DasPNGEncoder; import org.das2.util.FileUtil; import org.das2.util.awt.GraphicsOutput; import org.das2.util.monitor.NullProgressMonitor; import org.python.core.PySystemState; import org.python.util.PythonInterpreter; /** * Run a script on the server side, and produce a client-side GUI for the * getParam calls. * Note this has logging installed which is set up in code, which is bad practice. This should be * removed should this be used in production! * @author jbf */ public class ScriptGUIServlet extends HttpServlet { static final Logger logger= Logger.getLogger("autoplot.servlet.scriptgui"); static final Logger timelogger; /** * milliseconds within which script must run */ private static final int TIMEOUT_SCRIPT = 50000; static { timelogger= Logger.getLogger("autoplot.servlet.script.gui.timing"); timelogger.setLevel(Level.FINE); try { // %h is user.home String home= System.getProperty("user.home"); //TODO: verify this new code which makes the log directory File hf= Paths.get( home, "log", "tomcat" ).toFile(); if ( !hf.exists() ) { if ( !hf.mkdirs() ) { throw new RuntimeException("Unable to make log directory: "+hf); } } final Handler h= new FileHandler( "%h/log/tomcat/scriptGuiTiming.%g.log" ) { @Override public synchronized void publish(LogRecord record) { super.publish(record); flush(); } }; Formatter f= new Formatter() { @Override public String format(LogRecord record) { String msg= formatMessage(record); return Units.t1970.createDatum(record.getMillis()).toString() + ":" + msg + "\n"; } }; h.setFormatter( f ); timelogger.addHandler(h); } catch (IOException | SecurityException ex) { Logger.getLogger(ScriptGUIServlet.class.getName()).log(Level.SEVERE, null, ex); } } File logfile= new File( "/home/jbf/log/ScriptGUIServlet.log" ); @Override public void init(ServletConfig config) throws ServletException { System.setProperty("java.awt.headless", "true"); super.init(config); } /** * write out the current canvas to stdout. This is introduced to support servers. * TODO: this has issues with the size. See writeToPng(filename). * @param dom * @param out the OutputStream accepting the data, which is not closed. * @throws java.io.IOException */ private static void writeToPng( Application dom, String suri, BufferedImage orig, OutputStream out) throws IOException { waitUntilIdle(); DasCanvas c = dom.getController().getApplicationModel().getCanvas(); int width= dom.getCanvases(0).getWidth(); int height= dom.getCanvases(0).getHeight(); BufferedImage image = c.getImage(width,height); if ( image.equals(orig) ) { BufferedImage im= new BufferedImage( 320, 200, BufferedImage.TYPE_INT_ARGB ); Graphics g= im.getGraphics(); g.setColor( Color.WHITE ); g.fillRect( 0, 0, width, height ); g.setColor( Color.GRAY ); g.drawRect( 0, 0, width-1, height-1 ); g.drawString( "(canvas not used)", 10, 100 ); image= im; } DasPNGEncoder encoder = new DasPNGEncoder(); encoder.addText(DasPNGConstants.KEYWORD_CREATION_TIME, new Date().toString()); encoder.addText(DasPNGConstants.KEYWORD_SOFTWARE, "Autoplot" ); encoder.addText(DasPNGConstants.KEYWORD_PLOT_INFO, c.getImageMetadata() ); encoder.addText("ScriptURI",suri); encoder.write( image, out); } /** * Processes requests for both HTTP GET and POST * methods. * * @param request servlet request * @param response servlet response * @throws ServletException if a servlet-specific error occurs * @throws IOException if an I/O error occurs */ protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String script= request.getParameter("script"); if ( script==null ) { response.sendRedirect( "ScriptGUIServletPick" ); return; } if ( !ServletUtil.isWhitelisted(script) ) { throw new IllegalArgumentException("script must come from whitelisted host, contact " +ServletUtil.getServletContact() + " to see if script could be run: "+script ); } String mode; if ( request.getParameter("img")!=null ) { mode= "img"; } else if ( "Print SVG".equals(request.getParameter("printsvg")) ) { mode= "svg"; } else if ( "Print PDF".equals( request.getParameter("printpdf")) ) { mode= "pdf"; } else if ( request.getParameter("text")!=null ) { mode= "text"; } else { mode= "init"; } long t0= System.currentTimeMillis(); String key= request.getParameter("key"); if ( key==null ) key=""; logger.log( Level.INFO, "enter ScriptGUIServlet: {0} {1}", new Object[] { mode, key } ); Map params= request.getParameterMap(); Map ssparams= new LinkedHashMap<>(); StringBuilder sbparams= new StringBuilder(); for ( Object o: params.entrySet() ) { Entry e= (Entry)o; String value= Array.get(e.getValue(),0).toString(); ssparams.put( e.getKey().toString(), value ); sbparams.append("&").append(e.getKey().toString()).append("=").append(value); } String sparams= sbparams.toString(); String scriptURI= script; URISplit split= URISplit.parse(script); String pwd= split.path; String name= split.file.substring(split.path.length()); File scriptFile= DataSetURI.getFile( script, new NullProgressMonitor() ); script= FileUtil.readFileToString(scriptFile); if ( request.getParameter("img")!=null ) { if ( !( getKeyFile( key,".png.t" ).exists() || getKeyFile( key,".png" ).exists() ) ) { throw new IOException( "invalid key: "+key ); } writeOutputImage( key, response ); } else if ( "Print SVG".equals( request.getParameter("printsvg") ) ) { String[] ss= new String[ssparams.size()]; int i=0; for ( Entry e: ssparams.entrySet() ) { ss[i] = e.getKey() + "=" + e.getValue(); i++; } printScript( response, key, scriptURI, script, name, ss, pwd, "svg" ); } else if ( "Print PDF".equals( request.getParameter("printpdf") ) ) { String[] ss= new String[ssparams.size()]; int i=0; for ( Entry e: ssparams.entrySet() ) { ss[i] = e.getKey() + "=" + e.getValue(); i++; } printScript( response, key, scriptURI, script, name, ss, pwd, "pdf" ); } else if ( request.getParameter("text")!=null ) { if ( !( getKeyFile( key,".txt.t" ).exists() || getKeyFile( key,".txt" ).exists() ) ) { throw new IOException( "invalid key: "+key ); } writeOutputText( key, response ); } else { // key= String.format( "%06d", (int)( Math.random() * 100000 ) ); key = String.format( "%010d", Math.abs(sparams.hashCode()) ); writeParametersForm(key, response, pwd, script, ssparams, name, scriptURI, sparams); String[] ss= new String[ssparams.size()]; int i=0; for ( Entry e: ssparams.entrySet() ) { ss[i] = e.getKey() + "=" + e.getValue(); i++; } boolean runScript= true; File existingImageFile = getKeyFile( key, ".png" ); if ( existingImageFile.exists() ) { long ageMillis= t0 - existingImageFile.lastModified(); if ( ageMillis<3600000 ) { runScript= false; } } if ( runScript ) { existingImageFile = getKeyFile( key, ".png.t" ); if ( existingImageFile.exists() ) { long ageMillis= t0 - existingImageFile.lastModified(); if ( ageMillis<3600000 ) { runScript= false; } } } if ( runScript ) { // create empty new files for placeholders. File textKeyFile= getKeyFile( key, ".txt.t" ); if ( textKeyFile.exists() ) { if ( !textKeyFile.delete() ) { throw new IllegalArgumentException("unable to delete temporary key file. Please refresh to try again."); } } if ( !textKeyFile.createNewFile() ) throw new IllegalArgumentException("unable to create file: "+textKeyFile); File imageKeyFile = getKeyFile( key, ".png.t" ); if ( imageKeyFile.exists() ) { if ( !imageKeyFile.delete() ) { throw new IllegalArgumentException("unable to delete temporary image file. Please refresh to try again."); } } if ( !imageKeyFile.createNewFile() ) throw new IllegalArgumentException("unable to create file: "+imageKeyFile); startScript( request, key, scriptURI, script, name, ss, pwd ); } } logger.log( Level.INFO, "exit ScriptGUIServlet: {0} {1} {2}", new Object[] { mode, key, String.format("%.2f", (System.currentTimeMillis()-t0)/1000. ) } ); } /** * park this thread and wait for the image to be output by the other thread. * @param key * @param response * @throws IOException * @throws UnknownHostException */ private void writeOutputImage( String key, HttpServletResponse response ) throws IOException, UnknownHostException { File keyFile= getKeyFile( key,".png" ); long t0= System.currentTimeMillis(); while ( !keyFile.exists() ) { if ( ( System.currentTimeMillis()-t0 )> TIMEOUT_SCRIPT ) { throw new IOException( String.format( "timeout, process takes longer than %d seconds", TIMEOUT_SCRIPT/1000 ) ); } Thread.yield(); } // To support load balancing, insert the actual host that resolved the request response.setHeader( "X-Served-By", java.net.InetAddress.getLocalHost().getCanonicalHostName() ); response.setHeader( "X-ScriptGUIServlet-Key", key ); try ( InputStream ins= new FileInputStream(keyFile); OutputStream out = response.getOutputStream() ) { byte[] buf= new byte[48000]; int i; while ( (i=ins.read(buf))>-1 ) { out.write( buf, 0, i ); } } } /** * park this thread and wait for the text to be output by the other thread. * @param key * @param response * @throws IOException * @throws UnknownHostException */ private void writeOutputText( String key, HttpServletResponse response ) throws IOException, UnknownHostException { File keyFile= getKeyFile( key,".txt" ); long t0= System.currentTimeMillis(); while ( !keyFile.exists() ) { if ( ( System.currentTimeMillis()-t0 )> TIMEOUT_SCRIPT ) { throw new IOException( String.format( "timeout, process takes longer than %d seconds", TIMEOUT_SCRIPT/1000 ) ); } Thread.yield(); } response.setHeader( "X-Served-By", java.net.InetAddress.getLocalHost().getCanonicalHostName() ); response.setHeader( "X-ScriptGUIServlet-Key", key ); try ( InputStream ins= new FileInputStream(keyFile); OutputStream out = response.getOutputStream() ) { byte[] buf= new byte[48000]; int i; while ( (i=ins.read(buf))>-1 ) { out.write( buf, 0, i ); } } } /** * copy of JythonUtil.runScript allows the stdout to be gathered. * @param dom * @param in * @param out * @param name * @param argv * @param pwd * @throws IOException */ private void runScript( Application dom, InputStream in, OutputStream out, String name, String[] argv, String pwd ) throws IOException { if ( argv==null ) argv= new String[] {}; String[] pyInitArgv= new String[ argv.length+1 ]; pyInitArgv[0]= name; System.arraycopy(argv, 0, pyInitArgv, 1, argv.length); PySystemState.initialize( PySystemState.getBaseProperties(), null, pyInitArgv ); // legacy support sys.argv. now we use getParam PythonInterpreter interp = JythonUtil.createInterpreter(true, false, dom, new NullProgressMonitor() ); if ( pwd!=null ) { pwd= URISplit.format( URISplit.parse(pwd) ); // sanity check against injections interp.exec("PWD='"+pwd+"'");// JythonRefactory okay } interp.exec("import autoplot2017 as autoplot");// JythonRefactory okay interp.setOut(out); int iargv=1; // skip the zeroth one, it is the name of the script for (String s : argv ) { int ieq= s.indexOf('='); if ( ieq>0 ) { String snam= s.substring(0,ieq).trim(); if ( DataSourceUtil.isJavaIdentifier(snam) ) { String sval= s.substring(ieq+1).trim(); // if ( snam.equals("resourceURI") ) { // check to see if pwd can be inserted // URISplit split= URISplit.parse(sval); // if ( split.path==null ) { // sval= pwd + sval; // } // } interp.exec("autoplot.params['" + snam + "']='" + sval+"'");// JythonRefactory okay } else { if ( snam.startsWith("-") ) { System.err.println("\n!!! Script arguments should not start with -, they should be name=value"); } System.err.println("bad parameter: "+ snam); } } else { interp.exec("autoplot.params['arg_" + iargv + "']='" + s +"'" );// JythonRefactory okay iargv++; } } if ( name==null ) { interp.execfile(JythonRefactory.fixImports(in)); } else { interp.execfile(JythonRefactory.fixImports(in,name),name); } } private File getKeyFile( String key, String ext ) { File keyhome= new File( ServletUtil.getServletHome().getAbsolutePath(), "key" ); if ( !keyhome.exists() ) { if ( !keyhome.mkdirs() ) { throw new IllegalArgumentException("Unable to make key file folder"); } } return new File( keyhome, key+ ext ); } private void printScript( HttpServletResponse response, String key, String scriptURI, String script, String name, String[] aaparams, String pwd, String format ) throws IOException { try { File scriptLogArea= new File( ServletUtil.getServletHome(), "log" ); if ( !scriptLogArea.exists() ) { if ( !scriptLogArea.mkdirs() ) { logger.warning("unable to make log area"); } } File scriptLogFile= new File( scriptLogArea, "ScriptGUIServlet.log" ); Datum n= TimeUtil.now(); TimeParser tp= TimeParser.create( TimeParser.TIMEFORMAT_Z ); String s= tp.format( n ) + "\t" + key + "\t" + scriptURI ; try ( PrintWriter w= new PrintWriter( new FileWriter( scriptLogFile, scriptLogFile.exists() ) ) ) { w.println(s); } if ( !"true".equals(System.getProperty("java.awt.headless")) ) { throw new IllegalArgumentException("java.awt.headless must be set to true"); } org.autoplot.jythonsupport.JythonUtil.ScriptDescriptor sd0= org.autoplot.jythonsupport.JythonUtil.describeScript( null, script, null ); aaparams= interpretAsParams( sd0, aaparams ); logger.fine("add fonts, which must be done with headless mode"); //System.getProperty("java.awt.headless"); org.autoplot.Util.addFonts(); // PROBLEMS ApplicationModel model = new ApplicationModel(); model.setExceptionHandler( new DumpRteExceptionHandler() ); model.addDasPeersToAppAndWait(); Application dom= model.getDom(); logger.log(Level.FINE, "dom: {0}", dom); logger.log(Level.FINE, "dom options: {0}", dom.getOptions()); dom.getOptions().setAutolayout(false); PythonInterpreter interp = JythonUtil.createInterpreter( true, true ); interp.set("java",null); interp.set("org",null); interp.set("getFile",null); interp.set("dom",dom); interp.set("downloadResourceAsTempFile",null); LoggingOutputStream los1= new LoggingOutputStream( Logger.getLogger("autoplot.servlet.scriptservlet"), Level.INFO ); interp.setOut( los1 ); script= JythonRefactory.fixImports(script); ScriptContext.setApplicationModel(model); // why must I do this??? script= "def showMessageDialog(msg): \n pass\n" + script; long t0= System.currentTimeMillis(); timelogger.log(Level.FINE, "begin runScript {0}", name); File consoleKeyFile= getKeyFile( key, ".txt.t" ); try ( OutputStream baos= new FileOutputStream( consoleKeyFile, true ) ) { runScript( dom, new ByteArrayInputStream(script.getBytes("UTF-8")), baos, name, aaparams, pwd ); } catch ( Exception ex ) { try ( PrintWriter write= new PrintWriter( new FileWriter( consoleKeyFile, true ) ) ) { ex.printStackTrace(write); } } long elapsedTime= System.currentTimeMillis()-t0; timelogger.log(Level.FINE, "end printScript {0} ({1}ms)", new Object[]{name, elapsedTime }); waitUntilIdle(); if ( format.equals("svg") ) { Class goClass = Class.forName("org.das2.util.awt.SvgGraphicsOutput"); GraphicsOutput go = (GraphicsOutput) goClass.newInstance(); DasCanvas c = dom.getController().getApplicationModel().getCanvas(); c.writeToGraphicsOutput( response.getOutputStream(), go ); } else { Class goClass = Class.forName( "org.das2.util.awt.PdfGraphicsOutput" ); GraphicsOutput go = (GraphicsOutput) goClass.newInstance(); DasCanvas c = dom.getController().getApplicationModel().getCanvas(); c.writeToGraphicsOutput( response.getOutputStream(), go ); } } catch (InstantiationException ex) { Logger.getLogger(ScriptGUIServlet.class.getName()).log(Level.SEVERE, null, ex); } catch (IllegalAccessException ex) { Logger.getLogger(ScriptGUIServlet.class.getName()).log(Level.SEVERE, null, ex); } catch (ClassNotFoundException ex) { Logger.getLogger(ScriptGUIServlet.class.getName()).log(Level.SEVERE, null, ex); } } private synchronized void startScript( HttpServletRequest request, String key, String scriptURI, String script, String name, String[] aaparams, String pwd) throws IOException { File scriptLogArea= new File( ServletUtil.getServletHome(), "log" ); if ( !scriptLogArea.exists() ) { if ( !scriptLogArea.mkdirs() ) { logger.warning("unable to make log area"); } } File scriptLogFile= new File( scriptLogArea, "ScriptGUIServlet.log" ); Datum n= TimeUtil.now(); TimeParser tp= TimeParser.create( TimeParser.TIMEFORMAT_Z ); String s= tp.format( n ) + "\t" + key + "\t" + scriptURI ; try ( PrintWriter w= new PrintWriter( new FileWriter( scriptLogFile, scriptLogFile.exists() ) ) ) { w.println(s); } if ( !"true".equals(System.getProperty("java.awt.headless")) ) { throw new IllegalArgumentException("java.awt.headless must be set to true"); } logger.fine("add fonts, which must be done with headless mode"); //System.getProperty("java.awt.headless"); org.autoplot.Util.addFonts(); // PROBLEMS ApplicationModel model = new ApplicationModel(); model.setExceptionHandler( new DumpRteExceptionHandler() ); model.addDasPeersToAppAndWait(); Application dom= model.getDom(); logger.log(Level.FINE, "dom: {0}", dom); logger.log(Level.FINE, "dom options: {0}", dom.getOptions()); dom.getOptions().setAutolayout(false); //PythonInterpreter interp = JythonUtil.createInterpreter( true, true ); //interp.set("java",null); //interp.set("org",null); //interp.set("getFile",null); //interp.set("dom",dom); //interp.set("downloadResourceAsTempFile",null); //LoggingOutputStream los1= new LoggingOutputStream( Logger.getLogger("autoplot.servlet.scriptservlet"), Level.INFO ); //interp.setOut( los1 ); script= JythonRefactory.fixImports(script); ScriptContext.setApplicationModel(model); // why must I do this??? script= "def showMessageDialog(msg): \n pass\n" + script; long t0= System.currentTimeMillis(); timelogger.log(Level.FINE, "begin runScript {0}", name); File consoleKeyFile= getKeyFile( key, ".txt.t" ); DasCanvas c = dom.getController().getApplicationModel().getCanvas(); int width= dom.getCanvases(0).getWidth(); int height= dom.getCanvases(0).getHeight(); BufferedImage baseImage = c.getImage(width,height); boolean success= false; try ( OutputStream baos= new FileOutputStream( consoleKeyFile, true ) ) { baos.write( ("running script..."+name+"\n").getBytes() ); runScript( dom, new ByteArrayInputStream(script.getBytes("UTF-8")), baos, name, aaparams, pwd ); success= true; } catch ( Exception ex ) { try ( PrintWriter write= new PrintWriter( new FileWriter( consoleKeyFile, true ) ) ) { ex.printStackTrace(write); } } if ( success ) { File imageKeyFile = getKeyFile( key, ".png.t" ); try ( FileOutputStream out= new FileOutputStream( imageKeyFile, true ) ) { Map params= new LinkedHashMap<>(); for ( int i=0; i-1 ) params.put( p.substring(0,ieq), p.substring(ieq+1) ); } String suri= URISplit.format( "script", scriptURI, params ); writeToPng(dom, suri, baseImage, out ); } if ( !imageKeyFile.renameTo( getKeyFile( key, ".png" ) ) ) { throw new IllegalArgumentException("unable to rename file (.png)"); } if ( !consoleKeyFile.renameTo( getKeyFile( key, ".txt" ) ) ) { throw new IllegalArgumentException("unable to rename file (.txt)"); } } else { // clean up after ourselves... File imageKeyFile = getKeyFile( key, ".png.t" ); BufferedImage im= new BufferedImage( 400, 400, BufferedImage.TYPE_INT_ARGB ); Graphics2D g= (Graphics2D) im.getGraphics(); g.setColor( Color.LIGHT_GRAY ); g.fillRoundRect( 50,50,300,300,16,16 ); g.dispose(); ImageIO.write( im, "png", getKeyFile( key, ".png" ) ); boolean throwException=false; if ( ! imageKeyFile.delete() ) { throwException= true; } if ( !consoleKeyFile.renameTo( getKeyFile( key, ".txt" ) ) ) { throw new IllegalArgumentException("unable to rename file (.txt)"); } if ( throwException ) { throw new IOException("unable to delete png or console output, someone will have to deal with this..."); } } long elapsedTime= System.currentTimeMillis()-t0; File keyLogFile= getKeyFile( key, ".stats" ); try ( PrintStream outs= new PrintStream( new FileOutputStream( keyLogFile ) ) ) { outs.println( "ExecutionTimeMs: "+ elapsedTime ); outs.println( "Script: "+ scriptURI + "?"+ String.join("&", aaparams) ); outs.println( "ClientId: "+ SecurityUtil.clientId(request) ); outs.println( "UserAgent: " + request.getHeader("User-Agent") ); } timelogger.log(Level.FINE, "end runScript {0} ({1}ms)", new Object[]{name, elapsedTime }); } private static boolean isBoolean( Param p ) { if ( p.enums==null || p.enums.size()!=2 ) return false; if ( p.type=='A' && p.enums.size()==2 && p.enums.contains("T") && p.enums.contains("F") ) return true; if ( p.type=='F' && p.enums.size()==2 && p.enums.contains(0) && p.enums.contains(1) ) return true; return false; } /** * go through and convert "on" to "1", etc. Note doubles will still be Strings, URIs will still be Strings, etc. * ssparams will be modified and a copy is returned. * @param sd0 * @param ssparams * @return the map is returned as a string-object version for convenience. */ private static Map interpretAsParams( org.autoplot.jythonsupport.JythonUtil.ScriptDescriptor sd0, Map ssparams ) { Map result= new LinkedHashMap<>(); // go through and convert "on" to 1, etc. for ( Param p: sd0.getParams() ) { String svalue= ssparams.get(p.name); if ( isBoolean(p) ) { if ( svalue!=null ) { if ( svalue.equals("on") ) { if ( p.type=='F' ) { result.put( p.name, "1" ); ssparams.put( p.name, "1" ); } else { result.put( p.name, "T" ); ssparams.put( p.name, "T" ); } } else { if ( p.type=='F' ) { result.put( p.name, "0" ); ssparams.put( p.name, "0" ); } else { result.put( p.name, "F" ); ssparams.put( p.name, "F" ); } } } } else { result.put( p.name, svalue ); } } return result; } /** * go through and convert "on" to "1", etc. Note doubles will still be Strings, URIs will still be Strings, etc. * ssparams will be modified and a copy is returned. * @param sd0 * @param ssparams * @return the map is returned as a string-object version for convenience. */ private static String[] interpretAsParams( org.autoplot.jythonsupport.JythonUtil.ScriptDescriptor sd0, String[] ssparams ) { for ( int i=0; i ssparams, String name, String scriptURI, String sparams) throws IOException { response.setContentType("text/html;charset=UTF-8"); Map env= new HashMap<>(); env.put( "PWD", pwd ); long t0= System.currentTimeMillis(); timelogger.log(Level.FINE, "begin describeScript {0}", name); org.autoplot.jythonsupport.JythonUtil.ScriptDescriptor sd0= org.autoplot.jythonsupport.JythonUtil.describeScript( env, script, null ); Map params= interpretAsParams( sd0, ssparams ); org.autoplot.jythonsupport.JythonUtil.ScriptDescriptor sd= org.autoplot.jythonsupport.JythonUtil.describeScript( env, script, ssparams ); timelogger.log(Level.FINE, "end describeScript {0} ({1}ms)", new Object[]{name, System.currentTimeMillis()-t0}); String uri= URISplit.format( "vap+jy", scriptURI, params ); try (PrintWriter out = response.getWriter()) { out.println(""); out.println(""); out.println(""); out.println(""+name+""); out.println(""); out.println(""); out.println(""); if ( sd.getTitle().length()>0 ) { out.println("

"+sd.getTitle()+"

"); if ( sd.getDescription().length()>0 ) { out.println("

"+sd.getDescription() +"

"); } } else { out.println("

"+pwd + name+"

"); if ( sd.getDescription().length()>0 ) { out.println("

"+sd.getDescription() +"

"); } } out.println(""); out.println("\n"); out.println( "\n"); out.println( "\n"); out.println( "
"); out.println("
"); for ( Param p: sd.getParams() ) { p.doc= p.doc.trim(); Object currentValue= p.value == null ? p.deft : p.value; String andDoc= p.doc.length()>0 ? ( ", "+ p.doc +"" ) : ""; boolean isCheckBox= isBoolean(p); if ( !isCheckBox ) { out.println(""+p.name + andDoc +"
"); } else { out.println(""); } out.println("

"); } if ( sd.getParams().isEmpty() ) { out.println("script has no parameters."); out.println("

"); } out.println("\n"); out.println("\n"); out.println("
\n"); out.println("\n"); out.println("\n"); out.println("
\n"); out.println( "
\n"); out.println( "
\n"); out.println("image\n" ); out.println( "
\n"); out.println("
\n"); out.println("Console Output:
\n"); out.println("\n" ); out.println( "
\n" ); out.println("Running script "+scriptURI+""); out.println("Pick another...\n"); out.println("
key="+key+" "+uri+" "); out.println(""); out.println(""); out.close(); } } // /** * Handles the HTTP GET method. * * @param request servlet request * @param response servlet response * @throws ServletException if a servlet-specific error occurs * @throws IOException if an I/O error occurs */ @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } /** * Handles the HTTP POST method. * * @param request servlet request * @param response servlet response * @throws ServletException if a servlet-specific error occurs * @throws IOException if an I/O error occurs */ @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } /** * Returns a short description of the servlet. * * @return a String containing servlet description */ @Override public String getServletInfo() { return "Short description"; }// }