diff --git a/.gitignore b/.gitignore index 940fbf3..8ed8c05 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .* !.gitignore /build +*.iml diff --git a/CHANGELOG.md b/CHANGELOG.md index d615a37..3b6bb86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,2 +1,6 @@ ## v1.0 / 2014-10-01 - Initial release + +## v1.1 / 2015-09-16 +- Upgrade gradle and dependencies +- Add Redacted diff --git a/README.md b/README.md index cc27b27..ca2ce3a 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ environments { ``` #### Local Overrides -By setting the locations to load on the Config object. Latter locations will overrides values set by ealier locations. +By setting the locations to load on the Config object. Latter locations will overrides values set by earlier locations. Locations are Spring's resource strings such as `classpath:x/y/z`, and `file:/x/y/z`. With an additional type `class:fully.qualified.Classname` which loads a compiled config groovy class. ```java diff --git a/build.gradle b/build.gradle index 678a03e..5894f62 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,7 @@ //================================================== group = 'com.ctzen' -version = '1.0' +version = '1.1' defaultTasks 'clean', 'build' @@ -22,22 +22,22 @@ repositories { dependencies { // groovy - compile 'org.codehaus.groovy:groovy-all:2.3.6' // version matches eclipse plug-in + compile 'org.codehaus.groovy:groovy-all:2.4.4' // version matches eclipse plug-in // spring - compile 'org.springframework:spring-context:4.1.0.RELEASE' + compile 'org.springframework:spring-context:4.2.1.RELEASE' // must haves compile 'com.google.guava:guava:18.0' // logging - compile 'org.slf4j:slf4j-api:1.7.7' - runtime 'ch.qos.logback:logback-classic:1.1.2' - runtime 'org.slf4j:jcl-over-slf4j:1.7.7' // bridge commons-logging to slf4j - runtime 'org.slf4j:log4j-over-slf4j:1.7.7' // bridge log4j to slf4j + compile 'org.slf4j:slf4j-api:1.7.12' + runtime 'ch.qos.logback:logback-classic:1.1.3' + runtime 'org.slf4j:jcl-over-slf4j:1.7.12' // bridge commons-logging to slf4j + runtime 'org.slf4j:log4j-over-slf4j:1.7.12' // bridge log4j to slf4j // testing - testCompile 'org.slf4j:jcl-over-slf4j:1.7.7' // need this to compile groovy tests - testCompile 'org.testng:testng:6.8.8' + testCompile 'org.slf4j:jcl-over-slf4j:1.7.12' // need this to compile groovy tests + testCompile 'org.testng:testng:6.9.6' testRuntime 'org.uncommons:reportng:1.1.4' // nicer testng reports - testRuntime 'com.google.inject:guice:2.0' // required by reportng (no major version due to bad meta on repo) - testCompile 'org.springframework:spring-test:4.1.0.RELEASE' + testRuntime 'com.google.inject:guice:4.0' // required by reportng (no major version due to bad meta on repo) + testCompile 'org.springframework:spring-test:4.2.1.RELEASE' testRuntime name: 'slurper-configuration-test' // for testing META-INF/slurper-configuration.properties } @@ -209,3 +209,11 @@ task publishLocal { description = 'Alias for publishToMavenLocal' dependsOn publishToMavenLocal } + +//================================================== +// gradle wrapper +//================================================== + +task wrapper(type: Wrapper) { + gradleVersion = '2.7' +} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index b761216..e8c6bf7 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 9b8c07c..d3dbf05 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Mon Sep 29 10:11:17 EDT 2014 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.0-bin.zip +#Wed Sep 16 18:15:48 EDT 2015 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-2.7-bin.zip diff --git a/gradlew b/gradlew index 91a7e26..97fac78 100755 --- a/gradlew +++ b/gradlew @@ -42,11 +42,6 @@ case "`uname`" in ;; esac -# For Cygwin, ensure paths are in UNIX format before anything is touched. -if $cygwin ; then - [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` -fi - # Attempt to set APP_HOME # Resolve links: $0 may be a link PRG="$0" @@ -114,6 +109,7 @@ fi if $cygwin ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` diff --git a/sonar-project.properties b/sonar-project.properties index dce42b6..0f4f184 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -2,7 +2,7 @@ sonar.host.url=http://localhost:9088 # required metadata sonar.projectKey=com.ctzen:slurper-configuration sonar.projectName=slurper-configuration -sonar.projectVersion=1.0 +sonar.projectVersion=1.1 sonar.sources=src sonar.tests=src-test sonar.binaries=build/classes diff --git a/src-test/com/ctzen/config/GetTests.groovy b/src-test/com/ctzen/config/GetTests.groovy index 21813b2..e108ac8 100644 --- a/src-test/com/ctzen/config/GetTests.groovy +++ b/src-test/com/ctzen/config/GetTests.groovy @@ -55,6 +55,7 @@ class GetTests { [ 'l1.l2.qux', 2 ], [ 'l1.l2.l3.qux', 3 ], [ 'aNull', null ], + [ 'redacted', 'I am redacted!' ], ] as Object[][] } diff --git a/src-test/com/ctzen/config/GetTestsConfig.groovy b/src-test/com/ctzen/config/GetTestsConfig.groovy index b85df88..bbb713f 100644 --- a/src-test/com/ctzen/config/GetTestsConfig.groovy +++ b/src-test/com/ctzen/config/GetTestsConfig.groovy @@ -19,4 +19,6 @@ l1 { aNull = null -pojo = new TestPojo(name: 'I am pojo!') \ No newline at end of file +pojo = new TestPojo(name: 'I am pojo!') + +redacted = new Redact('I am redacted!') \ No newline at end of file diff --git a/src/com/ctzen/config/Config.java b/src/com/ctzen/config/Config.java index ddd76f7..ce3281e 100644 --- a/src/com/ctzen/config/Config.java +++ b/src/com/ctzen/config/Config.java @@ -1,22 +1,13 @@ package com.ctzen.config; +import com.ctzen.config.exception.ConfigException; +import com.ctzen.config.exception.NoSuchKeyException; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; import groovy.lang.Binding; import groovy.lang.GroovyShell; import groovy.util.ConfigObject; import groovy.util.ConfigSlurper; - -import java.io.IOException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Collection; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Properties; -import java.util.Set; -import java.util.TreeMap; - import org.codehaus.groovy.runtime.GStringImpl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -30,10 +21,10 @@ import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.PropertiesLoaderUtils; -import com.ctzen.config.exception.ConfigException; -import com.ctzen.config.exception.NoSuchKeyException; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; +import java.io.IOException; +import java.net.URL; +import java.util.*; +import java.util.Map.Entry; /** * {@link ConfigSlurper} backed configuration. @@ -196,6 +187,7 @@ public void load() { resourceLoader = new DefaultResourceLoader(Thread.currentThread().getContextClassLoader()); } values.clear(); + redacts.clear(); List effectiveProfiles = getEffectiveProfiles(); LOG.info("Load using profiles: {}", effectiveProfiles); final List effectiveLocations = getEffectiveLocations(); @@ -260,6 +252,10 @@ private ConfigObject loadFromClass(final ConfigSlurper slurper, final String cla private ConfigObject loadFromResource(final ConfigSlurper slurper, final String location) { final Resource res = resourceLoader.getResource(location); + if (!res.exists()) { + LOG.warn("Skip non-existence resource: {}", res); + return null; + } if (!res.isReadable()) { LOG.warn("Resource not readable: {}", res); return null; @@ -290,7 +286,7 @@ private void resolveScriptValues(final ConfigObject base, final ConfigObject src } } else if (srcValue instanceof CharSequence) { - final String sv = ((CharSequence)srcValue).toString(); + final String sv = srcValue.toString(); if (sv.startsWith(GROOVY_SCRIPT_VALUE_PREFIX)) { final Binding binding = new Binding(); final Object baseValue = base.get(srcKey); @@ -317,6 +313,11 @@ private void loadValues(final String keyPrefix, final ConfigObject configObject) loadValues(key + ".", (ConfigObject)value); } else { + + if (value instanceof Redact) { + redacts.add(key); + value = ((Redact)value).getValue(); + } if (value instanceof GStringImpl) { value = value.toString(); } @@ -329,22 +330,28 @@ private void logValues() { final StringBuilder msg = new StringBuilder(values.size() + " config values:"); for (final Map.Entry entry: values.entrySet()) { msg.append("\n ") - .append(entry.getKey()) - .append(" ("); - final Object value = entry.getValue(); - if (value == null) { - msg.append("null"); + .append(entry.getKey()); + if (redacts.contains(entry.getKey())) { + msg.append(" = "); } else { - msg.append(value.getClass().getSimpleName()); + msg.append(" ("); + final Object value = entry.getValue(); + if (value == null) { + msg.append("null"); + } + else { + msg.append(value.getClass().getSimpleName()); + } + msg.append(") = ") + .append(entry.getValue()); } - msg.append(") = ") - .append(entry.getValue()); } LOG.info(msg.toString()); } private final Map values = new TreeMap<>(); + private final Set redacts = new HashSet<>(); /** * @return {@code true} if there is no config entry diff --git a/src/com/ctzen/config/ConfigProfile.java b/src/com/ctzen/config/ConfigProfile.java index 26f6727..745d90a 100644 --- a/src/com/ctzen/config/ConfigProfile.java +++ b/src/com/ctzen/config/ConfigProfile.java @@ -8,10 +8,10 @@ public interface ConfigProfile { // NOSONAR: Move constants to a class or enum. // This allows the constants to be used as annotation parameters. - static final String DEV = "dev"; - static final String UNIT_TEST = "unittest"; - static final String INTEGRATION_TEST = "integrationtest"; - static final String QA = "qa"; - static final String PROD = "prod"; + String DEV = "dev"; + String UNIT_TEST = "unittest"; + String INTEGRATION_TEST = "integrationtest"; + String QA = "qa"; + String PROD = "prod"; } diff --git a/src/com/ctzen/config/Redact.java b/src/com/ctzen/config/Redact.java new file mode 100644 index 0000000..304e392 --- /dev/null +++ b/src/com/ctzen/config/Redact.java @@ -0,0 +1,21 @@ +package com.ctzen.config; + +/** + * Hide value when dumping config settings in log, + * use for passwords, for example. + * + * @author cchang + */ +public class Redact { + + public Redact(E value) { + this.value = value; + } + + private final E value; + + public E getValue() { + return value; + } + +}