package org.hwo.pulscounter; import static org.hwo.logging.Logging.log; import static org.hwo.logging.LogLevel.*; import java.awt.Component; import java.awt.EventQueue; import java.awt.Frame; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.InvalidPropertiesFormatException; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Properties; import java.util.Vector; import java.util.prefs.BackingStoreException; import java.util.prefs.Preferences; import javax.swing.JFrame; import org.hsqldb.persist.EventLogInterface; import org.hwo.StringHelper; import org.hwo.configuration.ConfigurableObjects; import org.hwo.i18n.Messages; import org.hwo.io.NewSerialPort.NewSerialPort; import org.hwo.logging.Logging; import org.hwo.platform.Platform; import org.hwo.servicelink.ServiceLink; import org.hwo.servicelink.ServiceLinkListener; import org.hwo.pulscounter.db.PulsCounterDatabase; import org.hwo.pulscounter.device.IDeviceConnector; import org.hwo.pulscounter.device.ServiceLinkDeviceConnector; import org.hwo.pulscounter.device.SimpleLinkDeviceConnector; import org.hwo.pulscounter.device.SimulatedCounter; import org.hwo.pulscounter.ui.AppSettingsListener; import org.hwo.pulscounter.ui.BatchRunner; import org.hwo.pulscounter.ui.NewMainWindow; import org.hwo.pulscounter.ui.ShutdownNotification; import org.hwo.scheduler.Scheduler; public class PulsCounterApplication implements ServiceLinkListener{ static PulsCounterApplication _application; public static PulsCounterApplication getApplication(){ if (_application == null) _application = new PulsCounterApplication(null); return _application; } private Properties applicationConfiguration, defaultConfiguration; private Object uiSynchronization; private boolean uiIsFinished; private boolean shouldSaveConfiguration; private boolean dontLoadTranslations; private List applicationListeners; private Vector unseenMessages; private List> interfaceClasses; private List interfaces; private PulsCounterDatabase database; private List batchCommands; private NewSerialPort serialPort; private ServiceLink serviceLink; private List appSettingsListeners; private boolean snapshotLock; private List exportSettings; private Scheduler scheduler; private String[] channelDescriptions; public PulsCounterApplication(String[] args) { /* Initialize Logging Framework */ logStartup(); /* Check... */ if (_application != null){ throw new InstantiationError("Only one Instance of PulsCounterApplication can exist!"); } else { _application = this; } /* Initialize fields... */ uiIsFinished = false; uiSynchronization = new Object(); applicationListeners = new LinkedList(); unseenMessages = new Vector(); exportSettings = new ArrayList<>(); interfaceClasses = new ArrayList<>(); interfaces = new ArrayList<>(); batchCommands = new ArrayList<>(); /* Prepare Translation Framework */ Messages i18n = Messages.getInstance(); i18n.setMissingKeysFileName("missing-translation.txt"); /* Prepare for Startup */ loadApplicationConfiguration(); /* Parse Command Line Arguments */ Iterator options = Arrays.asList(args).iterator(); while (options.hasNext()){ String option = options.next(); switch (option){ case "--gui": if (!options.hasNext()){ log(FATAL,"Argument to --gui is missing"); throw new IllegalArgumentException("Argument to --gui is missing"); } else { applicationConfiguration.setProperty("ui.class", options.next()); } break; case "--batch": case "-B": applicationConfiguration.setProperty("ui.class", BatchRunner.class.getCanonicalName()); break; case "-G": applicationConfiguration.setProperty("ui.class", NewMainWindow.class.getCanonicalName()); break; case "--batch-execute": batchCommands.add( options.next() ); break; case "--no-translation": dontLoadTranslations = true; break; default: log(WARN,"Unknown command line parameter: %s", option); } } if (!dontLoadTranslations){ Messages.loadMessages(PulsCounterApplication.class); } else { log(INFO,"Translation text fragments are NOT loaded, due to command line switch (--no-translation)"); } /* Old stuff... */ // this.initialize(); } private Properties createDefaultApplicationConfiguration(){ defaultConfiguration = new Properties(); defaultConfiguration.setProperty("ui.class", NewMainWindow.class.getCanonicalName()); defaultConfiguration.setProperty("interface.classes", StringHelper.join(new String[]{ ServiceLinkDeviceConnector.class.getCanonicalName(), SimulatedCounter.class.getCanonicalName(), SimpleLinkDeviceConnector.class.getCanonicalName() }, ",")); return defaultConfiguration; } private void loadApplicationConfiguration(){ createDefaultApplicationConfiguration(); applicationConfiguration = new Properties(defaultConfiguration); try { /* Try to load configuration from file */ FileInputStream fis = new FileInputStream("synololog.cfg"); applicationConfiguration.loadFromXML(fis); fis.close(); } catch (InvalidPropertiesFormatException e) { log(WARN,"synololog.cfg is misformated"); } catch (FileNotFoundException e) { log(WARN,"synololog.cfg not found"); } catch (IOException e) { log(ERROR,"I/O Error reading synololog.cfg"); } applicationConfiguration.setProperty("ui.class", NewMainWindow.class.getCanonicalName()); } public Properties getApplicationConfiguration(){ return this.applicationConfiguration; } private static void logStartup(){ log("Synololog Application Startup"); log("JAVA Environment: %s (%s)", System.getProperty("java.version"), System.getProperty("java.vendor")); log("Operating System: %s [%s] %s", System.getProperty("os.name"), System.getProperty("os.arch"), System.getProperty("os.version")); log("User Environment: %s (%s) (CWD:%s)", System.getProperty("user.name"), System.getProperty("user.home"), System.getProperty("user.dir")); log("Hostname: %s",Platform.getHostName()); log("OS Search Path: %s", System.getenv("PATH")); } public String[] getBatchCommands(){ return batchCommands.toArray(new String[0]); } public void start(){ initialize(); String uiClassName = applicationConfiguration.getProperty("ui.class"); Object ui = null; try { Class uiClazz = PulsCounterApplication.class.getClassLoader().loadClass(uiClassName); Constructor constructor = uiClazz.getConstructor(PulsCounterApplication.class); ui = (Object) constructor.newInstance(this); } catch (ClassNotFoundException e) { log(FATAL,"user interface class could not be loaded [%s] %s",uiClassName,e.getMessage()); } catch (NoSuchMethodException e) { log(FATAL,"user interface class misses valid constructor [%s] %s",uiClassName,e.getMessage()); } catch (SecurityException e) { e.printStackTrace(); } catch (Exception e) { log(FATAL,"user interface class could not be instantiated. [%s] %s",uiClassName,e.getMessage()); e.printStackTrace(); } waitUiFinished(); // ShutdownNotification sn = new ShutdownNotification(); // if (Component.class.isInstance(ui)){ // sn.setLocationRelativeTo((Component)ui); // } // sn.setVisible(true); try { shutdown(); } catch (Exception e){ log(e); } // sn.setVisible(false); } private void initialize(){ /* Interface Classes should be merged with application well known*/ HashSet interfaceClassNames = new HashSet<>(); for (String icn: applicationConfiguration.getProperty("interface.classes").split(",")){ interfaceClassNames.add(icn); } for (String icn: defaultConfiguration.getProperty("interface.classes").split(",")){ interfaceClassNames.add(icn); } for (String interfaceClassName: interfaceClassNames){ try { Class clazz = (Class)PulsCounterApplication.class.getClassLoader().loadClass(interfaceClassName); interfaceClasses.add(clazz); } catch (ClassNotFoundException e) { log(ERROR,"Interface class could not be loaded: %s",interfaceClassName); } } Integer nIntf = Integer.parseInt(applicationConfiguration.getProperty("interfaces.n","0")); for (int n=0;n clazz = getInterfaceClass(applicationConfiguration.getProperty(String.format("interfaces.%d.class",n))); addInterface(clazz, applicationConfiguration.getProperty(String.format("interfaces.%d.settings",n))); } database = new PulsCounterDatabase(); log(INFO,"Database Schema Version: %s", database.getSchemaVersion()); String sProfiles = database.getProperty("export.profiles"); if (sProfiles != null){ Integer nProfiles = new Integer(sProfiles); for (int n=0;n> getInterfaceClasses(){ return this.interfaceClasses; } private Class getInterfaceClass(String className){ for (Class c:interfaceClasses){ if (c.getCanonicalName().equals(className)) return c; } return null; } /* Physical Interfaces */ public List getInterfaces(){ return this.interfaces; } public void addInterface(Class clazz,String connectionSettings){ try { IDeviceConnector idc = clazz.newInstance(); idc.setConnectionSettings(connectionSettings); interfaces.add(idc); fireinterfacesChanged(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } public void removeInterface(IDeviceConnector intf){ interfaces.remove(intf); fireinterfacesChanged(); } private void fireinterfacesChanged(){ log(INFO,"interfaces changed"); for (PulsCounterApplicationListener l: applicationListeners){ l.interfacesChanged(this); } } public PulsCounterDatabase getDatabase() { return database; } /* Snapshots */ public void checkForSnapShots(){ for (IDeviceConnector idc: this.interfaces){ Integer deviceSerial = idc.getDeviceSerial(); Integer highestIndex = database.highestSnapShot(deviceSerial); log(INFO,"Highest known snapshot index for device #%d is %d", deviceSerial, highestIndex); SnapShot[] snapshots = idc.readSnapShots(highestIndex+1); if (snapshots != null){ getDatabase().storeSnapshots(snapshots); } } } public void addSnapshotToDatabase(SnapShot snapShot){ getDatabase().storeSnapshots(new SnapShot[]{ snapShot }); } /* ToDO: Upgrade the old stuff ... */ /* private void initialize(){ appSettingsListeners = new LinkedList(); exportSettings = new LinkedList(); scheduler = new Scheduler(); channelDescriptions = new String[32]; loadPrefs(); try { snapshotManager = new SnapshotManager(); snapshotManager.notify(Notification.INITIALIZE); } catch (FileNotFoundException e){ e.printStackTrace(); } } */ public void addAppSettingsListener(AppSettingsListener listener){ appSettingsListeners.add(listener); } public void removeAppSettingsListener(AppSettingsListener listener){ appSettingsListeners.remove(listener); } public void addPulsCounterApplicationListener(PulsCounterApplicationListener listener){ applicationListeners.add(listener); } public void removePulsCounterApplicationListener(PulsCounterApplicationListener listener){ applicationListeners.remove(listener); } public void fireServiceLinkChanged(){ for (AppSettingsListener l: appSettingsListeners){ l.ServiceLinkChanged(serviceLink); } } public void message(String message){ log(INFO, message); if (applicationListeners.size() == 0){ unseenMessages.addElement(message); } else { while (!unseenMessages.isEmpty()){ String msg = unseenMessages.remove(0); for (PulsCounterApplicationListener listener: applicationListeners){ listener.messageArrived(msg); } } for (PulsCounterApplicationListener listener: applicationListeners){ listener.messageArrived(message); } }; } @Override public void connectionStateChanged(Boolean connected) { } public List getExportSettings() { return exportSettings; } }