diff --git a/owner/src/main/java/org/aeonbits/owner/Config.java b/owner/src/main/java/org/aeonbits/owner/Config.java index 51e685de..0f00280c 100644 --- a/owner/src/main/java/org/aeonbits/owner/Config.java +++ b/owner/src/main/java/org/aeonbits/owner/Config.java @@ -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; @@ -101,13 +102,13 @@ enum LoadType { */ FIRST { @Override - Properties load(List urls, LoadersManager loaders) { + Properties load(List 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(); } @@ -121,12 +122,12 @@ Properties load(List urls, LoadersManager loaders) { */ MERGE { @Override - Properties load(List urls, LoadersManager loaders) { + Properties load(List 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(); } @@ -134,7 +135,7 @@ Properties load(List urls, LoadersManager loaders) { } }; - abstract Properties load(List urls, LoadersManager loaders); + abstract Properties load(List uris, LoadersManager loaders); } /** diff --git a/owner/src/main/java/org/aeonbits/owner/ConfigFactory.java b/owner/src/main/java/org/aeonbits/owner/ConfigFactory.java index dffd71c0..b89995bc 100644 --- a/owner/src/main/java/org/aeonbits/owner/ConfigFactory.java +++ b/owner/src/main/java/org/aeonbits/owner/ConfigFactory.java @@ -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(); + } } diff --git a/owner/src/main/java/org/aeonbits/owner/ConfigURLFactory.java b/owner/src/main/java/org/aeonbits/owner/ConfigURIFactory.java similarity index 65% rename from owner/src/main/java/org/aeonbits/owner/ConfigURLFactory.java rename to owner/src/main/java/org/aeonbits/owner/ConfigURIFactory.java index cd953909..2ba49798 100644 --- a/owner/src/main/java/org/aeonbits/owner/ConfigURLFactory.java +++ b/owner/src/main/java/org/aeonbits/owner/ConfigURIFactory.java @@ -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) { diff --git a/owner/src/main/java/org/aeonbits/owner/DefaultFactory.java b/owner/src/main/java/org/aeonbits/owner/DefaultFactory.java index d94d20c4..421a636a 100644 --- a/owner/src/main/java/org/aeonbits/owner/DefaultFactory.java +++ b/owner/src/main/java/org/aeonbits/owner/DefaultFactory.java @@ -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); diff --git a/owner/src/main/java/org/aeonbits/owner/Factory.java b/owner/src/main/java/org/aeonbits/owner/Factory.java index d1f0f9f2..3cdab827 100644 --- a/owner/src/main/java/org/aeonbits/owner/Factory.java +++ b/owner/src/main/java/org/aeonbits/owner/Factory.java @@ -87,5 +87,8 @@ public interface Factory { * @since 1.0.5 */ void registerLoader(Loader loader); + + void resetLoaders(); + } diff --git a/owner/src/main/java/org/aeonbits/owner/HotReloadLogic.java b/owner/src/main/java/org/aeonbits/owner/HotReloadLogic.java index f9232fd7..27cc79be 100644 --- a/owner/src/main/java/org/aeonbits/owner/HotReloadLogic.java +++ b/owner/src/main/java/org/aeonbits/owner/HotReloadLogic.java @@ -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; /** @@ -51,16 +52,16 @@ public boolean isChanged() { } } - public HotReloadLogic(HotReload hotReload, List urls, PropertiesManager manager) { + public HotReloadLogic(HotReload hotReload, List uris, PropertiesManager manager) { this.manager = manager; type = hotReload.type(); interval = hotReload.unit().toMillis(hotReload.value()); - setupWatchableResources(urls); + setupWatchableResources(uris); } - private void setupWatchableResources(List urls) { - for (URL url : urls) { - File file = fileFromURL(url); + private void setupWatchableResources(List uris) { + for (URI url : uris) { + File file = fileFromURI(url); if (file != null) watchableFiles.add(new WatchableFile(file)); } diff --git a/owner/src/main/java/org/aeonbits/owner/LoadersManager.java b/owner/src/main/java/org/aeonbits/owner/LoadersManager.java index 5e42d33d..aa3c9503 100644 --- a/owner/src/main/java/org/aeonbits/owner/LoadersManager.java +++ b/owner/src/main/java/org/aeonbits/owner/LoadersManager.java @@ -8,6 +8,7 @@ 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; @@ -15,6 +16,7 @@ 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; @@ -38,27 +40,26 @@ class LoadersManager implements Serializable { private final List loaders = new LinkedList(); 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(); } diff --git a/owner/src/main/java/org/aeonbits/owner/PropertiesManager.java b/owner/src/main/java/org/aeonbits/owner/PropertiesManager.java index 98bcbdea..bb554fb8 100644 --- a/owner/src/main/java/org/aeonbits/owner/PropertiesManager.java +++ b/owner/src/main/java/org/aeonbits/owner/PropertiesManager.java @@ -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; @@ -73,7 +75,7 @@ class PropertiesManager implements Reloadable, Accessible, Mutable { private final WriteLock writeLock = lock.writeLock(); private final LoadType loadType; - private final List urls; + private final List urls; private final HotReloadLogic hotReloadLogic; private volatile boolean loading = false; @@ -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; @@ -132,27 +134,29 @@ public void run() { } } - private List toURLs(Sources sources, ConfigURLFactory urlFactory) { + private List toURIs(Sources sources, ConfigURIFactory urlFactory) { String[] specs = specs(sources, urlFactory); - ArrayList result = new ArrayList(); + List result = new ArrayList(); 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); } diff --git a/owner/src/main/java/org/aeonbits/owner/Util.java b/owner/src/main/java/org/aeonbits/owner/Util.java index d8e12627..23b7d53a 100644 --- a/owner/src/main/java/org/aeonbits/owner/Util.java +++ b/owner/src/main/java/org/aeonbits/owner/Util.java @@ -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; @@ -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) { diff --git a/owner/src/main/java/org/aeonbits/owner/loaders/AbstractFileBasedLoader.java b/owner/src/main/java/org/aeonbits/owner/loaders/AbstractFileBasedLoader.java new file mode 100644 index 00000000..94338867 --- /dev/null +++ b/owner/src/main/java/org/aeonbits/owner/loaders/AbstractFileBasedLoader.java @@ -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; +} diff --git a/owner/src/main/java/org/aeonbits/owner/loaders/AbstractNamedCustomLoader.java b/owner/src/main/java/org/aeonbits/owner/loaders/AbstractNamedCustomLoader.java new file mode 100644 index 00000000..8efff1b4 --- /dev/null +++ b/owner/src/main/java/org/aeonbits/owner/loaders/AbstractNamedCustomLoader.java @@ -0,0 +1,53 @@ +package org.aeonbits.owner.loaders; + +import java.net.URI; +import java.util.Properties; + +import org.aeonbits.owner.Config; + +/** + *

Support class for custom named loaders, which expects the @Sources URI to be owner://<loadername>#<optional argument>

+ *

the default spec for a {@link Loader} with a name of "myCustomLoader" and a {@link Config} foo.bar.MyConfig would become
+ * owner://myCustomLoader#foo/bar/MyConfig
+ * + * + * @author philippgaschuetz + * + */ +public abstract class AbstractNamedCustomLoader implements Loader { + + private static final long serialVersionUID = 838201064524631453L; + + private static final String CLASSPATH_PROTOCOL = "classpath:"; + public final static String CUSTOMLOADER_SCHEME = "owner"; + + private final String loaderName; + + public AbstractNamedCustomLoader(String loaderName) { + if(loaderName == null || loaderName.length() == 0) { + throw new IllegalArgumentException("Loadername cannot be empty"); + } + this.loaderName = loaderName; + } + + public boolean accept(URI uri) { + return CUSTOMLOADER_SCHEME.equals(uri.getScheme()) && loaderName.equals(uri.getHost()); + } + + public String defaultSpecFor(String urlPrefix) { + if(urlPrefix.startsWith(CLASSPATH_PROTOCOL)) { + urlPrefix = urlPrefix.substring( CLASSPATH_PROTOCOL.length() ); + } + + String spec = String.format("%s://%s#%s", CUSTOMLOADER_SCHEME, loaderName, urlPrefix); + return spec; + } + + public void load(Properties result, URI uri) throws ConfigurationSourceNotFoundException { + String argument = uri.getFragment(); + doLoadInternal(result, argument); + } + + protected abstract void doLoadInternal(Properties result, String arg) throws ConfigurationSourceNotFoundException; + +} diff --git a/owner/src/main/java/org/aeonbits/owner/loaders/ConfigurationSourceNotFoundException.java b/owner/src/main/java/org/aeonbits/owner/loaders/ConfigurationSourceNotFoundException.java new file mode 100644 index 00000000..4a13c8e7 --- /dev/null +++ b/owner/src/main/java/org/aeonbits/owner/loaders/ConfigurationSourceNotFoundException.java @@ -0,0 +1,14 @@ +package org.aeonbits.owner.loaders; + +public class ConfigurationSourceNotFoundException extends Exception { + private static final long serialVersionUID = -2771460889844727051L; + + public ConfigurationSourceNotFoundException() { + super(); + } + + public ConfigurationSourceNotFoundException(Throwable throwable) { + super(throwable); + } + +} diff --git a/owner/src/main/java/org/aeonbits/owner/loaders/Loader.java b/owner/src/main/java/org/aeonbits/owner/loaders/Loader.java index cdf78dcf..e21879f5 100644 --- a/owner/src/main/java/org/aeonbits/owner/loaders/Loader.java +++ b/owner/src/main/java/org/aeonbits/owner/loaders/Loader.java @@ -8,10 +8,9 @@ package org.aeonbits.owner.loaders; -import java.io.IOException; import java.io.InputStream; import java.io.Serializable; -import java.net.URL; +import java.net.URI; import java.util.Properties; /** @@ -26,25 +25,25 @@ public interface Loader extends Serializable { * Indicates wether this Loader does accept the URL, guessing the content type from it. * * @since 1.0.5 - * @param url the URL + * @param uri the URL * @return true, if the loader is able to handle the content of the URL based on the filename. */ - boolean accept(URL url); + boolean accept(URI uri); /** - * Loads the given {@link InputStream input} into the given {@link Properties result} + * Loads the given {@link URI uri} into the given {@link Properties result} * * @since 1.0.5 * @param result the resulting properties where to load the {@link InputStream input} - * @param input the {@link InputStream} from where to load the properties. + * @param uri the {@link URI} from where to load the properties. */ - void load(Properties result, InputStream input) throws IOException; + void load(Properties result, URI uri) throws ConfigurationSourceNotFoundException; /** - * Returns the default URL specification for a given url resource, that can be handled by this loader. + * Returns the default URL specification for a given uri resource, that can be handled by this loader. * - * @param urlPrefix the prefix identifying the url resource. - * @return the default URL specification for a given url resource, that can be handled by this loader. + * @param urlPrefix the prefix identifying the uri resource. + * @return the default URL specification for a given uri resource, that can be handled by this loader. */ String defaultSpecFor(String urlPrefix); } diff --git a/owner/src/main/java/org/aeonbits/owner/loaders/PropertiesLoader.java b/owner/src/main/java/org/aeonbits/owner/loaders/PropertiesLoader.java index b0f7d2b7..f4550428 100644 --- a/owner/src/main/java/org/aeonbits/owner/loaders/PropertiesLoader.java +++ b/owner/src/main/java/org/aeonbits/owner/loaders/PropertiesLoader.java @@ -10,7 +10,8 @@ import java.io.IOException; import java.io.InputStream; -import java.net.URL; +import java.net.MalformedURLException; +import java.net.URI; import java.util.Properties; /** @@ -19,15 +20,20 @@ * @since 1.0.5 * @author Luigi R. Viggiano */ -public class PropertiesLoader implements Loader { +public class PropertiesLoader extends AbstractFileBasedLoader implements Loader { private static final long serialVersionUID = -1781643040589572341L; - public boolean accept(URL url) { - return true; + public boolean accept(URI uri) { + try { + uri.toURL(); + return true; + } catch (MalformedURLException e) { + return false; + } } - public void load(Properties result, InputStream input) throws IOException { + protected void doLoadInternal(Properties result, InputStream input) throws IOException { result.load(input); } diff --git a/owner/src/main/java/org/aeonbits/owner/loaders/XMLLoader.java b/owner/src/main/java/org/aeonbits/owner/loaders/XMLLoader.java index 96741d73..afa5ec05 100644 --- a/owner/src/main/java/org/aeonbits/owner/loaders/XMLLoader.java +++ b/owner/src/main/java/org/aeonbits/owner/loaders/XMLLoader.java @@ -17,9 +17,12 @@ import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; + import java.io.IOException; import java.io.InputStream; import java.io.StringReader; +import java.net.MalformedURLException; +import java.net.URI; import java.net.URL; import java.util.Properties; import java.util.Stack; @@ -31,7 +34,7 @@ * @since 1.0.5 * @author Luigi R. Viggiano */ -public class XMLLoader implements Loader { +public class XMLLoader extends AbstractFileBasedLoader implements Loader { private static final long serialVersionUID = -894351666332018767L; private transient volatile SAXParserFactory factory = null; @@ -128,11 +131,16 @@ public void error(SAXParseException e) throws SAXException { } } - public boolean accept(URL url) { - return url.getFile().toLowerCase().endsWith(".xml"); + public boolean accept(URI uri) { + try { + URL url = uri.toURL(); + return url.getFile().toLowerCase().endsWith(".xml"); + } catch (MalformedURLException e) { + return false; + } } - public void load(Properties result, InputStream input) throws IOException { + public void doLoadInternal(Properties result, InputStream input) throws IOException { try { SAXParser parser = factory().newSAXParser(); XmlToPropsHandler h = new XmlToPropsHandler(result); diff --git a/owner/src/test/java/org/aeonbits/owner/ConfigURLFactoryTest.java b/owner/src/test/java/org/aeonbits/owner/ConfigURLFactoryTest.java index 570b2a5b..f8ddae43 100644 --- a/owner/src/test/java/org/aeonbits/owner/ConfigURLFactoryTest.java +++ b/owner/src/test/java/org/aeonbits/owner/ConfigURLFactoryTest.java @@ -11,6 +11,8 @@ import org.junit.Test; import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; import java.net.URL; import java.util.Properties; @@ -21,9 +23,9 @@ */ public class ConfigURLFactoryTest { @Test - public void shouldReturnAnURL() throws MalformedURLException { - ConfigURLFactory h = new ConfigURLFactory(this.getClass().getClassLoader(), new VariablesExpander(new Properties())); - URL url = h.newURL("classpath:test.properties"); + public void shouldReturnAnURI() throws MalformedURLException, URISyntaxException { + ConfigURIFactory h = new ConfigURIFactory(this.getClass().getClassLoader(), new VariablesExpander(new Properties())); + URI url = h.newURI("classpath:test.properties"); assertNotNull(url); } } diff --git a/owner/src/test/java/org/aeonbits/owner/LoaderManagerTest.java b/owner/src/test/java/org/aeonbits/owner/LoaderManagerTest.java index 00c11787..2a1e4b8b 100644 --- a/owner/src/test/java/org/aeonbits/owner/LoaderManagerTest.java +++ b/owner/src/test/java/org/aeonbits/owner/LoaderManagerTest.java @@ -9,6 +9,7 @@ package org.aeonbits.owner; import org.aeonbits.owner.Config.Sources; +import org.aeonbits.owner.loaders.ConfigurationSourceNotFoundException; import org.aeonbits.owner.loaders.Loader; import org.aeonbits.owner.loaders.PropertiesLoader; import org.aeonbits.owner.loaders.XMLLoader; @@ -20,7 +21,8 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; -import java.net.URL; +import java.net.URI; +import java.net.URISyntaxException; import java.util.Properties; import java.util.concurrent.ScheduledExecutorService; @@ -47,7 +49,7 @@ interface MyConfigDefaultSpec extends Config { } @Before - public void before() throws IOException { + public void before() throws IOException, URISyntaxException { target = fileFromURL(SPEC); target.getParentFile().mkdirs(); target.createNewFile(); @@ -128,11 +130,11 @@ public void testRegisterNonNullLoaderOnSingleton() { } public static class LoaderThatDoesNothing implements Loader { - public boolean accept(URL url) { + public boolean accept(URI uri) { return false; } - public void load(Properties result, InputStream input) throws IOException { + public void load(Properties result, URI uri) throws ConfigurationSourceNotFoundException { } public String defaultSpecFor(String urlPrefix) { diff --git a/owner/src/test/java/org/aeonbits/owner/LoadersManagerForTest.java b/owner/src/test/java/org/aeonbits/owner/LoadersManagerForTest.java index 5e9744b8..2e5fb8eb 100644 --- a/owner/src/test/java/org/aeonbits/owner/LoadersManagerForTest.java +++ b/owner/src/test/java/org/aeonbits/owner/LoadersManagerForTest.java @@ -8,16 +8,16 @@ package org.aeonbits.owner; -import org.aeonbits.owner.loaders.Loader; +import java.net.URI; -import java.net.URL; +import org.aeonbits.owner.loaders.Loader; /** * @author Luigi R. Viggiano */ public class LoadersManagerForTest extends LoadersManager { @Override - public Loader findLoader(URL url) { - return super.findLoader(url); + public Loader findLoader(URI uri) { + return super.findLoader(uri); } } diff --git a/owner/src/test/java/org/aeonbits/owner/UtilTest.java b/owner/src/test/java/org/aeonbits/owner/UtilTest.java index f2f365e4..d8a4a83a 100644 --- a/owner/src/test/java/org/aeonbits/owner/UtilTest.java +++ b/owner/src/test/java/org/aeonbits/owner/UtilTest.java @@ -20,6 +20,7 @@ import java.io.OutputStream; import java.lang.reflect.Array; import java.net.MalformedURLException; +import java.net.URISyntaxException; import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -157,7 +158,7 @@ public static T ignore() { return Util.ignore(); } - public static File fileFromURL(String spec) throws MalformedURLException { + public static File fileFromURL(String spec) throws URISyntaxException { return Util.fileFromURL(spec); } diff --git a/owner/src/test/java/org/aeonbits/owner/customloader/CustomNamedLoaderTest.java b/owner/src/test/java/org/aeonbits/owner/customloader/CustomNamedLoaderTest.java new file mode 100644 index 00000000..be241f89 --- /dev/null +++ b/owner/src/test/java/org/aeonbits/owner/customloader/CustomNamedLoaderTest.java @@ -0,0 +1,90 @@ + +package org.aeonbits.owner.customloader; + +import static org.junit.Assert.*; + +import java.util.Properties; + +import org.aeonbits.owner.Config; +import org.aeonbits.owner.Config.Sources; +import org.aeonbits.owner.ConfigFactory; +import org.aeonbits.owner.loaders.AbstractNamedCustomLoader; +import org.aeonbits.owner.loaders.ConfigurationSourceNotFoundException; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * @author pgaschuetz + */ +public class CustomNamedLoaderTest { + + + public static interface SampleConfig extends Config { + public String favoriteColor(); + @DefaultValue("Bob") + public String favoriteName(); + } + + public static interface SampleConfigForSourceNotFoundException extends Config { + public String favoriteColor(); + @DefaultValue("Bob") + public String favoriteName(); + } + + @Sources({"owner://customloader"}) + public static interface SampleConfigWithSources extends Config { + public String favoriteColor(); + } + + static class CustomNamedLoader extends AbstractNamedCustomLoader { + + public CustomNamedLoader() { + super("customloader"); + } + + @Override + protected void doLoadInternal(Properties result, String arg) throws ConfigurationSourceNotFoundException { + + if("org/aeonbits/owner/customloader/CustomNamedLoaderTest$SampleConfigForSourceNotFoundException".equals(arg)) { + throw new ConfigurationSourceNotFoundException(); + } else { + String val = arg == null ? "lightblack" : "darkblack"; + result.put("favoriteColor", val); + result.put("favoriteName", "Alice"); + } + } + } + + @BeforeClass + public static void beforeTestClass() { + ConfigFactory.resetLoaders(); + ConfigFactory.registerLoader( new CustomNamedLoader() ); + } + + @AfterClass + public static void afterTestClass() { + ConfigFactory.resetLoaders(); + } + + @Test + public void testCustomNamedLoader() { + SampleConfig config = ConfigFactory.create(SampleConfig.class); + assertEquals("darkblack", config.favoriteColor()); + assertEquals("Alice", config.favoriteName()); + } + + @Test + public void testCustomNamedLoaderWithSources() { + SampleConfigWithSources config = ConfigFactory.create(SampleConfigWithSources.class); + assertEquals("lightblack", config.favoriteColor()); + } + + @Test + public void testCustomNamedLoaderWithInvalidSource() { + SampleConfigForSourceNotFoundException config = ConfigFactory.create(SampleConfigForSourceNotFoundException.class); + assertNull(config.favoriteColor()); + assertEquals("Bob", config.favoriteName()); + } + +} diff --git a/owner/src/test/java/org/aeonbits/owner/event/EventListenerOnReloadTest.java b/owner/src/test/java/org/aeonbits/owner/event/EventListenerOnReloadTest.java index bcbd2448..32ca1c33 100644 --- a/owner/src/test/java/org/aeonbits/owner/event/EventListenerOnReloadTest.java +++ b/owner/src/test/java/org/aeonbits/owner/event/EventListenerOnReloadTest.java @@ -25,6 +25,7 @@ import java.io.File; import java.io.IOException; import java.net.MalformedURLException; +import java.net.URISyntaxException; import java.util.Properties; import static org.aeonbits.owner.UtilTest.fileFromURL; @@ -62,7 +63,7 @@ public class EventListenerOnReloadTest implements TestConstants { private MyConfig cfg; @Before - public void before() throws MalformedURLException { + public void before() throws URISyntaxException { target = fileFromURL(SPEC); target.delete(); cfg = ConfigFactory.create(MyConfig.class); diff --git a/owner/src/test/java/org/aeonbits/owner/examples/AutoReloadExample.java b/owner/src/test/java/org/aeonbits/owner/examples/AutoReloadExample.java index c0f62e59..db7e2909 100644 --- a/owner/src/test/java/org/aeonbits/owner/examples/AutoReloadExample.java +++ b/owner/src/test/java/org/aeonbits/owner/examples/AutoReloadExample.java @@ -21,6 +21,7 @@ import java.io.File; import java.io.IOException; import java.net.MalformedURLException; +import java.net.URISyntaxException; import java.util.Date; import java.util.Properties; @@ -43,7 +44,7 @@ interface AutoReloadConfig extends Config, Reloadable { static { try { target = UtilTest.fileFromURL(SPEC); - } catch (MalformedURLException e) { + } catch (URISyntaxException e) { e.printStackTrace(); } } diff --git a/owner/src/test/java/org/aeonbits/owner/importedprops/ImportConfigTest.java b/owner/src/test/java/org/aeonbits/owner/importedprops/ImportConfigTest.java index a3ea816f..c9247f36 100644 --- a/owner/src/test/java/org/aeonbits/owner/importedprops/ImportConfigTest.java +++ b/owner/src/test/java/org/aeonbits/owner/importedprops/ImportConfigTest.java @@ -16,6 +16,7 @@ import java.io.File; import java.io.IOException; +import java.net.URISyntaxException; import java.util.Properties; import static org.aeonbits.owner.UtilTest.fileFromURL; @@ -71,7 +72,7 @@ public void testImportOrder() { } @Test - public void testThatImportedPropertiesHaveHigherPriorityThanPropertiesLoadedBySources() throws IOException { + public void testThatImportedPropertiesHaveHigherPriorityThanPropertiesLoadedBySources() throws IOException, URISyntaxException { File target = fileFromURL(SPEC); save(target, new Properties() {{ diff --git a/owner/src/test/java/org/aeonbits/owner/loadstrategies/DefaultLoadStrategyTest.java b/owner/src/test/java/org/aeonbits/owner/loadstrategies/DefaultLoadStrategyTest.java index 2987b660..6212030b 100644 --- a/owner/src/test/java/org/aeonbits/owner/loadstrategies/DefaultLoadStrategyTest.java +++ b/owner/src/test/java/org/aeonbits/owner/loadstrategies/DefaultLoadStrategyTest.java @@ -20,6 +20,7 @@ import org.mockito.runners.MockitoJUnitRunner; import java.io.IOException; +import java.net.URI; import java.net.URL; import java.util.Properties; import java.util.concurrent.ScheduledExecutorService; @@ -53,8 +54,8 @@ public void shouldReturnTheResourceForAClass() throws IOException { manager.load(); - verify(loaders, times(1)).findLoader(any(URL.class)); - verify(loaders, times(1)).findLoader(argThat(urlMatches( + verify(loaders, times(1)).findLoader(any(URI.class)); + verify(loaders, times(1)).findLoader(argThat(uriMatches( "org/aeonbits/owner/loadstrategies/DefaultLoadStrategyTest$SampleConfig.properties"))); } diff --git a/owner/src/test/java/org/aeonbits/owner/loadstrategies/FirstLoadStrategyTest.java b/owner/src/test/java/org/aeonbits/owner/loadstrategies/FirstLoadStrategyTest.java index b646a5ae..86261f1c 100644 --- a/owner/src/test/java/org/aeonbits/owner/loadstrategies/FirstLoadStrategyTest.java +++ b/owner/src/test/java/org/aeonbits/owner/loadstrategies/FirstLoadStrategyTest.java @@ -22,14 +22,12 @@ import org.mockito.runners.MockitoJUnitRunner; import java.io.IOException; -import java.net.URL; import java.util.Properties; import java.util.concurrent.ScheduledExecutorService; import static org.aeonbits.owner.Config.LoadType.FIRST; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; -import static org.mockito.Matchers.any; import static org.mockito.Matchers.argThat; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -105,8 +103,13 @@ public void shouldLoadURLFromSpecifiedSource() throws IOException { new PropertiesManagerForTest(SampleConfigWithSource.class, new Properties(), scheduler, expander, loaders); manager.load(); - verify(loaders, times(1)).findLoader(any(URL.class)); - verify(loaders, times(1)).findLoader(argThat(urlMatches("org/aeonbits/owner/FooBar.properties"))); + + /** + * This test is not valid anymore, since it expected LoadersManager#load to throw an IOException + * before LoadersManager#findLoader was executed + */ + //verify(loaders, times(1)).findLoader(any(URI.class)); + verify(loaders, times(1)).findLoader(argThat(uriMatches("org/aeonbits/owner/FooBar.properties"))); } @Test diff --git a/owner/src/test/java/org/aeonbits/owner/loadstrategies/LoadStrategyTestBase.java b/owner/src/test/java/org/aeonbits/owner/loadstrategies/LoadStrategyTestBase.java index fa5ab52b..b14d49f1 100644 --- a/owner/src/test/java/org/aeonbits/owner/loadstrategies/LoadStrategyTestBase.java +++ b/owner/src/test/java/org/aeonbits/owner/loadstrategies/LoadStrategyTestBase.java @@ -12,23 +12,24 @@ import org.hamcrest.Description; import org.hamcrest.Matcher; +import java.net.URI; import java.net.URL; /** * @author Luigi R. Viggiano */ public class LoadStrategyTestBase { - Matcher urlMatches(final String path) { - return new BaseMatcher(){ - public URL url; + Matcher uriMatches(final String path) { + return new BaseMatcher(){ + public URI uri; public boolean matches(Object o) { - url = (URL)o; - return url.getPath().endsWith(path); + uri = (URI)o; + return uri.getPath().endsWith(path); } public void describeTo(Description description) { - description.appendText("expected <" + (url != null ? url : "url") + "> ending with " + path); + description.appendText("expected <" + (uri != null ? uri : "uri") + "> ending with " + path); } }; } diff --git a/owner/src/test/java/org/aeonbits/owner/multithread/MultiThreadReloadTest.java b/owner/src/test/java/org/aeonbits/owner/multithread/MultiThreadReloadTest.java index 0c973ed4..5f169cee 100644 --- a/owner/src/test/java/org/aeonbits/owner/multithread/MultiThreadReloadTest.java +++ b/owner/src/test/java/org/aeonbits/owner/multithread/MultiThreadReloadTest.java @@ -20,6 +20,7 @@ import java.io.File; import java.net.MalformedURLException; +import java.net.URISyntaxException; import java.util.Properties; import static org.aeonbits.owner.UtilTest.fileFromURL; @@ -37,7 +38,7 @@ public class MultiThreadReloadTest extends MultiThreadTestBase implements TestCo private ReloadableConfig reloadableConfig; @BeforeClass - public static void beforeClass() throws MalformedURLException { + public static void beforeClass() throws URISyntaxException { target = fileFromURL(SPEC); } diff --git a/owner/src/test/java/org/aeonbits/owner/reload/AsyncAutoReloadTest.java b/owner/src/test/java/org/aeonbits/owner/reload/AsyncAutoReloadTest.java index e0d20dfc..33ff5454 100644 --- a/owner/src/test/java/org/aeonbits/owner/reload/AsyncAutoReloadTest.java +++ b/owner/src/test/java/org/aeonbits/owner/reload/AsyncAutoReloadTest.java @@ -21,6 +21,7 @@ import java.io.File; import java.net.MalformedURLException; +import java.net.URISyntaxException; import java.util.Properties; import static java.util.concurrent.TimeUnit.MILLISECONDS; @@ -42,7 +43,7 @@ public class AsyncAutoReloadTest extends AsyncReloadSupport implements TestConst private static File target; @BeforeClass - public static void beforeClass() throws MalformedURLException { + public static void beforeClass() throws URISyntaxException { target = fileFromURL(SPEC); } diff --git a/owner/src/test/java/org/aeonbits/owner/reload/ReloadTest.java b/owner/src/test/java/org/aeonbits/owner/reload/ReloadTest.java index 7254ec5d..c7d3948b 100644 --- a/owner/src/test/java/org/aeonbits/owner/reload/ReloadTest.java +++ b/owner/src/test/java/org/aeonbits/owner/reload/ReloadTest.java @@ -28,6 +28,7 @@ import java.io.File; import java.net.MalformedURLException; +import java.net.URISyntaxException; import java.util.Properties; import static org.aeonbits.owner.UtilTest.fileFromURL; @@ -48,7 +49,7 @@ public class ReloadTest implements TestConstants { ReloadListener listener; @BeforeClass - public static void beforeClass() throws MalformedURLException { + public static void beforeClass() throws URISyntaxException { target = fileFromURL(SPEC); } diff --git a/owner/src/test/java/org/aeonbits/owner/reload/SyncAutoReloadTest.java b/owner/src/test/java/org/aeonbits/owner/reload/SyncAutoReloadTest.java index 432f8b36..2c046813 100644 --- a/owner/src/test/java/org/aeonbits/owner/reload/SyncAutoReloadTest.java +++ b/owner/src/test/java/org/aeonbits/owner/reload/SyncAutoReloadTest.java @@ -22,6 +22,7 @@ import java.io.File; import java.io.IOException; import java.net.MalformedURLException; +import java.net.URISyntaxException; import java.util.Properties; import static java.util.concurrent.TimeUnit.SECONDS; @@ -48,7 +49,7 @@ public class SyncAutoReloadTest implements TestConstants { private static TimeProviderForTest time; @BeforeClass - public static void beforeClass() throws MalformedURLException { + public static void beforeClass() throws URISyntaxException { target = fileFromURL(SPEC); jarTarget = new File(JAR_FILE); }