Skip to content

Commit 2c37e45

Browse files
committed
Jooby.run: static bootstrap method fix jooby-project#296
1 parent f374d55 commit 2c37e45

10 files changed

Lines changed: 554 additions & 37 deletions

File tree

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
package org.jooby.js;
22

3+
import java.io.File;
34
import java.nio.file.Paths;
45

6+
import org.jooby.Jooby;
57
import org.jooby.internal.js.JsJooby;
68

79
public class JsApp {
810

911
public static void main(final String[] args) throws Exception {
10-
new JsJooby().run(Paths.get("src", "test", "resources", "org", "jooby", "js", "app.js")
11-
.toFile()).start();
12+
File appjs = Paths.get("src", "test", "resources", "org", "jooby", "js", "app.js")
13+
.toFile();
14+
Jooby.run(new JsJooby().run(appjs), args);
1215
}
1316
}

coverage-report/src/test/java/org/jooby/js/JsAppFeature.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.jooby.js;
22

33
import java.io.File;
4+
import java.io.InputStreamReader;
45
import java.nio.file.Paths;
56

67
import org.jooby.Jooby;
@@ -20,7 +21,7 @@ public void appfile() throws Exception {
2021
}
2122

2223
private void run(final String filename) throws Exception {
23-
new JsJooby().run(getClass().getResourceAsStream(filename));
24+
new JsJooby().run(new InputStreamReader(getClass().getResourceAsStream(filename))).get();
2425
}
2526

2627
private void run(final File filename) throws Exception {

jooby-archetype/src/main/resources/archetype-resources/src/main/java/App.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ public class App extends Jooby {
1212
}
1313

1414
public static void main(final String[] args) throws Exception {
15-
new App().start(args);
15+
run(App::new, args);
1616
}
1717

1818
}

jooby/src/main/java/org/jooby/Jooby.java

Lines changed: 103 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@
7979
import java.util.function.Consumer;
8080
import java.util.function.Function;
8181
import java.util.function.Predicate;
82+
import java.util.function.Supplier;
8283
import java.util.stream.Collectors;
8384

8485
import javax.inject.Singleton;
@@ -141,6 +142,8 @@
141142
import com.typesafe.config.ConfigValue;
142143
import com.typesafe.config.ConfigValueFactory;
143144

145+
import javaslang.control.Try;
146+
144147
/**
145148
* <h1>Getting Started:</h1>
146149
* <p>
@@ -477,15 +480,8 @@ public EnvDep(final Predicate<String> predicate, final Consumer<Config> callback
477480
// set pid as system property
478481
String pid = System.getProperty("pid", JvmInfo.pid() + "");
479482
System.setProperty("pid", pid);
480-
481-
// Avoid warning message from logback when multiples files are present
482-
String logback = System.getProperty("logback.configurationFile", "logback.xml");
483-
System.setProperty("logback.configurationFile", logback);
484483
}
485484

486-
/** The logging system. */
487-
private final Logger log = LoggerFactory.getLogger(getClass());
488-
489485
/**
490486
* Keep track of routes.
491487
*/
@@ -3098,6 +3094,67 @@ public WebSocket.Definition ws(final String path,
30983094
return ws;
30993095
}
31003096

3097+
/**
3098+
* <h1>Bootstrap</h1>
3099+
* <p>
3100+
* The bootstrap process is defined as follows:
3101+
* </p>
3102+
* <h2>1. Configuration files (first-listed are higher priority)</h2>
3103+
* <ol>
3104+
* <li>System properties</li>
3105+
* <li>Application properties: {@code application.conf} or custom, see {@link #use(Config)}</li>
3106+
* <li>{@link Jooby.Module Modules} properties</li>
3107+
* </ol>
3108+
*
3109+
* <h2>2. Dependency Injection and {@link Jooby.Module modules}</h2>
3110+
* <ol>
3111+
* <li>An {@link Injector Guice Injector} is created.</li>
3112+
* <li>It calls to {@link Jooby.Module#configure(Env, Config, Binder)} for each module.</li>
3113+
* <li>At this point Guice is ready and all the services has been binded.</li>
3114+
* <li>A web server is started</li>
3115+
* </ol>
3116+
*
3117+
* @param app App creator.
3118+
* @param args App arguments.
3119+
* @throws Exception If something fails to start.
3120+
*/
3121+
public static void run(final Supplier<? extends Jooby> app, final String... args)
3122+
throws Exception {
3123+
Config conf = ConfigFactory.systemProperties()
3124+
.withFallback(args(args));
3125+
System.setProperty("logback.configurationFile", logback(conf));
3126+
app.get().start(args);
3127+
}
3128+
3129+
/**
3130+
* <h1>Bootstrap</h1>
3131+
* <p>
3132+
* The bootstrap process is defined as follows:
3133+
* </p>
3134+
* <h2>1. Configuration files (first-listed are higher priority)</h2>
3135+
* <ol>
3136+
* <li>System properties</li>
3137+
* <li>Application properties: {@code application.conf} or custom, see {@link #use(Config)}</li>
3138+
* <li>{@link Jooby.Module Modules} properties</li>
3139+
* </ol>
3140+
*
3141+
* <h2>2. Dependency Injection and {@link Jooby.Module modules}</h2>
3142+
* <ol>
3143+
* <li>An {@link Injector Guice Injector} is created.</li>
3144+
* <li>It calls to {@link Jooby.Module#configure(Env, Config, Binder)} for each module.</li>
3145+
* <li>At this point Guice is ready and all the services has been binded.</li>
3146+
* <li>A web server is started</li>
3147+
* </ol>
3148+
*
3149+
* @param app App creator.
3150+
* @param args App arguments.
3151+
* @throws Exception If something fails to start.
3152+
*/
3153+
public static void run(final Class<? extends Jooby> app, final String... args)
3154+
throws Exception {
3155+
run(() -> Try.of(() -> app.newInstance()).get(), args);
3156+
}
3157+
31013158
/**
31023159
* <h1>Bootstrap</h1>
31033160
* <p>
@@ -3214,6 +3271,7 @@ public void start(final String[] args, final Consumer<List<Route.Definition>> ro
32143271

32153272
Config config = injector.getInstance(Config.class);
32163273

3274+
Logger log = LoggerFactory.getLogger(getClass());
32173275
log.debug("config tree:\n{}", configTree(config.origin().description()));
32183276

32193277
// Start server
@@ -3249,7 +3307,7 @@ public static void main(final String[] jsargs) throws Exception {
32493307
System.arraycopy(jsargs, 1, args, 0, args.length);
32503308
}
32513309
String filename = jsargs.length > 0 ? jsargs[0] : "app.js";
3252-
new JsJooby().run(new File(filename)).start(args);
3310+
run(new JsJooby().run(new File(filename)), args);
32533311
}
32543312

32553313
private String configTree(final String description) {
@@ -3588,6 +3646,7 @@ public void stop() {
35883646
if (injector != null) {
35893647
stopManaged(injector, onStop);
35903648

3649+
Logger log = LoggerFactory.getLogger(getClass());
35913650
try {
35923651
Server server = injector.getInstance(Server.class);
35933652
String serverName = server.getClass().getSimpleName().replace("Server", "").toLowerCase();
@@ -3721,17 +3780,18 @@ private Config modeConfig(final Config source, final String env) {
37213780
* @param fname A file name.
37223781
* @return A config for the file name.
37233782
*/
3724-
private Config fileConfig(final String fname) {
3725-
File froot = new File(fname);
3726-
File fconfig = new File("conf", fname);
3727-
Config config = ConfigFactory.empty();
3783+
static Config fileConfig(final String fname) {
3784+
File dir = new File(System.getProperty("user.dir"));
3785+
File froot = new File(dir, fname);
37283786
if (froot.exists()) {
3729-
config = config.withFallback(ConfigFactory.parseFile(froot));
3730-
}
3731-
if (fconfig.exists()) {
3732-
config = config.withFallback(ConfigFactory.parseFile(fconfig));
3787+
return ConfigFactory.parseFile(froot);
3788+
} else {
3789+
File fconfig = new File(new File(dir, "conf"), fname);
3790+
if (fconfig.exists()) {
3791+
return ConfigFactory.parseFile(fconfig);
3792+
}
37333793
}
3734-
return config;
3794+
return ConfigFactory.empty();
37353795
}
37363796

37373797
/**
@@ -3857,4 +3917,30 @@ private static Predicate<String> envpredicate(final String candidate) {
38573917
return env -> env.equalsIgnoreCase(candidate) || candidate.equals("*");
38583918
}
38593919

3920+
static String logback(final Config conf) {
3921+
// Avoid warning message from logback when multiples files are present
3922+
String logback;
3923+
if (conf.hasPath("logback.configurationFile")) {
3924+
logback = conf.getString("logback.configurationFile");
3925+
} else {
3926+
ImmutableList.Builder<File> files = ImmutableList.builder();
3927+
File userdir = new File(System.getProperty("user.dir"));
3928+
File confdir = new File(userdir, "conf");
3929+
if (conf.hasPath("application.env")) {
3930+
String env = conf.getString("application.env");
3931+
files.add(new File(userdir, "logback." + env + ".xml"));
3932+
files.add(new File(confdir, "logback." + env + ".xml"));
3933+
}
3934+
files.add(new File(userdir, "logback.xml"));
3935+
files.add(new File(confdir, "logback.xml"));
3936+
logback = files.build()
3937+
.stream()
3938+
.filter(f -> f.exists())
3939+
.map(f -> f.getAbsolutePath())
3940+
.findFirst()
3941+
.orElse("logback.xml");
3942+
}
3943+
return logback;
3944+
}
3945+
38603946
}

jooby/src/main/java/org/jooby/internal/js/JsJooby.java

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.io.InputStreamReader;
2525
import java.io.Reader;
2626
import java.nio.charset.StandardCharsets;
27+
import java.util.function.Supplier;
2728

2829
import javax.script.ScriptEngine;
2930
import javax.script.ScriptEngineManager;
@@ -32,28 +33,34 @@
3233

3334
import com.google.common.io.Closeables;
3435

36+
import javaslang.control.Try;
37+
3538
public class JsJooby {
3639

3740
private ScriptEngine engine;
3841

3942
public JsJooby() throws Exception {
4043
ScriptEngineManager sem = new ScriptEngineManager();
4144
engine = sem.getEngineByName("nashorn");
42-
run(Jooby.class.getResourceAsStream("/org/jooby/jooby.js"));
45+
eval(Jooby.class.getResourceAsStream("/org/jooby/jooby.js"));
4346
}
4447

45-
public Jooby run(final File file) throws Exception {
48+
public Supplier<Jooby> run(final File file) throws Exception {
4649
return run(new FileReader(file));
4750
}
4851

49-
public Jooby run(final InputStream stream) throws Exception {
50-
return run(new InputStreamReader(stream, StandardCharsets.UTF_8));
52+
public Supplier<Jooby> run(final Reader reader) throws Exception {
53+
eval(reader);
54+
return () -> Try.of(() -> (Jooby) engine.eval("this.__jooby_ && this.__jooby_()")).get();
55+
}
56+
57+
void eval(final InputStream stream) throws Exception {
58+
eval(new InputStreamReader(stream, StandardCharsets.UTF_8));
5159
}
5260

53-
public Jooby run(final Reader reader) throws Exception {
61+
void eval(final Reader reader) throws Exception {
5462
try {
55-
engine.eval(reader);
56-
return (Jooby) engine.eval("this.__jooby_ && this.__jooby_()");
63+
engine.eval(reader);
5764
} finally {
5865
Closeables.closeQuietly(reader);
5966
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
package org.jooby;
2+
3+
import static org.easymock.EasyMock.expect;
4+
import static org.junit.Assert.assertEquals;
5+
6+
import java.io.File;
7+
8+
import org.jooby.test.MockUnit;
9+
import org.junit.Test;
10+
import org.junit.runner.RunWith;
11+
import org.powermock.core.classloader.annotations.PrepareForTest;
12+
import org.powermock.modules.junit4.PowerMockRunner;
13+
14+
import com.typesafe.config.Config;
15+
import com.typesafe.config.ConfigFactory;
16+
17+
@RunWith(PowerMockRunner.class)
18+
@PrepareForTest({Jooby.class, File.class, ConfigFactory.class })
19+
public class FileConfTest {
20+
21+
@Test
22+
public void rootFile() throws Exception {
23+
Config conf = ConfigFactory.empty();
24+
new MockUnit()
25+
.expect(unit -> {
26+
unit.mockStatic(ConfigFactory.class);
27+
})
28+
.expect(unit -> {
29+
File dir = unit.constructor(File.class)
30+
.args(String.class)
31+
.build(System.getProperty("user.dir"));
32+
33+
File root = unit.constructor(File.class)
34+
.args(File.class, String.class)
35+
.build(dir, "app.conf");
36+
expect(root.exists()).andReturn(true);
37+
38+
expect(ConfigFactory.parseFile(root)).andReturn(conf);
39+
})
40+
.run(unit -> {
41+
assertEquals(conf, Jooby.fileConfig("app.conf"));
42+
});
43+
}
44+
45+
@Test
46+
public void confFile() throws Exception {
47+
Config conf = ConfigFactory.empty();
48+
new MockUnit()
49+
.expect(unit -> {
50+
unit.mockStatic(ConfigFactory.class);
51+
})
52+
.expect(unit -> {
53+
File dir = unit.constructor(File.class)
54+
.args(String.class)
55+
.build(System.getProperty("user.dir"));
56+
57+
File root = unit.constructor(File.class)
58+
.args(File.class, String.class)
59+
.build(dir, "app.conf");
60+
expect(root.exists()).andReturn(false);
61+
62+
File cdir = unit.constructor(File.class)
63+
.args(File.class, String.class)
64+
.build(dir, "conf");
65+
66+
File cfile = unit.constructor(File.class)
67+
.args(File.class, String.class)
68+
.build(cdir, "app.conf");
69+
expect(cfile.exists()).andReturn(true);
70+
71+
expect(ConfigFactory.parseFile(cfile)).andReturn(conf);
72+
})
73+
.run(unit -> {
74+
assertEquals(conf, Jooby.fileConfig("app.conf"));
75+
});
76+
}
77+
78+
@Test
79+
public void empty() throws Exception {
80+
Config conf = ConfigFactory.empty();
81+
new MockUnit()
82+
.expect(unit -> {
83+
unit.mockStatic(ConfigFactory.class);
84+
})
85+
.expect(unit -> {
86+
File dir = unit.constructor(File.class)
87+
.args(String.class)
88+
.build(System.getProperty("user.dir"));
89+
90+
File root = unit.constructor(File.class)
91+
.args(File.class, String.class)
92+
.build(dir, "app.conf");
93+
expect(root.exists()).andReturn(false);
94+
95+
File cdir = unit.constructor(File.class)
96+
.args(File.class, String.class)
97+
.build(dir, "conf");
98+
99+
File cfile = unit.constructor(File.class)
100+
.args(File.class, String.class)
101+
.build(cdir, "app.conf");
102+
expect(cfile.exists()).andReturn(false);
103+
104+
expect(ConfigFactory.empty()).andReturn(conf);
105+
})
106+
.run(unit -> {
107+
assertEquals(conf, Jooby.fileConfig("app.conf"));
108+
});
109+
}
110+
111+
}

0 commit comments

Comments
 (0)