1 package de.dlr.bt.stc;
2
3 import java.awt.GraphicsEnvironment;
4 import java.io.IOException;
5 import java.nio.file.FileSystems;
6 import java.util.concurrent.atomic.AtomicBoolean;
7
8 import org.greenrobot.eventbus.EventBus;
9 import org.slf4j.LoggerFactory;
10
11 import ch.qos.logback.classic.Logger;
12 import de.dlr.bt.stc.cli.CLIOptions;
13 import de.dlr.bt.stc.init.ModuleInitializer;
14 import de.dlr.bt.stc.init.STCInstance;
15 import de.dlr.bt.stc.init.STCInstance.AddConfigurationFolder;
16 import de.dlr.bt.stc.init.STCInstance.LoadConfiguration;
17 import de.dlr.bt.stc.init.STCInstance.StartEvent;
18 import de.dlr.bt.stc.init.STCInstance.StopEvent;
19 import de.dlr.bt.stc.opcuaserver.UAServer;
20 import lombok.extern.slf4j.Slf4j;
21 import picocli.CommandLine;
22
23 @Slf4j
24 public class App {
25
26 private static final int AUTO_RESTART_TIME_MS = 2500;
27 private static final int GRACEFUL_TERMINATION_TIMEOUT = 20000;
28
29 private static final AtomicBoolean mainThreadFinished = new AtomicBoolean(false);
30
31 public static void main(String[] args) {
32
33 log.info("Starting ...");
34
35 ModuleInitializer.initialize();
36
37 final var managementEventBus = new EventBus();
38
39 CLIOptions options = new CLIOptions();
40 CommandLine cmd = new CommandLine(options);
41 cmd.parseArgs(args);
42
43 if (options.isUsageHelpRequested()) {
44 cmd.usage(System.out);
45 return;
46 }
47
48 final boolean isHeadless;
49 if (options.isForceHeadless()) {
50 isHeadless = true;
51 } else {
52 isHeadless = GraphicsEnvironment.isHeadless();
53 }
54
55 if (options.getLogLevel() != null) {
56 Logger rootLogger = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
57 rootLogger.setLevel(options.getLogLevel());
58 }
59
60 UAServer uaserver = null;
61 if (options.isRunOpcuaServer()) {
62 try {
63 uaserver = new UAServer(options.getOpcuaServerPort(), managementEventBus);
64 uaserver.startup().get();
65 } catch (InterruptedException ie) {
66 Thread.currentThread().interrupt();
67 } catch (Exception ex) {
68 log.error("Failed to start OPC/UA server!");
69 }
70 }
71
72 STCInstance instance = new STCInstance(managementEventBus);
73
74 managementEventBus
75 .post(new AddConfigurationFolder(FileSystems.getDefault().getPath(options.getConfigFolder())));
76 managementEventBus.post(new LoadConfiguration());
77 managementEventBus.post(new StartEvent(AUTO_RESTART_TIME_MS));
78
79 Runtime.getRuntime().addShutdownHook(new Thread(() -> terminateApplication(managementEventBus)));
80
81 log.info("System started, send SIGTERM or SIGINT to stop (Ctrl+C)");
82
83 if (!isHeadless) {
84 Thread consoleInput = new Thread(() -> waitForConsoleQuit(instance, managementEventBus),
85 "ConsoleStdInThread");
86 consoleInput.setDaemon(true);
87 consoleInput.start();
88 }
89
90
91 instance.run();
92
93 try {
94 if (uaserver != null)
95 uaserver.shutdown().get();
96 } catch (InterruptedException ie) {
97 Thread.currentThread().interrupt();
98 } catch (Exception ex) {
99 log.error("Failed to stop OPC/UA server!");
100 }
101 log.info("sTC finished");
102
103 mainThreadFinished.set(true);
104 synchronized (mainThreadFinished) {
105 mainThreadFinished.notifyAll();
106 }
107 }
108
109 private static void waitForConsoleQuit(STCInstance instance, EventBus managementBus) {
110 log.info("Started, press e (followed by enter) to stop");
111 while (!instance.isTerminate()) {
112 try {
113 int chr = System.in.read();
114 if (chr == 'e') {
115 terminateApplication(managementBus);
116 }
117 } catch (IOException ioe) {
118 }
119 }
120 }
121
122
123
124
125
126
127
128
129
130 private static void terminateApplication(EventBus managementBus) {
131
132 if (mainThreadFinished.get())
133 return;
134
135
136 managementBus.post(new StopEvent(true));
137
138
139 try {
140 var startTime = System.currentTimeMillis();
141 while (!mainThreadFinished.get() && System.currentTimeMillis() - startTime < GRACEFUL_TERMINATION_TIMEOUT) {
142 synchronized (mainThreadFinished) {
143 mainThreadFinished.wait(500);
144 }
145 }
146
147
148
149
150 if (!mainThreadFinished.get()) {
151 log.error("The application did not terminate within {} ms. Forcefully terminating now ...",
152 GRACEFUL_TERMINATION_TIMEOUT);
153 Runtime.getRuntime().halt(-1);
154 }
155 } catch (InterruptedException ie) {
156 log.error("Final wait has been interrupted");
157 Thread.currentThread().interrupt();
158 }
159 }
160
161 }