// Proglet.java -- Lars Appel 11.mar.00 / 14.mar.00 import javax.servlet.*; import javax.servlet.http.*; import java.io.*; import java.util.*; /* This servlet acts as a gateway to an MPE program similar to CGI but with parameter passing much more appropriate for MPE programmers. The MPE program prompts the servlet for a number of request parameters, returns a complete HTML page and then waits for another request. By using the "implements SingleThreadModel" flag, we cause the servlet engine to perform automatic pool management for us! This is a quick & dirty prototype. It should be improved in its error handling and also be "generalized" by moving hardcoded logon and program information into a properties file (or servlet initArgs). */ public class Proglet extends HttpServlet implements SingleThreadModel { private static final boolean DEBUG = false; // some instance vars are setup from a props file String targetHost; String logonPrompt; String logonCommand; String runPrompt; String runCommand; String byePrompt; String byeCommand; HostIO host; public void init( ServletConfig config ) throws ServletException { super.init( config ); host = null; try { Properties props = new Properties(); props.load( new FileInputStream( getInitParameter("propsFile") ) ); targetHost = props.getProperty( "targetHost", "localhost" ); logonPrompt = props.getProperty( "logonPrompt", "MPE/iX:" ); logonCommand = props.getProperty( "logonCommand" ); // what if missing or bad logon command ?? runPrompt = props.getProperty( "runPrompt", ":" ); runCommand = props.getProperty( "runCommand" ); // what if missing or bad run command ?? byePrompt = props.getProperty( "byePrompt", ":" ); byeCommand = props.getProperty( "byeCommand", "bye" ); } catch (IOException e) { System.out.println( "Proglet init failed: " + e ); throw new UnavailableException( this, e.toString() ); } } public void doGet( HttpServletRequest req, HttpServletResponse res ) throws IOException { doBoth( "GET", req, res ); } public void doPost( HttpServletRequest req, HttpServletResponse res ) throws IOException { doBoth( "POST", req, res ); } private void doBoth( String method, HttpServletRequest req, HttpServletResponse res ) throws IOException { res.setContentType( "text/html" ); PrintWriter toClient = res.getWriter(); if (req.getPathInfo() == null) { toClient.println( "

OK

" ); // the NOP shortcut for /bin/touch } else { if (host == null) { if (DEBUG) System.out.println( "connecting proglet host" ); host = new HostIO(); host.open( targetHost ); // what if host does not respond ?? host.answerTo( logonPrompt, logonCommand ); // what if logon is incorrect ?? host.answerTo( runPrompt, runCommand ); // what if program fails to run ?? } if (DEBUG) System.out.println( "starting proglet dialog" ); host.answerTo( "HTTP> ", method ); host.skipLines(1); // the echo while ( ! host.readln().equals("") ) { String prompt = host.getLine(); if (prompt.equals( "PATHINFO> " )) { host.writeln( req.getPathInfo() ); host.skipLines(1); // the echo } else if (prompt.equals( "QUERYSTRING> " )) { host.writeln( req.getQueryString() ); host.skipLines(1); // the echo } else if (prompt.endsWith( "> " )) { String substr = prompt.substring( 0, prompt.length()-2); String htparm = req.getParameter(substr); host.writeln( (htparm != null) ? htparm : "" ); host.skipLines(1); // the echo } } toClient.println( host.getLine() ); while ( ! host.readln().equals("") ) { toClient.println( host.getLine() ); } toClient.println( host.getLine() ); if (DEBUG) System.out.println( "finished proglet dialog" ); } toClient.close(); } public void destroy() { if (host != null) try { host.answerTo( "HTTP> ", "EXIT" ); host.answerTo( byePrompt, byeCommand ); host.skipUntilStartsWith( "CPU=" ); host.close(); host = null; } catch (IOException e) { System.out.println( "Proglet destroy failed: " + e ); } } } /* Change History: 12.mar.00 (LA) The special PathInfo "/exit" is no longer used for the restart feature because it only affects one instance of the Servlet. The new approach is to /bin/touch the .class file and thus trigger the servlet engine's destroy-reload-init cycle, which will affect all instances of the servlet (oops... most probably also those different flavours run by different servlet aliases...) -- Using an empty PathInfo acts as a NOP shortcut, i.e. does not perform the telnet connection and program launching. 12.mar.00 (LA) Most of the hardcoded constants (prompts, logon, run) have been moved to a properties file for better flexibility. It might even be possible to use different servlet aliases and initArgs! Watch out that properties files do not like : but want \: standalone. 14.mar.00 (LA) Now return empty string instead of null when MPE program prompts for a getParameter() that does not exist in the http request data. The null could cause trouble if Transact expected < 4 chars. */