Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support arbitrary sources for loading properties from #70

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 12 additions & 11 deletions owner/src/main/java/org/aeonbits/owner/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,17 @@
package org.aeonbits.owner;


import java.io.IOException;
import java.io.Serializable;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.net.URL;
import java.net.URI;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.TimeUnit;

import org.aeonbits.owner.loaders.ConfigurationSourceNotFoundException;

import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
Expand Down Expand Up @@ -101,13 +102,13 @@ enum LoadType {
*/
FIRST {
@Override
Properties load(List<URL> urls, LoadersManager loaders) {
Properties load(List<URI> uris, LoadersManager loaders) {
Properties result = new Properties();
for (URL url : urls)
for (URI uri : uris)
try {
loaders.load(result, url);
loaders.load(result, uri);
break;
} catch (IOException ex) {
} catch (ConfigurationSourceNotFoundException ex) {
// happens when a file specified in the sources is not found or cannot be read.
ignore();
}
Expand All @@ -121,20 +122,20 @@ Properties load(List<URL> urls, LoadersManager loaders) {
*/
MERGE {
@Override
Properties load(List<URL> urls, LoadersManager loaders) {
Properties load(List<URI> uris, LoadersManager loaders) {
Properties result = new Properties();
for (URL url : reverse(urls))
for (URI uri : reverse(uris))
try {
loaders.load(result, url);
} catch (IOException ex) {
loaders.load(result, uri);
} catch (ConfigurationSourceNotFoundException ex) {
// happens when a file specified in the sources is not found or cannot be read.
ignore();
}
return result;
}
};

abstract Properties load(List<URL> urls, LoadersManager loaders);
abstract Properties load(List<URI> uris, LoadersManager loaders);
}

/**
Expand Down
4 changes: 4 additions & 0 deletions owner/src/main/java/org/aeonbits/owner/ConfigFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -133,5 +133,9 @@ public static String clearProperty(String key) {
public static void registerLoader(Loader loader) {
INSTANCE.registerLoader(loader);
}

public static void resetLoaders() {
INSTANCE.resetLoaders();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,34 +9,42 @@
package org.aeonbits.owner;

import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;

/**
* @author Luigi R. Viggiano
*/
class ConfigURLFactory {
class ConfigURIFactory {

private static final String CLASSPATH_PROTOCOL = "classpath:";
private static final String FILE_PROTOCOL = "file:";
private final transient ClassLoader classLoader;
private final VariablesExpander expander;

ConfigURLFactory(ClassLoader classLoader, VariablesExpander expander) {
ConfigURIFactory(ClassLoader classLoader, VariablesExpander expander) {
this.classLoader = classLoader;
this.expander = expander;
}

URL newURL(String spec) throws MalformedURLException {
URI newURI(String spec) throws MalformedURLException, URISyntaxException {
String expanded = expand(spec);
URL url;
URI uri;
if (expanded.startsWith(CLASSPATH_PROTOCOL)) {
String path = expanded.substring(CLASSPATH_PROTOCOL.length());
url = classLoader.getResource(path);
URL url = classLoader.getResource(path);
if (url == null)
return null;
uri = url.toURI();
} else if(expanded.startsWith(FILE_PROTOCOL)) {
URL url = new URL(expanded);
uri = url.toURI();
} else {
url = new URL(expanded);
uri = new URI(expanded);
}
return new URL(url.getProtocol(), url.getHost(), url.getPort(), expand(url.getPath()));

return uri;
}

private String expand(String path) {
Expand Down
5 changes: 5 additions & 0 deletions owner/src/main/java/org/aeonbits/owner/DefaultFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ public void setProperties(Properties properties) {
public void registerLoader(Loader loader) {
loadersManager.registerLoader(loader);
}

public void resetLoaders() {
loadersManager.clear();
loadersManager.registerDefaultLoaders();
}

public String getProperty(String key) {
checkKey(key);
Expand Down
3 changes: 3 additions & 0 deletions owner/src/main/java/org/aeonbits/owner/Factory.java
Original file line number Diff line number Diff line change
Expand Up @@ -87,5 +87,8 @@ public interface Factory {
* @since 1.0.5
*/
void registerLoader(Loader loader);

void resetLoaders();


}
13 changes: 7 additions & 6 deletions owner/src/main/java/org/aeonbits/owner/HotReloadLogic.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@

import java.io.File;
import java.io.Serializable;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import static org.aeonbits.owner.Config.HotReloadType.ASYNC;
import static org.aeonbits.owner.Config.HotReloadType.SYNC;
import static org.aeonbits.owner.Util.fileFromURL;
import static org.aeonbits.owner.Util.fileFromURI;
import static org.aeonbits.owner.Util.now;

/**
Expand Down Expand Up @@ -51,16 +52,16 @@ public boolean isChanged() {
}
}

public HotReloadLogic(HotReload hotReload, List<URL> urls, PropertiesManager manager) {
public HotReloadLogic(HotReload hotReload, List<URI> uris, PropertiesManager manager) {
this.manager = manager;
type = hotReload.type();
interval = hotReload.unit().toMillis(hotReload.value());
setupWatchableResources(urls);
setupWatchableResources(uris);
}

private void setupWatchableResources(List<URL> urls) {
for (URL url : urls) {
File file = fileFromURL(url);
private void setupWatchableResources(List<URI> uris) {
for (URI url : uris) {
File file = fileFromURI(url);
if (file != null)
watchableFiles.add(new WatchableFile(file));
}
Expand Down
23 changes: 12 additions & 11 deletions owner/src/main/java/org/aeonbits/owner/LoadersManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@

package org.aeonbits.owner;

import org.aeonbits.owner.loaders.ConfigurationSourceNotFoundException;
import org.aeonbits.owner.loaders.Loader;
import org.aeonbits.owner.loaders.PropertiesLoader;
import org.aeonbits.owner.loaders.XMLLoader;

import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.LinkedList;
Expand All @@ -38,27 +40,26 @@ class LoadersManager implements Serializable {
private final List<Loader> loaders = new LinkedList<Loader>();

LoadersManager() {
registerDefaultLoaders();
}

void registerDefaultLoaders() {
registerLoader(new PropertiesLoader());
registerLoader(new XMLLoader());
}

void load(Properties result, URL url) throws IOException {
InputStream stream = url.openStream();
try {
Loader loader = findLoader(url);
loader.load(result, stream);
} finally {
stream.close();
}
void load(Properties result, URI uri) throws ConfigurationSourceNotFoundException {
Loader loader = findLoader(uri);
loader.load(result, uri);
}

Loader findLoader(URL url) {
Loader findLoader(URI uri) {
lock.readLock().lock();
try {
for (Loader loader : loaders)
if (loader.accept(url))
if (loader.accept(uri))
return loader;
throw unsupported("Can't resolve a Loader for the URL %s.", url.toString());
throw unsupported("Can't resolve a Loader for the URL %s.", uri.toString());
} finally {
lock.readLock().unlock();
}
Expand Down
26 changes: 15 additions & 11 deletions owner/src/main/java/org/aeonbits/owner/PropertiesManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
Expand Down Expand Up @@ -73,7 +75,7 @@ class PropertiesManager implements Reloadable, Accessible, Mutable {
private final WriteLock writeLock = lock.writeLock();

private final LoadType loadType;
private final List<URL> urls;
private final List<URI> urls;
private final HotReloadLogic hotReloadLogic;

private volatile boolean loading = false;
Expand Down Expand Up @@ -111,8 +113,8 @@ public boolean remove(Object o) {
this.loaders = loaders;
this.imports = imports;

ConfigURLFactory urlFactory = new ConfigURLFactory(clazz.getClassLoader(), expander);
urls = toURLs(clazz.getAnnotation(Sources.class), urlFactory);
ConfigURIFactory urlFactory = new ConfigURIFactory(clazz.getClassLoader(), expander);
urls = toURIs(clazz.getAnnotation(Sources.class), urlFactory);

LoadPolicy loadPolicy = clazz.getAnnotation(LoadPolicy.class);
loadType = (loadPolicy != null) ? loadPolicy.value() : FIRST;
Expand All @@ -132,27 +134,29 @@ public void run() {
}
}

private List<URL> toURLs(Sources sources, ConfigURLFactory urlFactory) {
private List<URI> toURIs(Sources sources, ConfigURIFactory urlFactory) {
String[] specs = specs(sources, urlFactory);
ArrayList<URL> result = new ArrayList<URL>();
List<URI> result = new ArrayList<URI>();
for (String spec : specs) {
try {
URL url = urlFactory.newURL(spec);
if (url != null)
result.add(url);
URI uri = urlFactory.newURI(spec);
if (uri != null)
result.add(uri);
} catch (MalformedURLException e) {
throw unsupported(e, "Can't convert '%s' to a valid URL", spec);
}
} catch (URISyntaxException e) {
throw unsupported(e, "Can't convert '%s' to a valid URI", spec);
}
}
return result;
}

private String[] specs(Sources sources, ConfigURLFactory urlFactory) {
private String[] specs(Sources sources, ConfigURIFactory urlFactory) {
if (sources != null) return sources.value();
return defaultSpecs(urlFactory);
}

private String[] defaultSpecs(ConfigURLFactory urlFactory) {
private String[] defaultSpecs(ConfigURIFactory urlFactory) {
String prefix = urlFactory.toClasspathURLSpec(clazz.getName());
return loaders.defaultSpecs(prefix);
}
Expand Down
28 changes: 19 additions & 9 deletions owner/src/main/java/org/aeonbits/owner/Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
Expand Down Expand Up @@ -132,28 +134,36 @@ static long now() {
return timeProvider.getTime();
}

static File fileFromURL(URL url) {
if ("file".equalsIgnoreCase(url.getProtocol())) {
String path = url.getPath();
static File fileFromURI(URI uri) {
//if ("file".equalsIgnoreCase(url.getProtocol())) {
if ("file".equalsIgnoreCase(uri.getScheme())) {
String path = uri.getSchemeSpecificPart();
try {
path = decode(path, "utf-8");
return new File(path);
} catch (UnsupportedEncodingException e) {
return unreachableButCompilerNeedsThis(/* utf-8 is supported in jre libraries */);
}
} else if ("jar".equalsIgnoreCase(url.getProtocol())) {
//} else if ("jar".equalsIgnoreCase(url.getProtocol())) {
} else if ("jar".equalsIgnoreCase(uri.getScheme())) {
URL url = null;
try {
url = uri.toURL();
} catch (MalformedURLException e1) {
return unreachableButCompilerNeedsThis(/* utf-8 is supported in jre libraries */);
}
String path = url.getPath();
try {
return fileFromURL(path.substring(0, path.indexOf('!')));
} catch (MalformedURLException e) {
return ignore(/* non critical */);
}
} catch (URISyntaxException e) {
return ignore(/* non critical */);
}
}
return null;
}

static File fileFromURL(String urlSpec) throws MalformedURLException {
return fileFromURL(new URL(urlSpec));
static File fileFromURL(String urlSpec) throws URISyntaxException {
return fileFromURI(new URI(urlSpec));
}

static boolean eq(Object o1, Object o2) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.aeonbits.owner.loaders;

import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.Properties;

public abstract class AbstractFileBasedLoader implements Loader {

private static final long serialVersionUID = -7207237322627631047L;

public void load(Properties result, InputStream input) throws IOException {
result.load(input);
}

public void load(Properties result, URI uri) throws ConfigurationSourceNotFoundException {
try {
InputStream stream = uri.toURL().openStream();
doLoadInternal(result, stream);
} catch(IOException ioe) {
throw new ConfigurationSourceNotFoundException(ioe);
}
}

protected abstract void doLoadInternal(Properties result, InputStream input) throws IOException;
}
Loading