Skip to content

Commit

Permalink
Merge branch '176'
Browse files Browse the repository at this point in the history
  • Loading branch information
andrus committed Aug 31, 2017
2 parents 2cf8316 + ec56949 commit 201617a
Show file tree
Hide file tree
Showing 5 changed files with 170 additions and 5 deletions.
5 changes: 3 additions & 2 deletions bootique/src/main/java/io/bootique/BQCoreModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -387,9 +387,10 @@ ApplicationMetadata provideApplicationMetadata(ApplicationDescription descriptio
@Singleton
Environment provideEnvironment(@EnvironmentProperties Map<String, String> diProperties,
@EnvironmentVariables Map<String, String> diVars,
Set<DeclaredVariable> declaredVariables) {
Set<DeclaredVariable> declaredVariables,
BootLogger logger) {

return DefaultEnvironment.withSystemPropertiesAndVariables()
return DefaultEnvironment.withSystemPropertiesAndVariables(logger)
.properties(diProperties)
.variables(diVars)
.declaredVariables(declaredVariables)
Expand Down
2 changes: 2 additions & 0 deletions bootique/src/main/java/io/bootique/BQCoreModuleExtender.java
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,9 @@ public BQCoreModuleExtender setVars(Map<String, String> vars) {
* @param configPath a dot-separated "path" that navigates through the configuration tree to the property that
* should be bound form a variable. E.g. "jdbc.myds.password".
* @return this extender instance.
* @deprecated since 0.24
*/
@Deprecated
public BQCoreModuleExtender declareVar(String configPath) {
new DeclaredVariableBinder(contributeVariableDeclarations(), configPath).withCanonicalName();
return this;
Expand Down
55 changes: 52 additions & 3 deletions bootique/src/main/java/io/bootique/env/DefaultEnvironment.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package io.bootique.env;

import io.bootique.log.BootLogger;

import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toMap;

Expand All @@ -19,8 +23,8 @@ public class DefaultEnvironment implements Environment {
private Map<String, String> properties;
private Map<String, String> variables;

public static Builder withSystemPropertiesAndVariables() {
return new Builder().includeSystemProperties().includeSystemVariables();
public static Builder withSystemPropertiesAndVariables(BootLogger logger) {
return new Builder(logger).includeSystemProperties().includeSystemVariables();
}

protected DefaultEnvironment() {
Expand Down Expand Up @@ -60,8 +64,10 @@ public static class Builder {
private Collection<DeclaredVariable> declaredVariables;
private boolean includeSystemProperties;
private boolean includeSystemVariables;
private BootLogger logger;

private Builder() {
private Builder(BootLogger logger) {
this.logger = logger;
}

public DefaultEnvironment build() {
Expand Down Expand Up @@ -116,6 +122,9 @@ protected Map<String, String> buildProperties() {

protected Map<String, String> buildVariables() {

//warn if there are some variables overriding app configuration
warnAboutNotDeclaredVars();

Map<String, String> vars = new HashMap<>();
vars.putAll(canonicalizeVariableNames(this.variables));

Expand Down Expand Up @@ -156,5 +165,45 @@ protected Map<String, String> canonicalizeVariableNames(Map<String, String> vars

return canonical;
}

/**
* Checks and prints warning if there are some undeclared vars.
* This is the first step to remove BQ_* prefixed variables.
* <p>
* Currently BQ_* variables declared via {@link io.bootique.BQCoreModuleExtender#setVar(String, String)}
* {@link io.bootique.BQCoreModuleExtender#setVars(Map)} are overridden with real BQ_* shell vars.
* It can lead to some side effects whose cause is hard to be found (e.g. wrong values or extra vars in a env).
* <p>
* New approach: BQ_* shell variables and variables contributed in BQ are checked against vars declared via
* {@link io.bootique.BQCoreModuleExtender#declareVar(String, String)} or
* {@link io.bootique.BQCoreModuleExtender#declareVar(String)}.
* So that user should explicitly control what vars must be used as a part of app configuration.
* <p>
*/
private void warnAboutNotDeclaredVars() {
StringBuilder warn = new StringBuilder();

//print BQ_* shell vars
List<String> envVars = System.getenv().keySet().stream()
.filter(var -> var.startsWith(FRAMEWORK_VARIABLES_PREFIX))
.collect(Collectors.toList());
if (!envVars.isEmpty()) {
warn.append("WARNING: App JSON/YAML configuration will be overridden by ");
warn.append(String.format("not app-controlled shell vars:\n%s\n", envVars));
}

//print BQ vars
List<String> bqVars = variables.entrySet().stream()
.filter(var -> var.getKey().startsWith(FRAMEWORK_VARIABLES_PREFIX))
.map(var -> var.getKey())
.collect(Collectors.toList());

if (!bqVars.isEmpty()) {
warn.append(warn.length() == 0 ? "WARNING: App JSON/YAML configuration will be overridden by " : "And ");
warn.append(String.format("BQ_* vars contributed into BQ:\n %s ", bqVars));
}

logger.stdout(warn.toString());
}
}
}
108 changes: 108 additions & 0 deletions bootique/src/test/java/io/bootique/Bootique_VarsIT.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package io.bootique;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.google.inject.ProvisionException;
import io.bootique.config.ConfigurationFactory;
import io.bootique.unit.BQInternalTestFactory;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;

import static org.junit.Assert.assertEquals;

public class Bootique_VarsIT {

@Rule
public BQInternalTestFactory testFactory = new BQInternalTestFactory();

@Test
public void testVarSetValue() {
BQRuntime runtime = testFactory.app("--config=src/test/resources/io/bootique/config/configEnvironment.yml")
.var("BQ_C_M_F", "f")
.createRuntime();

Bean1 b1 = runtime.getInstance(ConfigurationFactory.class).config(Bean1.class, "");

assertEquals("f", b1.c.m.f);
}

@Test
public void testDeclaredVarSetValue() {
BQRuntime runtime = testFactory.app("--config=src/test/resources/io/bootique/config/configEnvironment.yml")
.var("BQ_C_M_F", "f")
.var("MY_VAR", "myValue")
.varAlias("c.m.l", "MY_VAR")
.createRuntime();

Bean1 b1 = runtime.getInstance(ConfigurationFactory.class).config(Bean1.class, "");

assertEquals("myValue", b1.c.m.l);
assertEquals("f", b1.c.m.f);
}

@Test
@Ignore
public void testVarCamelCase_AppliedInRandomTheOrder() {
BQRuntime runtime = testFactory.app("--config=src/test/resources/io/bootique/config/configEnvironment.yml")
.var("BQ_C_m_F", "camel")
.var("BQ_C_M_F", "myValue")
.createRuntime();

Bean1 b1 = runtime.getInstance(ConfigurationFactory.class).config(Bean1.class, "");

assertEquals("camel", b1.c.m.f);
}

@Test(expected = ProvisionException.class)
public void testDeclaredVar_CanonicalizeVarNameConflict() {
BQRuntime runtime = testFactory.app("--config=src/test/resources/io/bootique/config/configEnvironment.yml")
.var("BQ_C_M_F", "var1")
.var("MY_VAR", "myVar")
//canonical name is BQ_C_M_F (c.m.f -> BQ_C_M_F)
.varAlias("c.m.f", "MY_VAR")
.createRuntime();

runtime.getInstance(ConfigurationFactory.class).config(Bean1.class, "");
}

@JsonIgnoreProperties(ignoreUnknown = true)
static class Bean1 {
private String a;
private Bean2 c;

public void setA(String a) {
this.a = a;
}

public void setC(Bean2 c) {
this.c = c;
}
}

static class Bean2 {
private Bean3 m;

public void setM(Bean3 m) {
this.m = m;
}
}

static class Bean3 {
private String k;
private String f;
private String l;

public void setK(String k) {
this.k = k;
}

public void setF(String f) {
this.f = f;
}

public void setL(String l) {
this.l = l;
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
a: e
c:
m:
k: "q"
l: "n"

0 comments on commit 201617a

Please sign in to comment.