560 lines
14 KiB
Java
560 lines
14 KiB
Java
|
package org.hwo.pulscounter;
|
||
|
|
||
|
import static org.hwo.logging.Logging.log;
|
||
|
import static org.hwo.logging.LogLevel.*;
|
||
|
|
||
|
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.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 org.hwo.StringHelper;
|
||
|
import org.hwo.configuration.ConfigurableObjects;
|
||
|
import org.hwo.io.NewSerialPort.NewSerialPort;
|
||
|
import org.hwo.platform.Platform;
|
||
|
import org.hwo.servicelink.ServiceLink;
|
||
|
import org.hwo.servicelink.ServiceLinkListener;
|
||
|
import org.hwo.pulscounter.device.IDeviceConnector;
|
||
|
import org.hwo.pulscounter.device.ServiceLinkDeviceConnector;
|
||
|
import org.hwo.pulscounter.ui.AppSettingsListener;
|
||
|
import org.hwo.pulscounter.ui.BatchRunner;
|
||
|
import org.hwo.pulscounter.ui.NewMainWindow;
|
||
|
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;
|
||
|
private List<IDeviceConnector> deviceConnectors;
|
||
|
|
||
|
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 NewSerialPort serialPort;
|
||
|
private ServiceLink serviceLink;
|
||
|
|
||
|
private List<AppSettingsListener> appSettingsListeners;
|
||
|
|
||
|
private boolean snapshotLock;
|
||
|
|
||
|
|
||
|
private SnapshotManager snapshotManager;
|
||
|
|
||
|
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();
|
||
|
deviceConnectors = new ArrayList<>();
|
||
|
applicationListeners = new LinkedList<PulsCounterApplicationListener>();
|
||
|
unseenMessages = new Vector<String>();
|
||
|
|
||
|
interfaceClasses = new ArrayList<>();
|
||
|
interfaces = 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;
|
||
|
default:
|
||
|
log(WARN,"Unknown command line parameter: %s", option);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/* Old stuff... */
|
||
|
// this.initialize();
|
||
|
}
|
||
|
|
||
|
|
||
|
private void loadApplicationConfiguration(){
|
||
|
applicationConfiguration = new Properties();
|
||
|
|
||
|
/* Initialize default configuration */
|
||
|
applicationConfiguration.setProperty("ui.class", NewMainWindow.class.getCanonicalName());
|
||
|
applicationConfiguration.setProperty("interface.classes", StringHelper.join(new String[]{ServiceLinkDeviceConnector.class.getCanonicalName() }, ","));
|
||
|
|
||
|
|
||
|
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");
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
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 void start(){
|
||
|
|
||
|
initialize();
|
||
|
|
||
|
String uiClassName = applicationConfiguration.getProperty("ui.class");
|
||
|
|
||
|
try {
|
||
|
Class uiClazz = PulsCounterApplication.class.getClassLoader().loadClass(uiClassName);
|
||
|
|
||
|
Constructor<?> constructor = uiClazz.getConstructor(PulsCounterApplication.class);
|
||
|
Object 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();
|
||
|
|
||
|
try {
|
||
|
shutdown();
|
||
|
|
||
|
} catch (Exception e){
|
||
|
log(e);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
private void initialize(){
|
||
|
|
||
|
String[] interfaceClassNames = applicationConfiguration.getProperty("interface.classes").split(",");
|
||
|
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)));
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
private void shutdown(){
|
||
|
|
||
|
log(INFO,"Application shutdown...");
|
||
|
|
||
|
|
||
|
|
||
|
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(0).getClass().getCanonicalName());
|
||
|
applicationConfiguration.setProperty(String.format("interfaces.%d.settings", n), interfaces.get(0).getConnectionSettings());
|
||
|
}
|
||
|
|
||
|
|
||
|
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");
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
this.scheduler.shutdown();
|
||
|
this.snapshotManager.doShutdown();
|
||
|
TaskletManager.instance().shutdown();
|
||
|
|
||
|
this.getServiceLink().close();
|
||
|
|
||
|
this.savePrefs();
|
||
|
*/
|
||
|
}
|
||
|
|
||
|
|
||
|
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);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/* 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 fireSerialPortChanged(){
|
||
|
for (PulsCounterApplicationListener listener: applicationListeners){
|
||
|
listener.serialPortChanged();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void fireConnectionStateChanged(){
|
||
|
fireConnectionStateChanged(getServiceLink().isOpen());
|
||
|
}
|
||
|
|
||
|
public void fireConnectionStateChanged(Boolean connected){
|
||
|
for (PulsCounterApplicationListener listener: applicationListeners){
|
||
|
listener.connectionStateChanged(connected);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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);
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
public synchronized NewSerialPort getSerialPort() {
|
||
|
if (serialPort == null){
|
||
|
serialPort = new NewSerialPort("COM1:");
|
||
|
}
|
||
|
return serialPort;
|
||
|
}
|
||
|
public synchronized void setSerialPort(NewSerialPort serialPort) {
|
||
|
if (serviceLink != null){
|
||
|
serviceLink.close();
|
||
|
serviceLink = null;
|
||
|
}
|
||
|
this.serialPort = serialPort;
|
||
|
|
||
|
getServiceLink();
|
||
|
|
||
|
fireServiceLinkChanged();
|
||
|
fireSerialPortChanged();
|
||
|
}
|
||
|
|
||
|
public synchronized ServiceLink getServiceLink() {
|
||
|
if (serviceLink == null){
|
||
|
serviceLink = new ServiceLink(getSerialPort());
|
||
|
serviceLink.getSerialPort().setTimeOut(200);
|
||
|
serviceLink.addServiceLinkListener(this);
|
||
|
}
|
||
|
return serviceLink;
|
||
|
}
|
||
|
public synchronized void setServiceLink(ServiceLink serviceLink) {
|
||
|
if (serviceLink != null){
|
||
|
serviceLink.close();
|
||
|
}
|
||
|
this.serviceLink = serviceLink;
|
||
|
|
||
|
fireServiceLinkChanged();
|
||
|
}
|
||
|
|
||
|
private Preferences getPreferencesNode(){
|
||
|
return Preferences.userNodeForPackage(getClass());
|
||
|
}
|
||
|
|
||
|
public void savePrefs(){
|
||
|
Preferences prefs = getPreferencesNode();
|
||
|
|
||
|
if (serialPort != null)
|
||
|
prefs.put("io.port", getSerialPort().getPortName());
|
||
|
|
||
|
System.out.println(String.format("savePrefs(): %d exportSettings werden gesichert.", exportSettings.size()));
|
||
|
if (exportSettings.size()>0)
|
||
|
{
|
||
|
for (int n=0;n<exportSettings.size();n++){
|
||
|
prefs.put(String.format("export.configuration.%d", n), ConfigurableObjects.getConfiguration(exportSettings.get(n)));
|
||
|
}
|
||
|
prefs.putInt("export.configurations", exportSettings.size());
|
||
|
};
|
||
|
|
||
|
Preferences nChannels = prefs.node("channels");
|
||
|
for (int n=0;n<32;n++){
|
||
|
nChannels.put(String.format("%d.description", n), channelDescriptions[n]);
|
||
|
}
|
||
|
|
||
|
try {
|
||
|
prefs.flush();
|
||
|
} catch (BackingStoreException e)
|
||
|
{
|
||
|
e.printStackTrace();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void loadPrefs(){
|
||
|
Preferences prefs = getPreferencesNode();
|
||
|
|
||
|
String sn = prefs.get("io.port", null);
|
||
|
|
||
|
if (sn != null){
|
||
|
NewSerialPort nsp = new NewSerialPort(sn);
|
||
|
setSerialPort(nsp);
|
||
|
}
|
||
|
|
||
|
exportSettings.clear();
|
||
|
int nESC = prefs.getInt("export.configurations", 0);
|
||
|
for (int n=0;n<nESC;n++){
|
||
|
ExportSetting es = new ExportSetting();
|
||
|
ConfigurableObjects.setConfiguration(es, prefs.get(String.format("export.configuration.%d", n), ""));
|
||
|
exportSettings.add(es);
|
||
|
}
|
||
|
System.out.println(String.format("loadPrefs(): %d exportSettings geladen.", nESC));
|
||
|
|
||
|
Preferences nChannels = prefs.node("channels");
|
||
|
|
||
|
for (int n=0;n<32;n++){
|
||
|
channelDescriptions[n] = nChannels.get(String.format("%d.description", n), "");
|
||
|
}
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
public String getChannelDescription(int n){
|
||
|
return ""; // channelDescriptions[n];
|
||
|
}
|
||
|
public void setChannelDescription(int n,String desc){
|
||
|
channelDescriptions[n] = desc;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void connectionStateChanged(Boolean connected) {
|
||
|
fireConnectionStateChanged(connected);
|
||
|
}
|
||
|
|
||
|
public SnapshotManager getSnapshotManager() {
|
||
|
return snapshotManager;
|
||
|
}
|
||
|
|
||
|
public List<ExportSetting> getExportSettings() {
|
||
|
return exportSettings;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
}
|