package glg_demos; import java.io.*; import java.net.*; import javax.servlet.*; import javax.servlet.http.*; import javax.imageio.*; import java.awt.image.*; import com.genlogic.*; public final class GlgProcessServlet extends HttpServlet implements GlgErrorHandler { static final long serialVersionUID = 0; static GlgObject viewport = null; // Drawing path relative to the servlet app's dir. static String drawing_name = "/drawings/process2.glg"; // Global simulated data used by all servlets. static GlgProcessDemoData data = new GlgProcessDemoData(); ///////////////////////////////////////////////////////////////// // A wrapper around the main method, doGet2(), to properly handle // the access synchronization and unlocking on an error. ///////////////////////////////////////////////////////////////// public void doGet( HttpServletRequest request, HttpServletResponse response ) throws ServletException { try { doGet2( request, response ); } catch( Exception e ) { // Unlock if was interrupted by the exception while locked. GlgObject.UnlockThread(); throw new ServletException( e ); // Re-thow to log an error } // Unlock just in case the code did not do it due to a programming error. GlgObject.UnlockThread(); } ///////////////////////////////////////////////////////////////// // Main servlet's method: everything is handled here. ///////////////////////////////////////////////////////////////// // Supported actions (action parameter): // GetImage - generates image of the monitored process // ProcessEvent - processes object selection on MouseClick or // Tooltip event types. // GetDialogData - returns data for requested dialogs. ///////////////////////////////////////////////////////////////// public void doGet2( HttpServletRequest request, HttpServletResponse response ) { InitGLG(); // Init the Toolkit String action = GetStringParameter( request, "action", "GetImage" ); if( action.equals( "GetDialogData" ) ) { // Simply return requested dialog data: no drawing required. ProcessDialogData( request, response ); return; } // The rest of actions (GetImage, ProcessEvent) require a drawing - // load it (if first time) and update with data. // Get requested width/height of the image: need for all other actions. int width = GetIntegerParameter( request, "width", 500 ); int height = GetIntegerParameter( request, "height", 400 ); // Limit max. size to avoid running out of heap space creating an image. if( width > 1000 ) width = 1000; if( height > 1000 ) height = 1000; // This example reuses the same drawing between all servlets' threads. // Therefore lock to synchronize and prevent other servlets from // changing the drawing size, etc., before we are done. GlgObject.Lock(); // Load drawing just once and share it among all servlets and threads. // Alternatively, each servlet may load its own drawing. if( viewport == null ) // First time: load the drawing. { viewport = LoadDrawing( drawing_name ); viewport.SetImageSize( width, height ); viewport.SetupHierarchy(); // Setup to prepare to receive data } else // Already loaded, reuse the drawing. viewport.SetImageSize( width, height ); ShowPipes( request ); // Show pipes and flow lines if requested. data.UpdateProcessData(); // Get the new data values from any source. UpdateDrawingWithData(); // Updates drawing with current data. // Setup after data update to prepare to generate image. viewport.SetupHierarchy(); // Main action: Generate Image. if( action.equals( "GetImage" ) ) { // Create an image of the viewport's graphics. BufferedImage image = (BufferedImage) viewport.CreateImage( null ); GlgObject.Unlock(); // Write the image try { response.setContentType("image/png"); OutputStream out_stream = response.getOutputStream(); ImageIO.write( image, "png", out_stream ); out_stream.close(); } catch( IOException e ) { // Log( "Aborted writing of image file." ); } } // Secondary action: ProcessEvent. else if( action.equals( "ProcessEvent" ) ) { String selection_info = null; String event_type = GetStringParameter( request, "event_type", "" ); int selection_type; if( event_type.equals( "MouseClick" ) ) // Get selected object { // Find object with the MouseClick custom event. selection_type = GlgObject.CLICK_SELECTION; } else if( event_type.equals( "Tooltip" ) ) // Get object's tooltip { // Find object with the TooltipString property. selection_type = GlgObject.TOOLTIP_SELECTION; } else { selection_type = 0; selection_info = "Unsupported event_type"; } if( selection_type != 0 ) { // Get x and y coordinates of the mouse click. int x = GetIntegerParameter( request, "x", -1 ); int y = GetIntegerParameter( request, "y", -1 ); // Selection rectangle around the mouse click. GlgCube click_box = new GlgCube(); int selection_sensitivity = 3; // in pixels click_box.p1.x = x - selection_sensitivity; click_box.p1.y = y - selection_sensitivity; click_box.p2.x = x + selection_sensitivity; click_box.p2.y = y + selection_sensitivity; // Find selected object with MouseClick custom event attached. if( x > 0 && y > 0 ) { // Select using MouseClick custom events. GlgObject selection_message = null; selection_message = GlgObject.CreateSelectionMessage( viewport, click_box, viewport, selection_type, 1 ); if( selection_message != null ) switch( selection_type ) { default: case GlgObject.CLICK_SELECTION: // Return object name selection_info = selection_message.GetSResource( "Object/Name" ); break; case GlgObject.TOOLTIP_SELECTION: // Return tooltip string selection_info = selection_message. GetSResource( "Object/TooltipString" ); break; } } else selection_info = "Invalid x/y coordinates."; } GlgObject.Unlock(); WriteAsPlainText( response, selection_info == null ? "None" : selection_info ); } else { Log( "Unsupported action!" ); GlgObject.Unlock(); } } ///////////////////////////////////////////////////////////////// // Helper methods ///////////////////////////////////////////////////////////////// int GetIntegerParameter( HttpServletRequest request, String name, int default_value ) { String parameter_string = request.getParameter( name ); if( parameter_string == null || parameter_string.equals( "" ) ) return default_value; try { return Integer.parseInt( parameter_string ); } catch( NumberFormatException e ) { Log( "Invalid parameter value for: " + name + " = " + parameter_string ); return default_value; } } String GetStringParameter( HttpServletRequest request, String name, String default_value ) { String parameter_string = request.getParameter( name ); if( parameter_string == null ) return default_value; else return parameter_string; } ///////////////////////////////////////////////////////////////// void Log( String msg ) { getServletContext().log( "GlgProcessServlet: " + msg ); } // GlgErrorHandler interface method for error handling. public void Error( String message ) { Log( message ); // Log errors Log( GlgObject.GetStackTraceAsString() ); // Print stack } ///////////////////////////////////////////////////////////////// void WriteAsPlainText( HttpServletResponse response, String string ) { try { response.setContentType("text/plain"); PrintWriter out_stream = new PrintWriter( response.getOutputStream() ); out_stream.write( string ); out_stream.close(); } catch( IOException e ) { // Log( "Aborted writing of text responce." ); } } ///////////////////////////////////////////////////////////////// void InitGLG() { // Set an error handler to log errors. GlgObject.SetErrorHandler( this ); GlgObject.Init(); // Init GlgToolkit } ///////////////////////////////////////////////////////////////// GlgObject LoadDrawing( String drawing_name ) { // Get drawing URL relative to the servlet's directory. URL drawing_url = null; try { drawing_url = getServletConfig().getServletContext().getResource( drawing_name ); } catch( MalformedURLException e ) { Log( "Malformed URL: " + drawing_name ); return null; } if( drawing_url == null ) { Log( "Can't find resource: " + drawing_name ); return null; } // Load drawing from the URL viewport = GlgObject.LoadWidget( drawing_url.toString(), GlgObject.URL ); if( viewport == null ) { Log( "Can't load drawing: " + drawing_name ); return null; } // Disable viewport border in the image: let html define it if needed. viewport.SetDResource( "LineWidth", 0. ); return viewport; } ////////////////////////////////////////////////////////////////////////// // Updates drawing state with data. ////////////////////////////////////////////////////////////////////////// void UpdateDrawingWithData() { viewport.SetDResource( "SolventValve/Angle", data.SolventValve ); viewport.SetDResource( "SteamValve/Angle", data.SteamValve ); viewport.SetDResource( "CoolingValve/Angle", data.CoolingValve ); viewport.SetDResource( "WaterValve/Angle", data.WaterValve ); viewport.SetDResource( "Heater/SteamTemperature", data.SteamTemperature ); viewport.SetDResource( "Heater/HeaterTemperature", data.HeaterTemperature ); viewport.SetDResource( "BeforePreHeaterTemperature", data.BeforePreHeaterTemperature ); viewport.SetDResource( "PreHeaterTemperature", data.PreHeaterTemperature ); viewport.SetDResource( "AfterPreHeaterTemperature", data.AfterPreHeaterTemperature ); viewport.SetDResource( "CoolingTemperature", data.CoolingTemperature ); viewport.SetDResource( "Heater/HeaterLevel", data.HeaterLevel ); viewport.SetDResource( "WaterSeparator/WaterLevel", data.WaterLevel ); viewport.SetDResource( "HeaterAlarm", data.HeaterAlarm ? 1. : 0 ); viewport.SetDResource( "WaterAlarm", data.WaterAlarm ? 1. : 0 ); viewport.SetDResource( "Graph/DataGroup/EntryPoint", data.HeaterTemperature ); viewport.SetDResource( "PressureGauge/Value", 5. * data.HeaterPressure ); } ///////////////////////////////////////////////////////////////// // Shows pipes and flow lines if requested. // Constraints in the drawing take care of updating associated // toggle buttons when the pipe or flow line display state is // changed. The last parameter of SetDResource() is set to true // to update the drawing only if the resource value gets changed. ///////////////////////////////////////////////////////////////// void ShowPipes( HttpServletRequest request ) { // Show pipes if requested, default 0. int show_pipes = GetIntegerParameter( request, "show_pipes", 0 ); viewport.SetDResource( "3DPipes/Visibility", (double)show_pipes, true ); // Show flow if requested, default 1. int show_flow = GetIntegerParameter( request, "show_flow", 1 ); viewport.SetDResource( "FlowGroup/Visibility", (double)show_flow, true ); } ///////////////////////////////////////////////////////////////// // Returns data for a requested dialog. ///////////////////////////////////////////////////////////////// void ProcessDialogData( HttpServletRequest request, HttpServletResponse response ) { String dialog_type = GetStringParameter( request, "dialog_type", "None" ); if( dialog_type.equals( "Heater" ) ) { WriteAsPlainText( response, "Solvent Heater
" + "Level: " + Format( data.HeaterLevel * 100. ) + " %
" + "Pressure: " + Format( data.HeaterPressure * 5. ) + " ATM.
" + "Temperature: " + Format( 50. + data.HeaterTemperature * 100. ) + " C\u00B0" ); } else if( dialog_type.equals( "WaterSeparator" ) ) { WriteAsPlainText( response, "Water Heater
" + "Level: " + Format( data.WaterLevel * 100. ) + " %
" + "Temperature: " + Format( 50 + data.CoolingTemperature * 30. ) + " C\u00B0" ); } else if( dialog_type.equals( "SolventValve" ) ) { WriteAsPlainText( response, "Solvent Valve
" + "Open: " + Format( data.SolventValve * 100. ) + " %" ); } else if( dialog_type.equals( "SteamValve" ) ) { WriteAsPlainText( response, "Steam Valve
" + "Open: " + Format( data.SteamValve * 100. ) + " %" ); } else if( dialog_type.equals( "CoolingValve" ) ) { WriteAsPlainText( response, "Cooling Valve
" + "Open: " + Format( data.CoolingValve * 100. ) + " %" ); } else if( dialog_type.equals( "WaterValve" ) ) { WriteAsPlainText( response, "Water Valve
" + "Open: " + Format( data.WaterValve * 100. ) + " %" ); } else WriteAsPlainText( response, "None" ); } String Format( double value ) { return GlgObject.Printf( "%.2f", value ); } }