540 lines
14 KiB
Java
540 lines
14 KiB
Java
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.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.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 List<PulsCounterApplicationListener>
|
|
applicationListeners;
|
|
|
|
private Vector<String> unseenMessages;
|
|
|
|
private List<Class<IDeviceConnector>>
|
|
interfaceClasses;
|
|
private List<IDeviceConnector> interfaces;
|
|
|
|
private PulsCounterDatabase database;
|
|
|
|
private List<String> batchCommands;
|
|
|
|
|
|
|
|
|
|
private NewSerialPort serialPort;
|
|
private ServiceLink serviceLink;
|
|
|
|
private List<AppSettingsListener> appSettingsListeners;
|
|
|
|
private boolean snapshotLock;
|
|
|
|
|
|
private List<ExportSetting> 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<PulsCounterApplicationListener>();
|
|
unseenMessages = new Vector<String>();
|
|
exportSettings = new ArrayList<>();
|
|
|
|
interfaceClasses = new ArrayList<>();
|
|
interfaces = new ArrayList<>();
|
|
|
|
batchCommands = new ArrayList<>();
|
|
|
|
/* Prepare for Startup */
|
|
loadApplicationConfiguration();
|
|
|
|
/* Parse Command Line Arguments */
|
|
Iterator<String> 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() );
|
|
default:
|
|
log(WARN,"Unknown command line parameter: %s", option);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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()
|
|
}, ","));
|
|
|
|
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(){
|
|
Logging.setLogFileName("synololog.log");
|
|
|
|
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<String> 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<IDeviceConnector> clazz = (Class<IDeviceConnector>)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<nIntf;n++){
|
|
Class<IDeviceConnector> 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<nProfiles;n++){
|
|
String profileConf = database.getProperty(String.format("export.profiles.%d",n));
|
|
log(INFO,"Export Profile %d: %s",n,profileConf);
|
|
|
|
if (profileConf != null){
|
|
ExportSetting es = new ExportSetting();
|
|
ConfigurableObjects.setConfiguration(es, profileConf);
|
|
exportSettings.add(es);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
private void shutdown(){
|
|
|
|
log(INFO,"Application shutdown...");
|
|
|
|
/* Dispose all left frames */
|
|
for (Frame frame: JFrame.getFrames()){
|
|
frame.setVisible(false);
|
|
frame.dispose();
|
|
}
|
|
|
|
if (shouldSaveConfiguration){
|
|
|
|
applicationConfiguration.setProperty("interfaces.n", Integer.toString(interfaces.size()));
|
|
for (int n=0;n<interfaces.size();n++){
|
|
applicationConfiguration.setProperty(String.format("interfaces.%d.class", n), interfaces.get(n).getClass().getCanonicalName());
|
|
applicationConfiguration.setProperty(String.format("interfaces.%d.settings", n), interfaces.get(n).getConnectionSettings());
|
|
}
|
|
|
|
for (int n=0;n<exportSettings.size();n++){
|
|
String conf = ConfigurableObjects.getConfiguration(exportSettings.get(n));
|
|
if (conf != null){
|
|
database.setProperty(String.format("export.profiles.%d", n), conf);
|
|
}
|
|
}
|
|
database.setProperty("export.profiles", new Integer(exportSettings.size()).toString());
|
|
|
|
|
|
|
|
try {
|
|
log(INFO,"Save application configuration");
|
|
FileOutputStream fos = new FileOutputStream("synololog.cfg");
|
|
applicationConfiguration.storeToXML(fos, "Synololog Application Configuration");
|
|
fos.flush();
|
|
fos.close();
|
|
} catch (FileNotFoundException e) {
|
|
log(ERROR,"synololog.cfg could not be created/opened for writing");
|
|
} catch (IOException e) {
|
|
log(ERROR,"synololog.cfg could not be written");
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
database.close();
|
|
|
|
|
|
}
|
|
|
|
|
|
private void waitUiFinished(){
|
|
|
|
synchronized (uiSynchronization) {
|
|
|
|
while (!uiIsFinished){
|
|
try {
|
|
uiSynchronization.wait(250);
|
|
} catch (InterruptedException e){
|
|
log(e);
|
|
}
|
|
}
|
|
}
|
|
log(INFO,"UI notified finish");
|
|
|
|
}
|
|
|
|
public void notifyUiIsFinished(boolean saveApplicationConfiguration){
|
|
synchronized (uiSynchronization) {
|
|
uiIsFinished = true;
|
|
shouldSaveConfiguration = saveApplicationConfiguration;
|
|
uiSynchronization.notify();
|
|
}
|
|
}
|
|
|
|
|
|
/* Interface Types */
|
|
public List<Class<IDeviceConnector>> getInterfaceClasses(){
|
|
return this.interfaceClasses;
|
|
}
|
|
|
|
private Class<IDeviceConnector> getInterfaceClass(String className){
|
|
for (Class<IDeviceConnector> c:interfaceClasses){
|
|
if (c.getCanonicalName().equals(className))
|
|
return c;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/* Physical Interfaces */
|
|
public List<IDeviceConnector> getInterfaces(){
|
|
return this.interfaces;
|
|
}
|
|
public void addInterface(Class<IDeviceConnector> 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<AppSettingsListener>();
|
|
exportSettings = new LinkedList<ExportSetting>();
|
|
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){
|
|
|
|
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<ExportSetting> getExportSettings() {
|
|
return exportSettings;
|
|
}
|
|
|
|
|
|
|
|
}
|