Skip to content

Commit b956520

Browse files
committed
when starting in prod profile, print some info to console
and also some dots!
1 parent 9179309 commit b956520

9 files changed

Lines changed: 313 additions & 125 deletions

File tree

src/main/java/de/rwth/idsg/steve/Application.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
@Slf4j
2424
public class Application {
2525

26-
public static void main(String[] args) throws IOException {
26+
public static void main(String[] args) throws Exception {
2727

2828
// For Hibernate validator
2929
System.setProperty("org.jboss.logging.provider", "slf4j");
@@ -36,15 +36,18 @@ public static void main(String[] args) throws IOException {
3636

3737
log.info("Loaded the properties. Starting with the '{}' profile", PROFILE);
3838

39-
JettyServer jettyServer = new JettyServer();
40-
jettyServer.start();
39+
if (PROFILE.isProd()) {
40+
new SteveProdStarter().start();
41+
} else {
42+
new SteveDevStarter().start();
43+
}
4144
}
4245

4346
private static void loadProperties() throws IOException {
4447
PropertiesFileLoader prop = new PropertiesFileLoader("main.properties");
4548

4649
STEVE_VERSION = prop.getString("steve.version");
47-
PROFILE = prop.getString("profile");
50+
PROFILE = ApplicationProfile.fromName(prop.getString("profile"));
4851

4952
DB.IP = prop.getString("db.ip");
5053
DB.PORT = prop.getInt("db.port");
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package de.rwth.idsg.steve;
2+
3+
/**
4+
* @author Sevket Goekay <goekay@dbis.rwth-aachen.de>
5+
* @since 05.11.2015
6+
*/
7+
public enum ApplicationProfile {
8+
DEV,
9+
PROD;
10+
11+
public static ApplicationProfile fromName(String v) {
12+
for (ApplicationProfile ap : ApplicationProfile.values()) {
13+
if (ap.name().equalsIgnoreCase(v)) {
14+
return ap;
15+
}
16+
}
17+
throw new IllegalArgumentException(v);
18+
}
19+
20+
public boolean isProd() {
21+
return this == PROD;
22+
}
23+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package de.rwth.idsg.steve;
2+
3+
/**
4+
* @author Sevket Goekay <goekay@dbis.rwth-aachen.de>
5+
* @since 05.11.2015
6+
*/
7+
public interface ApplicationStarter {
8+
void start() throws Exception;
9+
}

src/main/java/de/rwth/idsg/steve/JettyServer.java

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
import org.eclipse.jetty.util.thread.QueuedThreadPool;
1414
import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler;
1515

16-
import java.io.IOException;
1716
import java.util.concurrent.TimeUnit;
1817

1918
/**
@@ -34,7 +33,7 @@ public class JettyServer {
3433
/**
3534
* A fully configured Jetty Server instance
3635
*/
37-
public JettyServer() throws IOException {
36+
public void prepare() throws Exception {
3837

3938
// === jetty.xml ===
4039
// Setup Threadpool
@@ -119,30 +118,22 @@ private ServerConnector httpsConnector(HttpConfiguration httpConfig) {
119118
/**
120119
* Starts the Jetty Server instance
121120
*/
122-
public void start() {
123-
try {
121+
public void start() throws Exception {
122+
if (server != null) {
124123
server.start();
125-
server.join();
126-
} catch (InterruptedException ie) {
127-
log.error("Exception happened", ie);
128-
} catch (Exception e) {
129-
log.error("Failed to start Jetty server.", e);
130124
}
131125
}
132126

133127
/**
134-
* Stops the Jetty Server instance
128+
* Join the server thread with the current thread
135129
*/
136-
public void stop() {
137-
new Thread() {
138-
@Override
139-
public void run() {
140-
try {
141-
server.stop();
142-
} catch (Exception e) {
143-
log.error("Failed to stop Jetty server.", e);
144-
}
145-
}
146-
}.start();
130+
public void join() throws Exception {
131+
if (server != null) {
132+
server.join();
133+
}
134+
}
135+
136+
public boolean isStarted() {
137+
return server != null && server.isStarted();
147138
}
148139
}

src/main/java/de/rwth/idsg/steve/SteveConfiguration.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ private SteveConfiguration() { }
2727
// -------------------------------------------------------------------------
2828

2929
public static String STEVE_VERSION;
30-
public static String PROFILE;
30+
public static ApplicationProfile PROFILE;
3131

3232
/**
3333
* Jetty configuration
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package de.rwth.idsg.steve;
2+
3+
/**
4+
* ApplicationStarter for DEV profile
5+
*
6+
* @author Sevket Goekay <goekay@dbis.rwth-aachen.de>
7+
* @since 05.11.2015
8+
*/
9+
public class SteveDevStarter implements ApplicationStarter {
10+
11+
@Override
12+
public void start() throws Exception {
13+
JettyServer jettyServer = new JettyServer();
14+
jettyServer.prepare();
15+
jettyServer.start();
16+
jettyServer.join();
17+
}
18+
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
package de.rwth.idsg.steve;
2+
3+
import de.rwth.idsg.steve.utils.LogFileRetriever;
4+
import lombok.extern.slf4j.Slf4j;
5+
6+
import java.util.concurrent.TimeUnit;
7+
8+
/**
9+
* ApplicationStarter for PROD profile
10+
*
11+
* Since we log everything to a file, it can be confusing for the user to see nothing written to console, when starting
12+
* the app. So, this class prints some stuff to console.
13+
*
14+
* @author Sevket Goekay <goekay@dbis.rwth-aachen.de>
15+
* @since 05.11.2015
16+
*/
17+
@Slf4j
18+
public class SteveProdStarter implements ApplicationStarter {
19+
20+
private static final String HINT = "Hint: You can stop the application by pressing CTRL+C";
21+
private static final String REFER = "Please refer to the log file for details";
22+
23+
private Thread dotThread;
24+
25+
/**
26+
* TODO: Is this flow correct? Not sure about the error handling. Do the branches cover all situations?
27+
*/
28+
@Override
29+
public void start() throws Exception {
30+
31+
starting();
32+
JettyServer jettyServer = new JettyServer();
33+
34+
try {
35+
jettyServer.prepare();
36+
jettyServer.start();
37+
started();
38+
39+
} catch (Exception e) {
40+
41+
stopPrintingDots();
42+
log.error("Exception happened", e);
43+
44+
if (jettyServer.isStarted()) {
45+
startedWithErrors();
46+
47+
} else {
48+
failed();
49+
throw e;
50+
}
51+
}
52+
53+
jettyServer.join();
54+
}
55+
56+
// -------------------------------------------------------------------------
57+
// Private helpers
58+
// -------------------------------------------------------------------------
59+
60+
private void starting() {
61+
String msg = "Log file: "
62+
+ new LogFileRetriever().getLogFilePathOrErrorMessage()
63+
+ System.lineSeparator()
64+
+ "Starting";
65+
66+
System.out.print(msg);
67+
startPrintingDots();
68+
}
69+
70+
private void started() {
71+
stopPrintingDots();
72+
String msg = " Done!" + System.lineSeparator() + HINT;
73+
System.out.println(msg);
74+
}
75+
76+
private void startedWithErrors() {
77+
String msg = " Done, but there were some errors! " + REFER + System.lineSeparator() + HINT;
78+
System.out.println(msg);
79+
}
80+
81+
private void failed() {
82+
String msg = " FAILED!" + System.lineSeparator() + REFER;
83+
System.out.println(msg);
84+
}
85+
86+
// -------------------------------------------------------------------------
87+
// Let's print some dots
88+
// -------------------------------------------------------------------------
89+
90+
private void startPrintingDots() {
91+
dotThread = new Thread() {
92+
public void run() {
93+
try {
94+
while (!isInterrupted()) {
95+
System.out.print(".");
96+
TimeUnit.MILLISECONDS.sleep(600);
97+
}
98+
} catch (InterruptedException e) {
99+
// This is expected, since stopPrintingDots() is called. Do nothing and let the thread end.
100+
}
101+
}
102+
};
103+
104+
dotThread.start();
105+
}
106+
107+
private void stopPrintingDots() {
108+
if (dotThread != null) {
109+
dotThread.interrupt();
110+
}
111+
}
112+
}
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
package de.rwth.idsg.steve.utils;
2+
3+
import com.google.common.base.Optional;
4+
import lombok.extern.slf4j.Slf4j;
5+
import org.apache.logging.log4j.LogManager;
6+
import org.apache.logging.log4j.core.Appender;
7+
import org.apache.logging.log4j.core.LoggerContext;
8+
import org.apache.logging.log4j.core.appender.FileAppender;
9+
import org.apache.logging.log4j.core.appender.MemoryMappedFileAppender;
10+
import org.apache.logging.log4j.core.appender.RandomAccessFileAppender;
11+
import org.apache.logging.log4j.core.appender.RollingFileAppender;
12+
import org.apache.logging.log4j.core.appender.RollingRandomAccessFileAppender;
13+
import org.apache.logging.log4j.core.impl.Log4jContextFactory;
14+
import org.apache.logging.log4j.core.selector.ContextSelector;
15+
import org.apache.logging.log4j.spi.LoggerContextFactory;
16+
17+
import java.nio.file.Path;
18+
import java.nio.file.Paths;
19+
import java.util.ArrayList;
20+
import java.util.List;
21+
import java.util.Random;
22+
23+
/**
24+
* @author Sevket Goekay <goekay@dbis.rwth-aachen.de>
25+
* @since 05.11.2015
26+
*/
27+
@Slf4j
28+
public class LogFileRetriever {
29+
30+
private List<Path> logPathList;
31+
private Random random = new Random();
32+
33+
public LogFileRetriever() {
34+
logPathList = getActiveLogFilePaths();
35+
}
36+
37+
public Optional<Path> getPath() {
38+
Path p;
39+
if (logPathList.isEmpty()) {
40+
p = null;
41+
} else if (logPathList.size() == 1) {
42+
p = logPathList.get(0);
43+
} else {
44+
p = rollTheDice();
45+
}
46+
return Optional.fromNullable(p);
47+
}
48+
49+
public String getLogFilePathOrErrorMessage() {
50+
Optional<Path> p = getPath();
51+
if (p.isPresent()) {
52+
return p.get().toAbsolutePath().toString();
53+
} else {
54+
return getErrorMessage();
55+
}
56+
}
57+
58+
public String getErrorMessage() {
59+
return "Not available";
60+
}
61+
62+
// -------------------------------------------------------------------------
63+
// Private helpers
64+
// -------------------------------------------------------------------------
65+
66+
/**
67+
* If the user configured multiple file appenders, which log file should we choose?
68+
* Clearly, the only sane solution is rolling the dice.
69+
* Easter egg mode: On
70+
*/
71+
private Path rollTheDice() {
72+
log.trace("Rolling the dice...");
73+
int index = random.nextInt(logPathList.size());
74+
return logPathList.get(index);
75+
}
76+
77+
/**
78+
* We cannot presume that the default file name/location setting won't be changed by the user.
79+
* Therefore, we should be able to retrieve that info from the underlying logging mechanism
80+
* by iterating over appenders.
81+
*/
82+
private List<Path> getActiveLogFilePaths() {
83+
LoggerContextFactory factory = LogManager.getFactory();
84+
ContextSelector selector = ((Log4jContextFactory) factory).getSelector();
85+
86+
List<Path> fileNameList = new ArrayList<>();
87+
for (LoggerContext ctx : selector.getLoggerContexts()) {
88+
for (Appender appender : ctx.getConfiguration().getAppenders().values()) {
89+
String fileName = extractFileName(appender);
90+
if (fileName != null) {
91+
fileNameList.add(Paths.get(fileName));
92+
}
93+
}
94+
}
95+
return fileNameList;
96+
}
97+
98+
/**
99+
* File appender types do not share a "write-to-file" superclass.
100+
*/
101+
private String extractFileName(Appender a) {
102+
if (a instanceof FileAppender) {
103+
return ((FileAppender) a).getFileName();
104+
105+
} else if (a instanceof RollingFileAppender) {
106+
return ((RollingFileAppender) a).getFileName();
107+
108+
} else if (a instanceof RollingRandomAccessFileAppender) {
109+
return ((RollingRandomAccessFileAppender) a).getFileName();
110+
111+
} else if (a instanceof RandomAccessFileAppender) {
112+
return ((RandomAccessFileAppender) a).getFileName();
113+
114+
} else if (a instanceof MemoryMappedFileAppender) {
115+
return ((MemoryMappedFileAppender) a).getFileName();
116+
117+
} else {
118+
return null;
119+
}
120+
}
121+
}

0 commit comments

Comments
 (0)