Skip to content

Commit

Permalink
Merge 02b7399 into 239776f
Browse files Browse the repository at this point in the history
  • Loading branch information
Gmugra committed May 10, 2021
2 parents 239776f + 02b7399 commit bcfea86
Show file tree
Hide file tree
Showing 8 changed files with 134 additions and 51 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,10 @@ FYI: `Converter`-implementation must be stateless and must have a default(no-arg
- XML format: [properties.dtd](https://docs.oracle.com/javase/8/docs/api/java/util/Properties.html) or [OWNER](http://owner.aeonbits.org/docs/xml-support/)
- Default charset (if URI fragment not present) is **UTF-8**
- e.g. `file:./my.xml`
1. META-INF/MANIFEST.MF: classpath:jar:manifest?*attribute*[=value]
- The loader scans all JARs in classpath for META-INF/MANIFEST.MF files. First META-INF/MANIFEST.MF, which contain *attribute* (with optional value) from the URI will be used as source.
- e.g. MANIFEST.MF must containt attribute **Bundle-Name** with value **JUnit Jupiter API**: `classpath:jar:manifest?Bundle-Name=JUnit%20Jupiter%20API`
- e.g. MANIFEST.MF must containt attribute **exotic-unique-attribite** with any value: `classpath:jar:manifest?exotic-unique-attribite`

### Custom loaders
It's possible to implement custom loaders using `Loader` interface.
Expand Down
50 changes: 0 additions & 50 deletions core/src/main/java/net/cactusthorn/config/core/ConfigBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,54 +27,4 @@ protected ConfigBuilder(Loaders loaders) {
protected Loaders loaders() {
return loaders;
}

/*
protected <T> T get(Function<String, T> convert, String key) {
return configHolder.get(convert, key);
}
protected <T> T get(Function<String, T> convert, String key, String defaultValue) {
return configHolder.get(convert, key, defaultValue);
}
protected <T> Optional<T> getOptional(Function<String, T> convert, String key) {
return configHolder.getOptional(convert, key);
}
protected <T> List<T> getList(Function<String, T> convert, String key, String splitRegEx) {
return configHolder.getList(convert, key, splitRegEx);
}
protected <T> List<T> getList(Function<String, T> convert, String key, String splitRegEx, String defaultValue) {
return configHolder.getList(convert, key, splitRegEx, defaultValue);
}
protected <T> Optional<List<T>> getOptionalList(Function<String, T> convert, String key, String splitRegEx) {
return configHolder.getOptionalList(convert, key, splitRegEx);
}
protected <T> Set<T> getSet(Function<String, T> convert, String key, String splitRegEx) {
return configHolder.getSet(convert, key, splitRegEx);
}
protected <T> Set<T> getSet(Function<String, T> convert, String key, String splitRegEx, String defaultValue) {
return configHolder.getSet(convert, key, splitRegEx, defaultValue);
}
protected <T> Optional<Set<T>> getOptionalSet(Function<String, T> convert, String key, String splitRegEx) {
return configHolder.getOptionalSet(convert, key, splitRegEx);
}
protected <T> SortedSet<T> getSortedSet(Function<String, T> convert, String key, String splitRegEx) {
return configHolder.getSortedSet(convert, key, splitRegEx);
}
protected <T> SortedSet<T> getSortedSet(Function<String, T> convert, String key, String splitRegEx, String defaultValue) {
return configHolder.getSortedSet(convert, key, splitRegEx, defaultValue);
}
protected <T> Optional<SortedSet<T>> getOptionalSortedSet(Function<String, T> convert, String key, String splitRegEx) {
return configHolder.getOptionalSortedSet(convert, key, splitRegEx);
}
*/
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;

import net.cactusthorn.config.core.loader.ClasspathJarManifestLoader;
import net.cactusthorn.config.core.loader.ClasspathPropertiesLoader;
import net.cactusthorn.config.core.loader.ClasspathXMLLoader;
import net.cactusthorn.config.core.loader.ConfigHolder;
Expand Down Expand Up @@ -60,6 +61,7 @@ private Builder() {
loaders.add(new UrlPropertiesLoader());
loaders.add(new ClasspathXMLLoader());
loaders.add(new UrlXMLLoader());
loaders.add(new ClasspathJarManifestLoader());
}

public Builder addLoader(Loader loader) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package net.cactusthorn.config.core.loader;

import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.jar.Manifest;

import static net.cactusthorn.config.core.util.ApiMessages.msg;
import static net.cactusthorn.config.core.util.ApiMessages.Key.*;

import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Map;
import java.util.logging.Logger;
import java.util.stream.Collectors;

public class ClasspathJarManifestLoader implements Loader {

private static final Logger LOG = Logger.getLogger(ClasspathJarManifestLoader.class.getName());

private static final String SUB_PREFIX = "jar:manifest?";
private static final String PREFIX = "classpath:" + SUB_PREFIX;

@Override public boolean accept(URI uri) {
return uri.toString().startsWith(PREFIX);
}

@Override public Map<String, String> load(URI uri, ClassLoader classLoader) {

String param = uri.getSchemeSpecificPart().substring(SUB_PREFIX.length());
String[] parts = param.split("=", 2);
String name = parts[0];
String value = parts.length > 1 ? parts[1] : null;

try {
Enumeration<URL> urls = getClass().getClassLoader().getResources(JarFile.MANIFEST_NAME);
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
try (InputStream in = url.openStream()) {

Manifest manifest = new Manifest(in);
Attributes attributes = manifest.getMainAttributes();
String attribute = attributes.getValue(name);
if (attribute != null && (value == null || value.equals(attribute))) {
return attributes.entrySet().stream()
.collect(Collectors.toMap(e -> e.getKey().toString(), e -> e.getValue().toString()));
}
}
}
} catch (IOException e) {
LOG.info(msg(CANT_LOAD_RESOURCE, uri.toString(), e.toString()));
return Collections.emptyMap();
}

if (value != null) {
LOG.info(msg(MANIFEST_NOT_FOUND_1, name, value));
return Collections.emptyMap();
}
LOG.info(msg(MANIFEST_NOT_FOUND_2, name));
return Collections.emptyMap();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ public final class ApiMessages {

public enum Key {
IS_NULL, IS_EMPTY, CANT_LOAD_RESOURCE, VALUE_NOT_FOUND, LOADER_NOT_FOUND, CANT_INVOKE_CONFIGBUILDER, CANT_FIND_CONFIGBUILDER,
WRONG_SOURCE_PARAM, DURATION_NO_NUMBER, DURATION_WRONG_TIME_UNIT, PERIOD_NO_NUMBER, PERIOD_WRONG_TIME_UNIT
WRONG_SOURCE_PARAM, DURATION_NO_NUMBER, DURATION_WRONG_TIME_UNIT, PERIOD_NO_NUMBER, PERIOD_WRONG_TIME_UNIT, MANIFEST_NOT_FOUND_1,
MANIFEST_NOT_FOUND_2
}

private ApiMessages() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ DURATION_NO_NUMBER=No number in duration value '{0}'
DURATION_WRONG_TIME_UNIT=Could not parse time unit '{0}' (try ns, us, ms, s, m, h, d)
PERIOD_NO_NUMBER=No number in duration value '{0}'
PERIOD_WRONG_TIME_UNIT=Could not parse time unit '{0}' (try d, w, mo, y)
MANIFEST_NOT_FOUND_1=Manifest for ''{0}={1}'' NOT found
MANIFEST_NOT_FOUND_2="Manifest for ''{0}'' NOT found."

Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package net.cactusthorn.config.core.loader;

import static org.junit.jupiter.api.Assertions.*;

import java.net.URI;
import java.util.Map;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;

import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

public class ClasspathJarManifestLoaderTest {

private static final Loader LOADER = new ClasspathJarManifestLoader();
private static final ClassLoader CL = ClasspathJarManifestLoaderTest.class.getClassLoader();

@BeforeAll static void setUpLogger() {
Logger rootLogger = LogManager.getLogManager().getLogger("");
rootLogger.setLevel(Level.FINE);
// switch off default Handlers to do not get anything in console
for (Handler h : rootLogger.getHandlers()) {
h.setLevel(Level.OFF);
}
}

@Test public void accept() {
assertTrue(LOADER.accept(URI.create("classpath:jar:manifest?a=b")));
}

@Test public void notAccept() {
assertFalse(LOADER.accept(URI.create("classpath:a.xml#ISO-8859-1")));
}

@Test public void notFoundNameValue() {
LOADER.load(URI.create("classpath:jar:manifest?a=b"), CL);
}

@Test public void notFoundName() {
LOADER.load(URI.create("classpath:jar:manifest?a"), CL);
}

@Test public void load() {
Map<String, String> result = LOADER.load(URI.create("classpath:jar:manifest?Bundle-Name=JUnit%20Jupiter%20API"), CL);
assertEquals("junit-jupiter-api", result.get("Implementation-Title"));
}

@Test public void loadOnlyName() {
Map<String, String> result = LOADER.load(URI.create("classpath:jar:manifest?Bundle-Name"), CL);
assertFalse(result.isEmpty());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -117,4 +117,8 @@ public class ConfigHolderTest {
Optional<List<UUID>> list = holder.getOptionalList(UUID::fromString, "list", ",");
assertEquals(2, list.get().size());
}

@Test public void getNotExist() {
assertThrows(IllegalArgumentException.class, () -> holder.get(UUID::fromString, "notExist"));
}
}

0 comments on commit bcfea86

Please sign in to comment.