2 * Created on Aug 13, 2003
7 * BridgeMain: main class for bridge, does initialization and provides logging
8 * delegate and utility functionality.
15 import java.awt.BorderLayout;
16 import java.awt.Color;
18 import java.awt.event.WindowAdapter;
19 import java.awt.event.WindowEvent;
20 import java.awt.event.WindowListener;
21 import java.io.BufferedReader;
23 import java.io.FileInputStream;
24 import java.io.FileNotFoundException;
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.io.InputStreamReader;
28 import java.io.OutputStream;
29 import java.io.PrintWriter;
30 import java.rmi.RemoteException;
31 import java.util.Properties;
32 import java.util.Vector;
34 import javax.swing.JFrame;
35 import javax.swing.JPanel;
36 import javax.swing.JScrollPane;
37 import javax.swing.JTextArea;
39 import org.apache.log4j.Logger;
42 * Bridge main class: initializes connection to SML, starts auxillary threads,
43 * handles logging mechanism
47 class BridgeMain extends JFrame {
49 private String ini_path_;
51 private int socket_port_;
55 private String kernel_exec_;
57 private String kernel_args_;
59 private long wait_millis_;
61 private final static int TRANS_STRING = 1;
63 private final static int TRANS_MATHML = 2;
65 private int transport_mode_ = TRANS_STRING;
71 JScrollPane scroll_pane_;
73 private Thread thread_clients2kernel_;
75 private Thread thread_sml_;
77 private Thread thread_kernel2clients_;
79 private Thread thread_time_checker_;
81 private ClientList client_list_;
83 private BridgeLogger bridge_logger_;
85 private OutputStream sml_output_;
87 private InputStream sml_input_;
89 private PrintWriter sml_writer_;
91 private BufferedReader sml_reader_;
93 private Vector time_out_times_;
95 public int ignore_output_ = 0;
97 private BridgeRMI bridge_rmi_; // multiple RMI connections: Vector
99 private boolean restoring_; // true = bridge is in restoring_ phase
101 private boolean kernel_responding_ = true;
103 static Logger logger_ = Logger.getLogger(BridgeMain.class.getName());
106 * Constructor used to set up the bridge main program
109 * path_ to initialization file
111 BridgeMain(String iniPath) {
112 //hack for suppressing warning messages
113 //(no longer nescessary with j2sdk1.4.2)
114 //System.setProperty("java.util.prefs.syncInterval", "20000000000");
116 logger_.warn("BridgeMain obj.init: ini_path_=" + iniPath);
117 this.ini_path_ = iniPath;
120 bridge_logger_ = new BridgeLogger(path_);
121 client_list_ = new ClientList();
122 time_out_times_ = new Vector();
124 startThreadsFirstTime();
127 private void setUpBridgeLog() {
128 this.setLocation(700, 250);
129 panel_ = new JPanel();
130 panel_.setSize(200, 300);
131 panel_.setLayout(new BorderLayout());
132 panel_.setBackground(Color.white);
134 text_area_ = new JTextArea();
135 text_area_.setFont(new Font("Monospaced", 0, 11));
136 scroll_pane_ = new JScrollPane(text_area_,
137 JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
138 JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
139 panel_.add("Center", scroll_pane_);
140 getContentPane().add(panel_);
142 setTitle("BridgeLog Java <=> SML");
143 WindowListener l = new WindowAdapter() {
145 public void windowClosing(WindowEvent e) {
149 addWindowListener(l);
151 this.setSize(300, 500);
155 // Read Bridge properties from Files
156 private void readProperties() {
157 Properties p = new Properties();
160 p.load(new FileInputStream(ini_path_));
161 prop = p.getProperty("transportMode");
162 if (prop.equals("string")) {
163 transport_mode_ = TRANS_STRING;
164 } else if (prop.equals("mathml")) {
165 transport_mode_ = TRANS_MATHML;
167 System.out.println("INI-File: transport_mode_ value not valid");
170 System.out.println("transport_mode_ = " + transport_mode_);
172 prop = p.getProperty("socketPort");
174 socket_port_ = Integer.valueOf(prop).intValue();
175 } catch (NumberFormatException e1) {
176 System.out.println("INI-File: socketport is not a number!");
179 Float.floatToIntBits(3.14f);
180 System.out.println("socket_port_ = " + socket_port_);
182 prop = p.getProperty("path");
183 File f = new File(prop);
184 if (f.isDirectory()) {
187 System.out.println("INI-File: path_ is not a valid directory!");
190 System.out.println("path_ = " + path_);
192 prop = p.getProperty("waitMillis");
194 wait_millis_ = Long.valueOf(prop).longValue();
195 } catch (NumberFormatException e1) {
196 System.out.println("INI-File: wait_millis_ is not a number!");
199 System.out.println("wait_millis_ = " + wait_millis_);
201 kernel_exec_ = p.getProperty("kernelExec");
202 kernel_args_ = p.getProperty("kernelArgs");
204 } catch (FileNotFoundException e) {
205 System.out.println("Couldn't open INI File");
207 } catch (IOException e) {
208 System.out.println("Couldn't read INI File");
213 //Start sml Threads and catch in- and output-streams
214 private void startSMLThread() {
215 logger_.warn("startSMLThread");
216 SMLThread smlThread = new SMLThread(this, kernel_exec_, kernel_args_);
217 thread_sml_ = new Thread(smlThread, "java_bridge_execution");
218 thread_sml_.setDaemon(true);
219 // daemon threads: discontinue running after main application is
221 log(1, "SML Execution Thread starting...");
223 log(1, "SML Execution Thread started");
224 sml_input_ = smlThread.getInputStream();
225 log(1, "SML input stream");
226 sml_output_ = smlThread.getOutputStream();
227 log(1, "SML output stream");
229 sml_writer_ = new PrintWriter(sml_output_, true);
230 //NIO (doesn't run for some reason)
233 // Channels.newWriter(Channels.newChannel(sml_output_), "ISO-8859-1"));
235 sml_reader_ = new BufferedReader(new InputStreamReader(sml_input_));
238 // new BufferedReader(
239 // Channels.newReader(Channels.newChannel(sml_input_), "ISO-8859-1"));
241 log(1, "SML in/output streams fetched");
242 //log(1, sml_writer_.toString());
243 //log(1, sml_reader_.toString());
246 private void startThreadsFirstTime() {
247 logger_.warn("startThreadsFirstTime");
250 Clients2KernelServer c2k = new Clients2KernelServer(this);
251 thread_clients2kernel_ = new Thread(c2k, "java_bridge_clients2kernel");
252 thread_clients2kernel_.setDaemon(true);
253 thread_clients2kernel_.start();
254 log(1, "Clients2Kernel Thread started");
256 Kernel2ClientsServer k2c = new Kernel2ClientsServer(this);
257 thread_kernel2clients_ = new Thread(k2c, "java_bridge_kernel2clients");
258 thread_kernel2clients_.setDaemon(true);
259 thread_kernel2clients_.start();
260 log(1, "Kernel2Clients Thread started");
262 thread_time_checker_ = new TimeCheckerThread(this, wait_millis_);
263 thread_time_checker_.setDaemon(true);
264 thread_time_checker_.start();
265 log(1, "TimeChecker Thread started");
268 public void restartSML() {
269 log(1, "No response from sml-kernel: restart");
270 time_out_times_.clear();
271 log(1, "Trying to kill sml-kernel...");
272 while (thread_sml_.isAlive()) {
273 thread_sml_.interrupt();
275 log(1, "Successfully killed sml-kernel");
278 log(1, "BridgeMain: trying to close reader/writer");
281 log(1, "BridgeMain: closed reader/writer");
282 } catch (IOException e) {
283 log(1, "BridgeMain: couldn't close reader/writer");
286 restoreStateOfKernel();
289 // This method restores the last consistent state of the kernel
290 // It will be called when the sml kernel crashes
291 private void restoreStateOfKernel() {
292 //test first if kernel is still responding:
293 //if this is the case, no further restoring_ is needed
294 //dummy call to test respondablity
295 //it could be also work to send a SIGINT (^C in terminal)
296 //to the not reacting sml-Kernel
297 //But this is not possible in Java (only with C in JNI)
299 while (!kernel_responding_) {
300 sml_writer_.println("DEconstrCalcTree 0;");
301 // if the kernel responds to this instruction, it has
302 // not crashed: no restarting nescessary
303 if (sml_reader_.ready()) {
305 sml_reader_.readLine();
306 kernel_responding_ = true;
309 } catch (Exception e) {
311 if (!kernel_responding_) {
312 log(1, "Kernel is not responding: now restarting");
313 this.restoring_ = true;
316 * Vector inputs = bridge_rmi_.getInputs();
319 * Iterator it = newInputs.iterator(); while (it.hasNext()) { int
320 * clientID = ((ClientInput)it.next()).getClientID();
321 * client_list_.getPrintWriterOfClient(clientID).println(" <FATALERROR>
324 log(1, "------ now restoring_ state of kernel");
325 this.restoring_ = true;
326 //send empty response string to blocking client
327 client_list_.getPrintWriterOfClient(bridge_rmi_.getRmiID()).println(
329 log(1, "------ restoreExistingCalcTrees()");
330 bridge_rmi_.restoreExistingCalcTrees();
331 //TODO: bridge_rmi_.deleteLastBufferInput();
332 this.restoring_ = false;
333 log(1, "------ done restoring_ state of kernel");
335 * ignore_output_ = inputs.size(); Iterator it = inputs.iterator();
336 * while (it.hasNext()) { ClientInput clientInput =
337 * (ClientInput)it.next(); String input = clientInput.getInputLine();
338 * log(1, "user "+clientInput.getClientID()+" ---> " + input); //Resend
339 * user input to sml sml_writer_.println(input); time_out_times_.add(new
340 * Long(System.currentTimeMillis())); }
344 //Here goes the future load balancing functionality
345 //public void startNewKernel() {
346 // implement load balancing
349 protected void finalize() throws Throwable {
350 super.finalize(); //gosling p.47
351 //Objects created in run method are finalized when
352 //program terminates and thread exits
353 while (thread_sml_.isAlive()) {
354 thread_sml_.interrupt();
355 log(1, "waiting for SML thread to quit..");
357 bridge_logger_.log(1, "finished");
358 bridge_logger_.close();
362 * Log a message with a specified severity level
367 * the message to be logged
369 public void log(int level, String msg) {
370 this.bridge_logger_.log(level, msg);
371 this.text_area_.append(msg + "\n");
374 public ClientList getClientList() {
378 public BufferedReader getSmlReader() {
379 logger_.warn("getSmlReader x");
383 public PrintWriter getSmlWriter() {
387 public Vector getTimeOutTimes() {
388 return time_out_times_;
391 public String getPath() {
395 public int getSocketPort() {
399 public void setRMI(BridgeRMI bridgeRMI) {
400 logger_.warn("setRMI: bridge_rmi_=" + bridgeRMI);
401 this.bridge_rmi_ = bridgeRMI;
402 bridgeRMI.setRmiID(1); //only one BridgeRMI used so far
405 boolean isRestoring() {
409 void setRestoring(boolean b) {
415 * commandline arguments (exactly 4 expected: _iniPath _host
419 public static void main(String[] args) {
420 if (args.length != 4) {
422 .println("Usage: java BridgeMain _iniPath _host _port _dtdPath");
424 // initialize bridge main part
425 BridgeMain bridge = new BridgeMain(args[0]);
428 // setup rmi connection to to the clients
429 BridgeRMI rmi = new BridgeRMI(bridge, args[1], Integer
430 .parseInt(args[2]), args[3]);
432 } catch (RemoteException e) {
433 System.out.println("Could not instantiate RMI: exiting");