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