Skip to content

Commit 7c1bb85

Browse files
committed
Add debugging info to Env reduce memory usage by using delegation
1 parent 38aa9de commit 7c1bb85

4 files changed

Lines changed: 122 additions & 55 deletions

File tree

examples/src/main/java/examples/HelloApp.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,6 @@ public Message(String message) {
113113
}
114114

115115
public static void main(String[] args) {
116-
run(HelloApp::new);
116+
run(HelloApp::new, args);
117117
}
118118
}

jooby/src/main/java/io/jooby/Env.java

Lines changed: 115 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,48 @@
77
import java.nio.file.Files;
88
import java.nio.file.Path;
99
import java.nio.file.Paths;
10+
import java.util.ArrayList;
11+
import java.util.Arrays;
1012
import java.util.Collections;
1113
import java.util.HashMap;
1214
import java.util.LinkedHashMap;
1315
import java.util.LinkedList;
1416
import java.util.List;
1517
import java.util.Map;
1618
import java.util.Properties;
19+
import java.util.concurrent.atomic.AtomicReference;
20+
import java.util.function.BiFunction;
21+
import java.util.function.Consumer;
1722
import java.util.stream.Stream;
1823

1924
public class Env extends Value.Object {
2025

26+
public static class PropertySource {
27+
private String name;
28+
29+
private Map<String, String> properties;
30+
31+
public PropertySource(String name, Map properties) {
32+
this.name = name;
33+
this.properties = properties;
34+
}
35+
36+
public String name() {
37+
return name;
38+
}
39+
40+
public Map<String, String> properties() {
41+
return properties;
42+
}
43+
44+
@Override public String toString() {
45+
return name;
46+
}
47+
}
48+
2149
private final String name;
2250

23-
private final Map<String, String> properties = new LinkedHashMap<>();
51+
private final List<PropertySource> sources = new ArrayList<>();
2452

2553
public Env(final String name) {
2654
this.name = name;
@@ -30,9 +58,9 @@ public Env(final String name) {
3058
Value result = super.get(name);
3159
if (result.isMissing()) {
3260
// fallback to full path access
33-
String value = properties.get(name);
61+
String value = fromSource(sources, name, null);
3462
if (value != null) {
35-
result = Value.value(name, value);
63+
return Value.value(name, value);
3664
}
3765
}
3866
return result;
@@ -42,9 +70,21 @@ public Env(final String name) {
4270
return name;
4371
}
4472

45-
public static Map<String, String> parse(String... args) {
73+
@Override public String toString() {
74+
StringBuilder buff = new StringBuilder();
75+
buff.append(name).append("\n");
76+
String indent = " ";
77+
for (int i = sources.size() - 1; i >= 0; i--) {
78+
String sname = sources.get(i).name;
79+
buff.append(indent).append("::").append(sname).append("\n");
80+
indent += " ";
81+
}
82+
return buff.toString().trim();
83+
}
84+
85+
public static PropertySource parse(String... args) {
4686
if (args == null || args.length == 0) {
47-
return Collections.emptyMap();
87+
return new PropertySource("args", Collections.emptyMap());
4888
}
4989
Map<String, String> conf = new HashMap<>();
5090
for (String arg : args) {
@@ -56,25 +96,28 @@ public static Map<String, String> parse(String... args) {
5696
conf.putIfAbsent("application.env", arg);
5797
}
5898
}
59-
return conf;
99+
return new PropertySource("args", conf);
60100
}
61101

62-
public static Map<String, String> load(ClassLoader loader, String filename) {
63-
return load(loader, filename, stream -> {
64-
Map<String, String> result = new LinkedHashMap<>();
65-
Properties properties = new Properties();
66-
properties.load(stream);
67-
properties.forEach((k, v) -> result.put(k.toString(), v.toString()));
68-
return result;
102+
public static PropertySource load(ClassLoader loader, String filename) {
103+
return load(loader, filename, (name, stream) -> {
104+
try {
105+
Properties properties = new Properties();
106+
properties.load(stream);
107+
return new PropertySource(name, properties);
108+
} catch (IOException x) {
109+
throw Throwing.sneakyThrow(x);
110+
}
69111
});
70112
}
71113

72-
public static Map<String, String> load(ClassLoader loader, String filename,
73-
Throwing.Function<InputStream, Map<String, String>> propertyLoader) {
74-
InputStream stream = findProperties(loader, filename);
114+
public static PropertySource load(ClassLoader loader, String filename,
115+
BiFunction<String, InputStream, PropertySource> propertyLoader) {
116+
AtomicReference<String> fullpath = new AtomicReference<>();
117+
InputStream stream = findProperties(loader, filename, fullpath::set);
75118
if (stream != null) {
76119
try {
77-
return propertyLoader.apply(stream);
120+
return propertyLoader.apply(fullpath.get(), stream);
78121
} finally {
79122
try {
80123
stream.close();
@@ -83,68 +126,90 @@ public static Map<String, String> load(ClassLoader loader, String filename,
83126
}
84127
}
85128
}
86-
return Collections.emptyMap();
129+
return new PropertySource(filename, Collections.emptyMap());
130+
}
131+
132+
public static PropertySource systemProperties() {
133+
return new PropertySource("systemProperties", System.getProperties());
134+
}
135+
136+
public static PropertySource systemEnv() {
137+
return new PropertySource("systemEnv", System.getenv());
87138
}
88139

89140
public static Env defaultEnvironment(String... args) {
90141
ClassLoader classLoader = Env.class.getClassLoader();
91-
Map<String, String> argMap = parse(args);
92-
String env = argMap.getOrDefault("application.env", "dev");
93-
List<Map> sources = new LinkedList<>();
142+
PropertySource argMap = parse(args);
143+
String env = argMap.properties.getOrDefault("application.env", "dev");
144+
List<PropertySource> sources = new LinkedList<>();
94145
Stream
95146
.of("application.properties", "application." + env + ".properties")
96147
.map(filename -> load(classLoader, filename))
97-
.filter(props -> props.size() > 0)
148+
.filter(props -> props.properties().size() > 0)
98149
.forEach(sources::add);
99-
sources.add(System.getProperties());
100-
sources.add(System.getenv());
101-
if (argMap.size() > 0) {
102-
sources.add(argMap);
103-
}
104-
return build(sources.toArray(new Map[sources.size()]));
150+
sources.add(systemProperties());
151+
sources.add(systemEnv());
152+
sources.add(argMap);
153+
return build(sources.toArray(new PropertySource[sources.size()]));
105154
}
106155

107-
public static Env build(Map<String, String>... sources) {
108-
Env env = new Env(environmentName(sources));
109-
for (Map<String, String> source : sources) {
110-
env.properties.putAll(source);
156+
public static Env build(PropertySource... sources) {
157+
Env env = new Env(fromSource(Arrays.asList(sources), "application.env", "dev").toLowerCase());
158+
/** Merge to build values: */
159+
Map<String, String> merged = new LinkedHashMap<>();
160+
for (PropertySource source : sources) {
161+
merged.putAll(source.properties);
111162
}
112-
env.properties.forEach((k, v) -> {
113-
try {
114-
String[] values = v.split(",");
115-
for (String value : values) {
116-
env.put(k, value.trim());
163+
List<String> skip = Arrays.asList("java.", "sun.");
164+
merged.forEach((k, v) -> {
165+
if (skip.stream().anyMatch(it -> !it.startsWith(k))) {
166+
// ignore java. and sun. properties (too many, not worth it)
167+
try {
168+
String[] values = v.split(",");
169+
for (String value : values) {
170+
env.put(k, value.trim());
171+
}
172+
} catch (ClassCastException x) {
173+
// Caused by system properties like:
174+
// java.vendor.url vs java.vendor.url.bug
117175
}
118-
} catch (ClassCastException x) {
119-
// Caused by system properties like:
120-
// java.vendor.url vs java.vendor.url.bug
121176
}
122177
});
178+
// Only worth it property from java.*
179+
env.put("java.io.tmpdir", System.getProperty("java.io.tmpdir"));
180+
181+
merged.clear();
182+
183+
/** Add sources */
184+
Stream.of(sources).forEach(env.sources::add);
123185
return env;
124186
}
125187

126-
private static InputStream findProperties(ClassLoader loader, String filename) {
188+
private static InputStream findProperties(ClassLoader loader, String filename,
189+
Consumer<String> fullpath) {
127190
try {
128191
String envdir = System.getProperty("env.dir", "conf");
129192
Path file = Paths.get(System.getProperty("user.dir"), envdir, filename).toAbsolutePath();
130193
if (Files.exists(file)) {
194+
fullpath.accept(file.toString());
131195
return new FileInputStream(file.toFile());
132196
}
133-
return loader.getResourceAsStream(envdir + "/" + filename);
197+
String resource = envdir + "/" + filename;
198+
fullpath.accept(resource);
199+
return loader.getResourceAsStream(resource);
134200
} catch (IOException x) {
135201
throw Throwing.sneakyThrow(x);
136202
}
137203
}
138204

139-
private static String environmentName(Map<String, String>[] sources) {
140-
for (int i = sources.length - 1; i >= 0; i--) {
141-
Map<String, String> properties = sources[i];
142-
String name = properties.get("application.env");
143-
if (name != null) {
144-
return name.toLowerCase();
205+
private static String fromSource(List<PropertySource> sources, String name, String defaults) {
206+
for (int i = sources.size() - 1; i >= 0; i--) {
207+
PropertySource source = sources.get(i);
208+
String value = source.properties().get(name);
209+
if (value != null) {
210+
return value;
145211
}
146212
}
147-
return "dev";
213+
return defaults;
148214
}
149-
150215
}

jooby/src/main/java/io/jooby/Jooby.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ public Jooby start(Server server) {
240240
/** Start router: */
241241
ensureTmpdir(tmpdir);
242242
Logger log = log();
243+
log.debug("environment:\n{}", environment);
243244
router.start(this);
244245
log.info("{} [{}@{}]\n\n{}\n\nlistening on:\n http://localhost:{}{}\n",
245246
getClass().getSimpleName(),

jooby/src/test/java/io/jooby/EnvTest.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,12 @@ public void defaultEnv() {
3838

3939
@Test
4040
public void args() {
41-
Map<String, String> args = Env.parse("foo", " bar = ");
42-
assertEquals(Map.of("application.env", "foo", "bar", ""), args);
41+
Env.PropertySource args = Env.parse("foo", " bar = ");
42+
assertEquals("args", args.name());
43+
assertEquals(Map.of("application.env", "foo", "bar", ""), args.properties());
4344

44-
assertEquals(Collections.emptyMap(), Env.parse());
45-
assertEquals(Collections.emptyMap(), Env.parse(null));
45+
assertEquals(Collections.emptyMap(), Env.parse().properties());
46+
assertEquals(Collections.emptyMap(), Env.parse(null).properties());
4647
}
4748

4849
private void env(String dir, Consumer<Env> consumer) {

0 commit comments

Comments
 (0)