src/java/isac/bridge/BridgeMain.java
author wneuper
Fri, 20 Jul 2007 08:58:53 +0200
branchstart-work-070517
changeset 84 d183c0b0efce
parent 60 7bbb079d40cf
child 86 d60261a08cae
permissions -rw-r--r--
make inherit BrowserFrameSwing, BrowserFrameWeb(MockBrowserFrame) from BrowserFrame
     1 /**
     2  * Created on Aug 13, 2003
     3  * 
     4  * @author Richard Gradischnegg RG
     5  */
     6 package isac.bridge;
     7 
     8 /**
     9  * BridgeMain: main class for bridge, does initialization and provides logging
    10  * delegate and utility functionality.
    11  * 
    12  * @author Richard Gradischnegg RG
    13  * @version 1.1
    14  */
    15 
    16 import isac.gui.browser.BrowserFrameSwing;
    17 import isac.util.BridgeMainPaths;
    18 import isac.util.FixedPortRMISocketFactory;
    19 import isac.util.ObjectManagerRMISocketFactory;
    20 import isac.util.ObjectManagerPaths;
    21 
    22 import java.awt.BorderLayout;
    23 import java.awt.Color;
    24 import java.awt.Font;
    25 import java.awt.event.WindowAdapter;
    26 import java.awt.event.WindowEvent;
    27 import java.awt.event.WindowListener;
    28 import java.io.BufferedReader;
    29 import java.io.File;
    30 import java.io.FileInputStream;
    31 import java.io.FileNotFoundException;
    32 import java.io.IOException;
    33 import java.io.InputStream;
    34 import java.io.InputStreamReader;
    35 import java.io.OutputStream;
    36 import java.io.PrintWriter;
    37 import java.io.Serializable;
    38 import java.rmi.RemoteException;
    39 import java.rmi.server.RMISocketFactory;
    40 import java.util.Properties;
    41 import java.util.Vector;
    42 
    43 import javax.swing.JFrame;
    44 import javax.swing.JPanel;
    45 import javax.swing.JScrollPane;
    46 import javax.swing.JTextArea;
    47 
    48 import org.apache.log4j.Logger;
    49 
    50 /**
    51  * Bridge main class: initializes connection to SML, starts auxillary threads,
    52  * handles logging mechanism
    53  * 
    54  * @author rgradisc
    55  */
    56 class BridgeMain implements Serializable {
    57 
    58 	private static final long serialVersionUID = 507L;
    59     private static final Logger logger = Logger.getLogger(BridgeMain.class.getName());
    60 	
    61 	private String ini_path_;
    62 
    63 	private int socket_port_;
    64 
    65 	private JFrame log_frame_;
    66 
    67 	private String path_;
    68 
    69 	private String kernel_exec_;
    70 
    71 	private String kernel_args_;
    72 
    73 	private long wait_millis_;
    74 
    75 	private final static int TRANS_STRING = 1;
    76 
    77 	private final static int TRANS_MATHML = 2;
    78 
    79 	private int transport_mode_ = TRANS_STRING;
    80 
    81 	JPanel panel_;
    82 
    83 	JTextArea text_area_;
    84 
    85 	JScrollPane scroll_pane_;
    86 
    87 	private Thread thread_clients2kernel_;
    88 
    89 	private Thread thread_sml_;
    90 
    91 	private Thread thread_kernel2clients_;
    92 
    93 	private Thread thread_time_checker_;
    94 
    95 	private ClientList client_list_;
    96 
    97 	private BridgeLogger bridge_logger_;
    98 
    99 	private OutputStream sml_output_;
   100 
   101 	private InputStream sml_input_;
   102 
   103 	private PrintWriter sml_writer_;
   104 
   105 	private BufferedReader sml_reader_;
   106 
   107 	private Vector time_out_times_;
   108 
   109 	public int ignore_output_ = 0;
   110 
   111 	private BridgeRMI bridge_rmi_; // multiple RMI connections: Vector
   112 
   113 	private boolean restoring_; // true = bridge is in restoring_ phase
   114 
   115 	private boolean kernel_responding_ = true;
   116 
   117 
   118 	/**
   119 	 * Constructor used to set up the bridge main program
   120 	 * 
   121 	 * @param ini_path_:
   122 	 *            path_ to initialization file
   123 	 */
   124 	BridgeMain(String iniPath) {
   125 		// hack for suppressing warning messages
   126 		// (no longer nescessary with j2sdk1.4.2)
   127 		// System.setProperty("java.util.prefs.syncInterval", "20000000000");
   128 
   129         if (logger.isDebugEnabled())
   130             logger.debug("BridgeMain obj.init: ini_path_=" + iniPath);
   131 		this.ini_path_ = iniPath;
   132 		readProperties();
   133 
   134 		bridge_logger_ = new BridgeLogger(path_);
   135 		client_list_ = new ClientList();
   136 		time_out_times_ = new Vector();
   137 		setUpBridgeLog();
   138 		startThreadsFirstTime();
   139 	}
   140 
   141 	private void setUpBridgeLog() {
   142 		if (BridgeMainPaths.SHOW_GUI_LOGGER) {
   143 			log_frame_ = new JFrame("Java<->SML");
   144 			log_frame_.setLocation(700, 250);
   145 			panel_ = new JPanel();
   146 			panel_.setSize(200, 300);
   147 			panel_.setLayout(new BorderLayout());
   148 			panel_.setBackground(Color.white);
   149 
   150 			text_area_ = new JTextArea();
   151 			text_area_.setFont(new Font("Monospaced", 0, 11));
   152 			scroll_pane_ = new JScrollPane(text_area_,
   153 					JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
   154 					JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
   155 			panel_.add("Center", scroll_pane_);
   156 			log_frame_.getContentPane().add(panel_);
   157 
   158 			log_frame_.setTitle("BridgeLog Java <=> SML");
   159 			WindowListener l = new WindowAdapter() {
   160 
   161 				public void windowClosing(WindowEvent e) {
   162 					System.exit(0);
   163 				}
   164 			};
   165 			log_frame_.addWindowListener(l);
   166 			log_frame_.pack();
   167 			log_frame_.setSize(300, 500);
   168 			log_frame_.setVisible(true);
   169 		}
   170 	}
   171 
   172 	// Read Bridge properties from Files
   173 	private void readProperties() {
   174 		Properties p = new Properties();
   175 		String prop;
   176 		try {
   177 			p.load(new FileInputStream(ini_path_));
   178 			prop = p.getProperty("transportMode");
   179 			if (prop.equals("string")) {
   180 				transport_mode_ = TRANS_STRING;
   181 			} else if (prop.equals("mathml")) {
   182 				transport_mode_ = TRANS_MATHML;
   183 			} else {
   184 				System.out.println("INI-File: transport_mode_ value not valid");
   185 				System.exit(1);
   186 			}
   187 			System.out.println("transport_mode_ = " + transport_mode_);
   188 
   189 			prop = p.getProperty("socketPort");
   190 			try {
   191 				socket_port_ = Integer.valueOf(prop).intValue();
   192 			} catch (NumberFormatException e1) {
   193 				System.out.println("INI-File: socketport is not a number!");
   194 				System.exit(1);
   195 			}
   196 			Float.floatToIntBits(3.14f);
   197 			System.out.println("socket_port_ = " + socket_port_);
   198 
   199 			prop = p.getProperty("path");
   200 			File f = new File(prop);
   201 			System.out.println(prop);
   202 			if (f.isDirectory()) {
   203 				path_ = prop;
   204 			} else {
   205 				System.out.println("INI-File: path_ is not a valid directory!");
   206 				System.exit(1);
   207 			}
   208 			System.out.println("path_ = " + path_);
   209 
   210 			prop = p.getProperty("waitMillis");
   211 			try {
   212 				wait_millis_ = Long.valueOf(prop).longValue();
   213 			} catch (NumberFormatException e1) {
   214 				System.out.println("INI-File: wait_millis_ is not a number!");
   215 				System.exit(1);
   216 			}
   217 			System.out.println("wait_millis_ = " + wait_millis_);
   218 
   219 			kernel_exec_ = p.getProperty("kernelExec");
   220 			kernel_args_ = p.getProperty("kernelArgs");
   221 
   222 		} catch (FileNotFoundException e) {
   223 			System.out.println("Couldn't open INI File");
   224 			System.exit(1);
   225 		} catch (IOException e) {
   226 			System.out.println("Couldn't read INI File");
   227 			System.exit(1);
   228 		}
   229 	}
   230 
   231 	// Start sml Threads and catch in- and output-streams
   232 	private void startSMLThread() {
   233         if (logger.isDebugEnabled())
   234             logger.debug("startSMLThread");
   235 		SMLThread smlThread = new SMLThread(this, kernel_exec_, kernel_args_);
   236 		thread_sml_ = new Thread(smlThread, "java_bridge_execution");
   237 		thread_sml_.setDaemon(true);
   238 		// daemon threads: discontinue running after main application is
   239 		// finished
   240 		log(1, "SML Execution Thread starting...");
   241 		thread_sml_.start();
   242 		log(1, "SML Execution Thread started");
   243 		sml_input_ = smlThread.getInputStream();
   244 		log(1, "SML input stream");
   245 		sml_output_ = smlThread.getOutputStream();
   246 		log(1, "SML output stream");
   247 		// old IO:
   248 		sml_writer_ = new PrintWriter(sml_output_, true);
   249 		// NIO (doesn't run for some reason)
   250 		// sml_writer_ =
   251 		// new PrintWriter(
   252 		// Channels.newWriter(Channels.newChannel(sml_output_), "ISO-8859-1"));
   253 		// old IO:
   254 		sml_reader_ = new BufferedReader(new InputStreamReader(sml_input_));
   255 		// NIO:
   256 		// sml_reader_ =
   257 		// new BufferedReader(
   258 		// Channels.newReader(Channels.newChannel(sml_input_), "ISO-8859-1"));
   259 
   260 		log(1, "SML in/output streams fetched");
   261 		// log(1, sml_writer_.toString());
   262 		// log(1, sml_reader_.toString());
   263 	}
   264 
   265 	private void startThreadsFirstTime() {
   266         if (logger.isDebugEnabled())
   267             logger.debug("startThreadsFirstTime");
   268 		startSMLThread();
   269 
   270 		Clients2KernelServer c2k = new Clients2KernelServer(this);
   271 		thread_clients2kernel_ = new Thread(c2k, "java_bridge_clients2kernel");
   272 		thread_clients2kernel_.setDaemon(true);
   273 		thread_clients2kernel_.start();
   274 		log(1, "Clients2Kernel Thread started");
   275 
   276 		Kernel2ClientsServer k2c = new Kernel2ClientsServer(this);
   277 		thread_kernel2clients_ = new Thread(k2c, "java_bridge_kernel2clients");
   278 		thread_kernel2clients_.setDaemon(true);
   279 		thread_kernel2clients_.start();
   280 		log(1, "Kernel2Clients Thread started");
   281 
   282 		thread_time_checker_ = new TimeCheckerThread(this, wait_millis_);
   283 		thread_time_checker_.setDaemon(true);
   284 		thread_time_checker_.start();
   285 		log(1, "TimeChecker Thread started");
   286 	}
   287 
   288 	public void restartSML() {
   289 		log(1, "No response from sml-kernel: restart");
   290 		time_out_times_.clear();
   291 		log(1, "Trying to kill sml-kernel...");
   292 		while (thread_sml_.isAlive()) {
   293 			thread_sml_.interrupt();
   294 		}
   295 		log(1, "Successfully killed sml-kernel");
   296 
   297 		try {
   298 			log(1, "BridgeMain: trying to close reader/writer");
   299 			sml_reader_.close();
   300 			sml_writer_.close();
   301 			log(1, "BridgeMain: closed reader/writer");
   302 		} catch (IOException e) {
   303 			log(1, "BridgeMain: couldn't close reader/writer");
   304 		}
   305 		startSMLThread();
   306 		restoreStateOfKernel();
   307 	}
   308 
   309 	// This method restores the last consistent state of the kernel
   310 	// It will be called when the sml kernel crashes
   311 	private void restoreStateOfKernel() {
   312 		// test first if kernel is still responding:
   313 		// if this is the case, no further restoring_ is needed
   314 		// dummy call to test respondablity
   315 		// it could be also work to send a SIGINT (^C in terminal)
   316 		// to the not reacting sml-Kernel
   317 		// But this is not possible in Java (only with C in JNI)
   318 		try {
   319 			while (!kernel_responding_) {
   320 				sml_writer_.println("DEconstrCalcTree 0;");
   321 				// if the kernel responds to this instruction, it has
   322 				// not crashed: no restarting nescessary
   323 				if (sml_reader_.ready()) {
   324 					Thread.sleep(1000);
   325 					sml_reader_.readLine();
   326 					kernel_responding_ = true;
   327 				}
   328 			}
   329 		} catch (Exception e) {
   330 		}
   331 		if (!kernel_responding_) {
   332 			log(1, "Kernel is not responding: now restarting");
   333 			this.restoring_ = true;
   334 		}
   335 		/*
   336 		 * Vector inputs = bridge_rmi_.getInputs();
   337 		 */
   338 		/*
   339 		 * Iterator it = newInputs.iterator(); while (it.hasNext()) { int
   340 		 * clientID = ((ClientInput)it.next()).getClientID();
   341 		 * client_list_.getPrintWriterOfClient(clientID).println(" <FATALERROR>
   342 		 * </FATALERROR>"); }
   343 		 */
   344 		log(1, "------ now restoring_ state of kernel");
   345 		this.restoring_ = true;
   346 		// send empty response string to blocking client
   347 		client_list_.getPrintWriterOfClient(bridge_rmi_.getRmiID()).println(
   348 				"<ISAC></ISAC>");
   349 		log(1, "------ restoreExistingCalcTrees()");
   350 		bridge_rmi_.restoreExistingCalcTrees();
   351 		// TODO: bridge_rmi_.deleteLastBufferInput();
   352 		this.restoring_ = false;
   353 		log(1, "------ done restoring_ state of kernel");
   354 		/*
   355 		 * ignore_output_ = inputs.size(); Iterator it = inputs.iterator();
   356 		 * while (it.hasNext()) { ClientInput clientInput =
   357 		 * (ClientInput)it.next(); String input = clientInput.getInputLine();
   358 		 * log(1, "user "+clientInput.getClientID()+" ---> " + input); //Resend
   359 		 * user input to sml sml_writer_.println(input); time_out_times_.add(new
   360 		 * Long(System.currentTimeMillis())); }
   361 		 */
   362 	}
   363 
   364 	// Here goes the future load balancing functionality
   365 	// public void startNewKernel() {
   366 	// implement load balancing
   367 	// }
   368 
   369 	protected void finalize() throws Throwable {
   370 		super.finalize(); // gosling p.47
   371 		// Objects created in run method are finalized when
   372 		// program terminates and thread exits
   373 		while (thread_sml_.isAlive()) {
   374 			thread_sml_.interrupt();
   375 			log(1, "waiting for SML thread to quit..");
   376 		}
   377 		bridge_logger_.log(1, "finished");
   378 		bridge_logger_.close();
   379 	}
   380 
   381 	/**
   382 	 * Log a message with a specified severity level
   383 	 * 
   384 	 * @param level
   385 	 *            severity level
   386 	 * @param msg
   387 	 *            the message to be logged
   388 	 */
   389 	public void log(int level, String msg) {
   390 		if(BridgeMainPaths.LOG_TO_FILE)
   391 			this.bridge_logger_.log(level, msg);
   392         if(BridgeMainPaths.SHOW_GUI_LOGGER)
   393         	this.text_area_.append(msg + "\n");
   394 	}
   395 
   396 	public ClientList getClientList() {
   397 		return client_list_;
   398 	}
   399 
   400 	public BufferedReader getSmlReader() {
   401         //if (logger.isDebugEnabled())
   402         //    logger.debug("getSmlReader x");
   403 		return sml_reader_;
   404 	}
   405 
   406 	public PrintWriter getSmlWriter() {
   407 		return sml_writer_;
   408 	}
   409 
   410 	public Vector getTimeOutTimes() {
   411 		return time_out_times_;
   412 	}
   413 
   414 	public String getPath() {
   415 		return path_;
   416 	}
   417 
   418 	public int getSocketPort() {
   419 		return socket_port_;
   420 	}
   421 
   422 	public void setRMI(BridgeRMI bridgeRMI) {
   423         if (logger.isDebugEnabled())
   424             logger.debug("setRMI: bridge_rmi_=" + bridgeRMI);
   425 		this.bridge_rmi_ = bridgeRMI;
   426 		bridgeRMI.setRmiID(1); // only one BridgeRMI used so far
   427 	}
   428 
   429 	boolean isRestoring() {
   430 		return restoring_;
   431 	}
   432 
   433 	void setRestoring(boolean b) {
   434 		restoring_ = b;
   435 	}
   436 
   437 	/**
   438 	 * @param args
   439 	 *            commandline arguments (exactly 4 expected: _iniPath _host
   440 	 *            _port _dtdPath)
   441 	 * @see BridgeMain()
   442 	 */
   443 	public static void main(String[] args) {
   444 
   445 		String ini_load_result = BridgeMainPaths.loadFromFile(args[0]);
   446 
   447 		if (ini_load_result != null)
   448 			ini_load_result += BridgeMainPaths.loadFromResource(args[0]);
   449 
   450 		if (ini_load_result != null) {
   451 			System.err.println(ini_load_result);
   452 			System.exit(1);
   453 		}
   454 
   455 		// initialize bridge main part
   456 		BridgeMain bridge = new BridgeMain(BridgeMainPaths.INI_PATH);
   457 
   458 		try {
   459             // Use ObjectManagerRMISocketFactory
   460 			// 6666 = dummy
   461             RMISocketFactory.setSocketFactory( new FixedPortRMISocketFactory(BridgeMainPaths.BRIDGE_RMI_PORT ));
   462 
   463 			// setup rmi connection to to the clients
   464 			BridgeRMI rmi = new BridgeRMI(bridge, BridgeMainPaths.HOST,
   465 					BridgeMainPaths.BRIDGE_MAIN_PORT, BridgeMainPaths.DTD_PATH);
   466 			
   467 			System.out.println( rmi );
   468 			
   469 			bridge.setRMI(rmi);
   470 		} catch (RemoteException e) {
   471 			System.out.println("Could not instantiate RMI: exiting");
   472 			e.printStackTrace();
   473 		}
   474         catch (IOException e)
   475         {
   476                 System.out.println("Exception: " + e.getMessage());
   477                 e.printStackTrace();
   478         }
   479 	}
   480 }