Skip to content

Commit 01e8c49

Browse files
committed
jooby:run improvements
* Fix #396: undertow server doesnt work with jooby:run * Improve #337: redesign build tools. Now jooby:run is a lot more independent from Maven
1 parent e6d75d5 commit 01e8c49

4 files changed

Lines changed: 187 additions & 214 deletions

File tree

jooby-hotreload/src/main/java/org/jooby/hotreload/AppModule.java

Lines changed: 46 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -18,40 +18,37 @@
1818
*/
1919
package org.jooby.hotreload;
2020

21-
import java.io.BufferedReader;
2221
import java.io.File;
2322
import java.io.FileInputStream;
24-
import java.io.FileReader;
2523
import java.io.IOException;
2624
import java.io.InputStream;
27-
import java.io.InputStreamReader;
28-
import java.io.Reader;
2925
import java.lang.reflect.InvocationTargetException;
3026
import java.lang.reflect.Method;
3127
import java.nio.file.FileSystems;
3228
import java.nio.file.Path;
3329
import java.nio.file.PathMatcher;
34-
import java.nio.file.Paths;
3530
import java.nio.file.WatchEvent.Kind;
3631
import java.util.ArrayList;
3732
import java.util.Arrays;
38-
import java.util.LinkedHashSet;
3933
import java.util.List;
4034
import java.util.Map.Entry;
4135
import java.util.Properties;
42-
import java.util.Set;
4336
import java.util.concurrent.ExecutorService;
4437
import java.util.concurrent.Executors;
4538

4639
import org.jboss.modules.Module;
4740
import org.jboss.modules.ModuleClassLoader;
4841
import org.jboss.modules.ModuleIdentifier;
42+
import org.jboss.modules.log.StreamModuleLogger;
4943

5044
public class AppModule {
5145

46+
public static boolean DEBUG;
47+
48+
public static boolean TRACE;
49+
5250
private AppModuleLoader loader;
53-
private File[] dirs;
54-
private Path[] paths;
51+
private Path[] paths = {new File(System.getProperty("user.dir")).toPath() };
5552
private ExecutorService executor;
5653
private Watcher scanner;
5754
private PathMatcher includes;
@@ -61,57 +58,65 @@ public class AppModule {
6158
private String mainClass;
6259
private volatile Module module;
6360

64-
public AppModule(final String mId, final String mainClass, final String repo, final File[] dirs)
65-
throws IOException {
61+
public AppModule(final String mId, final String mainClass, final File... cp)
62+
throws Exception {
6663
this.mainClass = mainClass;
67-
loader = new AppModuleLoader(new File(repo));
64+
loader = AppModuleLoader.build(mId, mainClass, cp);
6865
this.mId = ModuleIdentifier.create(mId);
69-
this.dirs = dirs;
70-
this.paths = toPath(dirs);
7166
this.executor = Executors.newSingleThreadExecutor(task -> new Thread(task, "HotSwap"));
7267
this.scanner = new Watcher(this::onChange, paths);
7368
}
7469

7570
public static void main(final String[] args) throws Exception {
76-
setPkgs();
77-
setSystemProperties(args[2]);
7871
List<File> cp = new ArrayList<File>();
7972
String includes = "**/*.class,**/*.conf,**/*.properties,*.js, src/*.js";
8073
String excludes = "";
81-
for (int i = 3; i < args.length; i++) {
82-
File dir = new File(args[i]);
83-
if (dir.exists()) {
84-
// cp option
85-
cp.add(dir);
86-
} else {
87-
String[] option = args[i].split("=");
88-
if (option.length < 2) {
74+
for (int i = 2; i < args.length; i++) {
75+
String[] option = args[i].split("=");
76+
if (option.length < 2) {
77+
throw new IllegalArgumentException("Unknown option: " + args[i]);
78+
}
79+
String name = option[0].toLowerCase();
80+
switch (name) {
81+
case "includes":
82+
includes = option[1];
83+
break;
84+
case "excludes":
85+
excludes = option[1];
86+
break;
87+
case "props":
88+
setSystemProperties(new File(option[1]));
89+
break;
90+
case "deps":
91+
String[] deps = option[1].split(":");
92+
for (String dep : deps) {
93+
cp.add(new File(dep));
94+
}
95+
break;
96+
default:
8997
throw new IllegalArgumentException("Unknown option: " + args[i]);
90-
}
91-
String name = option[0].toLowerCase();
92-
switch (name) {
93-
case "includes":
94-
includes = option[1];
95-
break;
96-
case "excludes":
97-
excludes = option[1];
98-
break;
99-
default:
100-
throw new IllegalArgumentException("Unknown option: " + args[i]);
101-
}
10298
}
10399
}
100+
// set log level, once we call setSystemProps
101+
DEBUG = Integer.getInteger("logLevel", 2) == 1;
102+
TRACE = Integer.getInteger("logLevel", 2) == 0;
103+
104104
if (cp.isEmpty()) {
105105
cp.add(new File(System.getProperty("user.dir")));
106106
}
107-
AppModule launcher = new AppModule(args[0], args[1], args[2], cp.toArray(new File[cp.size()]))
107+
108+
if (TRACE) {
109+
Module.setModuleLogger(new StreamModuleLogger(System.out));
110+
}
111+
112+
AppModule launcher = new AppModule(args[0], args[1], cp.toArray(new File[cp.size()]))
108113
.includes(includes)
109114
.excludes(excludes);
110115
launcher.run();
111116
}
112117

113-
private static void setSystemProperties(final String repo) throws IOException {
114-
try (InputStream in = new FileInputStream(new File(repo, "sys.properties"))) {
118+
private static void setSystemProperties(final File sysprops) throws IOException {
119+
try (InputStream in = new FileInputStream(sysprops)) {
115120
Properties properties = new Properties();
116121
properties.load(in);
117122
for (Entry<Object, Object> prop : properties.entrySet()) {
@@ -126,46 +131,8 @@ private static void setSystemProperties(final String repo) throws IOException {
126131
}
127132
}
128133

129-
private static void setPkgs() throws IOException {
130-
Set<String> pkgs = pkgs(new InputStreamReader(AppModule.class.getResourceAsStream("pkgs")));
131-
132-
/**
133-
* Hack to let users to configure system packages, javax.transaction cause issues with
134-
* hibernate.
135-
*/
136-
pkgs.addAll(pkgs(Paths.get("src", "etc", "jboss-modules", "pkgs.includes").toFile()));
137-
138-
pkgs.removeAll(pkgs(Paths.get("src", "etc", "jboss-modules", "pkgs.excludes").toFile()));
139-
140-
StringBuilder sb = new StringBuilder();
141-
for (String pkg : pkgs) {
142-
sb.append(pkg).append(',');
143-
}
144-
sb.setLength(sb.length() - 1);
145-
System.setProperty("jboss.modules.system.pkgs", sb.toString());
146-
}
147-
148-
private static Set<String> pkgs(final File file) throws IOException {
149-
if (file.exists()) {
150-
return pkgs(new FileReader(file));
151-
}
152-
return new LinkedHashSet<String>();
153-
}
154-
155-
private static Set<String> pkgs(final Reader reader) throws IOException {
156-
try (BufferedReader in = new BufferedReader(reader)) {
157-
Set<String> pkgs = new LinkedHashSet<String>();
158-
String line = in.readLine();
159-
while (line != null) {
160-
pkgs.add(line.trim());
161-
line = in.readLine();
162-
}
163-
return pkgs;
164-
}
165-
}
166-
167134
public void run() {
168-
System.out.printf("Hotswap available on: %s%n", Arrays.toString(dirs));
135+
System.out.printf("Hotswap available on: %s%n", Arrays.toString(paths));
169136
System.out.printf(" includes: %s%n", includes);
170137
System.out.printf(" excludes: %s%n", excludes);
171138

@@ -257,14 +224,6 @@ private Path relativePath(final Path path) {
257224
return null;
258225
}
259226

260-
private static Path[] toPath(final File[] cp) {
261-
Path[] paths = new Path[cp.length];
262-
for (int i = 0; i < paths.length; i++) {
263-
paths[i] = cp[i].toPath();
264-
}
265-
return paths;
266-
}
267-
268227
private static PathMatcher pathMatcher(final String expressions) {
269228
List<PathMatcher> matchers = new ArrayList<PathMatcher>();
270229
for (String expression : expressions.split(",")) {
@@ -288,4 +247,5 @@ public String toString() {
288247
}
289248
};
290249
}
250+
291251
}

jooby-hotreload/src/main/java/org/jooby/hotreload/AppModuleLoader.java

Lines changed: 125 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,24 +18,143 @@
1818
*/
1919
package org.jooby.hotreload;
2020

21+
import java.io.BufferedReader;
2122
import java.io.File;
23+
import java.io.FileReader;
24+
import java.io.IOException;
25+
import java.io.InputStreamReader;
26+
import java.io.Reader;
27+
import java.lang.reflect.Field;
28+
import java.nio.file.Paths;
29+
import java.util.HashMap;
30+
import java.util.LinkedHashSet;
31+
import java.util.Map;
32+
import java.util.Set;
33+
import java.util.jar.JarFile;
2234

23-
import org.jboss.modules.LocalModuleFinder;
35+
import org.jboss.modules.DependencySpec;
2436
import org.jboss.modules.Module;
25-
import org.jboss.modules.ModuleFinder;
37+
import org.jboss.modules.ModuleIdentifier;
38+
import org.jboss.modules.ModuleLoadException;
2639
import org.jboss.modules.ModuleLoader;
27-
import org.jboss.modules.filter.PathFilters;
40+
import org.jboss.modules.ModuleSpec;
41+
import org.jboss.modules.ResourceLoaderSpec;
42+
import org.jboss.modules.ResourceLoaders;
2843

2944
public class AppModuleLoader extends ModuleLoader {
3045

31-
public AppModuleLoader(final File repo) {
32-
super(new ModuleFinder[]{
33-
new LocalModuleFinder(new File[]{repo }, PathFilters.acceptAll()) });
46+
private Map<ModuleIdentifier, ModuleSpec> modules;
47+
48+
public AppModuleLoader(final Map<ModuleIdentifier, ModuleSpec> modules) {
49+
this.modules = modules;
50+
}
51+
52+
@Override
53+
protected ModuleSpec findModule(final ModuleIdentifier moduleId) throws ModuleLoadException {
54+
ModuleSpec mod = modules.get(moduleId);
55+
return mod == null ? super.findModule(moduleId) : mod;
3456
}
3557

3658
public void unload(final Module module) {
3759
super.unloadModuleLocal(module);
3860
}
3961

62+
/**
63+
* Build a flat jboss module, with some minor exceptions (like j2v8).
64+
*
65+
* @param name module name.
66+
* @param mainClass
67+
* @param cp
68+
* @return
69+
* @throws Exception
70+
*/
71+
public static AppModuleLoader build(final String name, final String mainClass, final File... cp)
72+
throws Exception {
73+
Map<ModuleIdentifier, ModuleSpec> modules = newModule(name, mainClass, cp);
74+
return new AppModuleLoader(modules);
75+
}
76+
77+
private static Map<ModuleIdentifier, ModuleSpec> newModule(final String name,
78+
final String mainClass, final File... cp)
79+
throws Exception {
80+
Map<ModuleIdentifier, ModuleSpec> modules = new HashMap<>();
81+
82+
ModuleSpec.Builder builder = ModuleSpec.build(ModuleIdentifier.fromString(name));
83+
84+
for (File file : cp) {
85+
if (AppModule.DEBUG) {
86+
System.out.println("adding " + file);
87+
}
88+
if (file.getName().startsWith("j2v8") && !name.equals(file.getName())) {
89+
ModuleSpec dependency = newModule(file.getName(), null, file).values().iterator().next();
90+
builder.addDependency(
91+
DependencySpec.createModuleDependencySpec(dependency.getModuleIdentifier()));
92+
modules.put(dependency.getModuleIdentifier(), dependency);
93+
} else {
94+
if (file.getName().endsWith(".jar")) {
95+
builder.addResourceRoot(ResourceLoaderSpec
96+
.createResourceLoaderSpec(ResourceLoaders
97+
.createJarResourceLoader(file.getName(), new JarFile(file))));
98+
} else {
99+
builder.addResourceRoot(ResourceLoaderSpec
100+
.createResourceLoaderSpec(ResourceLoaders
101+
.createFileResourceLoader(file.getName(), file)));
102+
}
103+
}
104+
}
105+
Set<String> jdkPaths = sysPaths();
106+
builder.addDependency(DependencySpec.createSystemDependencySpec(jdkPaths));
107+
builder.addDependency(DependencySpec.createLocalDependencySpec());
108+
109+
if (mainClass != null) {
110+
builder.setMainClass(mainClass);
111+
}
112+
113+
ModuleSpec module = builder.create();
114+
modules.put(module.getModuleIdentifier(), builder.create());
115+
return modules;
116+
}
117+
118+
@SuppressWarnings({"rawtypes", "unchecked" })
119+
private static Set<String> jdkPaths() throws Exception {
120+
Class jdkPath = AppModuleLoader.class.getClassLoader().loadClass("org.jboss.modules.JDKPaths");
121+
Field field = jdkPath.getDeclaredField("JDK");
122+
field.setAccessible(true);
123+
return (Set<String>) field.get(null);
124+
}
125+
126+
private static Set<String> sysPaths() throws Exception {
127+
Set<String> pkgs = new LinkedHashSet<>();
128+
129+
pkgs.addAll(jdkPaths());
130+
pkgs.addAll(pkgs(new InputStreamReader(AppModule.class.getResourceAsStream("pkgs"))));
131+
132+
/**
133+
* Hack to let users to configure system packages, javax.transaction cause issues with
134+
* hibernate.
135+
*/
136+
pkgs.addAll(pkgs(Paths.get("src", "etc", "jboss-modules", "pkgs.includes").toFile()));
137+
138+
pkgs.removeAll(pkgs(Paths.get("src", "etc", "jboss-modules", "pkgs.excludes").toFile()));
139+
return pkgs;
140+
}
141+
142+
private static Set<String> pkgs(final File file) throws IOException {
143+
if (file.exists()) {
144+
return pkgs(new FileReader(file));
145+
}
146+
return new LinkedHashSet<String>();
147+
}
40148

149+
private static Set<String> pkgs(final Reader reader) throws IOException {
150+
try (BufferedReader in = new BufferedReader(reader)) {
151+
Set<String> pkgs = new LinkedHashSet<String>();
152+
String line = in.readLine();
153+
while (line != null) {
154+
pkgs.add(line.trim());
155+
line = in.readLine();
156+
}
157+
return pkgs;
158+
}
159+
}
41160
}

jooby-hotreload/src/main/resources/org/jooby/hotreload/pkgs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -939,5 +939,4 @@ jdk.nashorn.internal.tools.resources
939939
jdk.internal.dynalink
940940
jdk.internal.dynalink.beans
941941
jdk.internal.dynalink.linker
942-
jdk.internal.dynalink.support
943-
META-INF.services
942+
jdk.internal.dynalink.support

0 commit comments

Comments
 (0)