/* * Copyright 2008-2014 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.kaleidofoundry.core.config; import java.io.Serializable; import java.math.BigDecimal; import java.math.BigInteger; import java.net.URI; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Properties; import java.util.Set; import org.kaleidofoundry.core.cache.Cache; import org.kaleidofoundry.core.config.model.FireChangesReport; import org.kaleidofoundry.core.context.Provider; import org.kaleidofoundry.core.context.Scope; import org.kaleidofoundry.core.lang.annotation.NotNull; import org.kaleidofoundry.core.lang.annotation.Nullable; import org.kaleidofoundry.core.lang.annotation.ThreadSafe; import org.kaleidofoundry.core.plugin.Declare; import org.kaleidofoundry.core.store.ClasspathFileStore; import org.kaleidofoundry.core.store.FileStore; import org.kaleidofoundry.core.store.FileSystemStore; import org.kaleidofoundry.core.store.FtpStore; import org.kaleidofoundry.core.store.HttpFileStore; import org.kaleidofoundry.core.store.JpaFileStore; import org.kaleidofoundry.core.store.ResourceException; /** * <p> * Interface used to access <b>runtime configuration data</b> from your application (this data could be this data could be technical / * environmental / application / ...). A {@link Configuration} is like a set of key identifier / value(s) (as {@link Properties}) but with * more functionalities ({@link Cache}, typed accessor, changed events...).<br/> * <br/> * The goal of these interface, is to <b>provide an unique and uniform way to manage for the runtime configuration of your application.</b><br/> * Multiple formats and implementations are provided by default, like : * <ul> * <li>Classic java properties file - {@link PropertiesConfiguration},</li> * <li>Xml java properties file - {@link XmlPropertiesConfiguration},</li> * <li>Xml custom properties file - {@link XmlConfiguration},</li> * <li>Java system variables set - {@link JavaSystemConfiguration},</li> * <li>OS environment variables set - {@link OsEnvConfiguration},</li> * <li>Java main args variables set - {@link MainArgsConfiguration}</li> * <li>...</li> * </ul> * <br/> * <b>The configuration resource content (usually file)</b> could be accessed through different way, using URI : <br/> * <br/> * <ul> * <li>File system - {@link FileSystemStore},</li> * <li>Java classpath - {@link ClasspathFileStore},</li> * <li>Http url - {@link HttpFileStore},</li> * <li>Ftp url - {@link FtpStore},</li> * <li>Jpa custom url - {@link JpaFileStore},</li> * <li>...</li> * </ul> * The type of the uri will determine the sub {@link FileStore} to use <br/> * <p> * <b>With your configuration instance, you can managed :</b> * <ul> * <li>load configuration store</li> * <li>unload configuration store</li> * <li>store (persist) configuration</li> * </ul> * </p> * <br/> * <b>Configuration properties can be accessible locally or via a cache cluster (see {@link ConfigurationContextBuilder}) </b> <br/> * Each functionalities {@link #load()}, {@link #store()}, {@link #unload()}, {@link #getProperty(String)}, * {@link #setProperty(String, Serializable)} can use caches functionalities * </p> * <p> * <b>Configuration listener :</b> {@link ConfigurationListener} <br/> * To use configuration listener, you can register your own using : {@link #addConfigurationListener(ConfigurationListener)} <br/> * This listener enables to trap : * <ul> * <li>{@link ConfigurationListener#propertyCreate(ConfigurationChangeEvent)}</li> * <li>{@link ConfigurationListener#propertyUpdate(ConfigurationChangeEvent)}</li> * <li>{@link ConfigurationListener#propertyRemove(ConfigurationChangeEvent)}</li> * <li>{@link ConfigurationListener#configurationUnload(Configuration)}</li> * </ul> * </p> * <br/> * <p> * <a href="package-summary.html"/>Package description</a> * </p> * <p> * Implementation have to be thread safe * </p> * <b>Use case :</b><br/> * <br/> * For the following properties file (named "appConfig" in the following javadoc) implements by {@link PropertiesConfiguration} : * * <pre> * application.name=app * application.version=1.0.0 * application.description=description of the application... * application.date=2006-09-01T00:00:00 * application.librairies=dom4j.jar log4j.jar mail.jar * * application.modules.sales=Sales * application.modules.sales.version=1.1.0 * application.modules.marketing=Market. * application.modules.netbusiness= * </pre> * <p> * Sample of configuration <b>key</b> identifiers: * <ul> * <li><code>configuration.getString("//application/name") -> "app"</code></li> * <li><code>configuration.getString("//application/version") -> "1.0.0"</code></li> * <li><code>configuration.getStringList("//application/libraries") -> {"dom4j.jar","log4j.jar","mail.jar"}</code></li> * </ul> * Informations : * <ul> * <li>-><code>'//'</code> represents the root</li> * <li>-><code>'/'</code> represents the key separator</li> * </ul> * You can also used standard java properties format : * <ul> * <li><code>configuration.getString("application.name") -> "app"</code></li> * <li><code>configuration.getString("application.version") -> "1.0.0"</code></li> * <li><code>configuration.getStringList("application.libraries") -> {"dom4j.jar","log4j.jar","mail.jar"}</code></li> * </ul> * </ul> * </p> * * @see FileStore * @see NamedConfiguration * @see NamedConfigurations * @author jraduget */ @ThreadSafe @Declare(ConfigurationConstants.ConfigurationPluginName) @Provider(value = ConfigurationProvider.class, scope=Scope.singleton) public interface Configuration { /** * @return configuration name (have to be unique) */ String getName(); /** * @return configuration resource {@link URI} */ String getResourceUri(); // ************************************************************************** // -> Property configuration access management // ************************************************************************** /** * @param key key identifier (unique) * @return get the raw property value <br> */ Serializable getProperty(@NotNull String key); /** * @param key property name * @param type type of the return value * @return value of the property * @param <T> */ <T extends Serializable> T getProperty(final String key, final Class<T> type); /** * @param key property name * @param type type of the return value * @return values of the property * @param <T> */ <T extends Serializable> List<T> getPropertyList(final String key, final Class<T> type); /** * add or update property value * * @param key key identifier (unique) * @param value property value to set * @throws IllegalStateException if configuration is for read-only use * @see #addConfigurationListener(ConfigurationListener) to register a listener on change */ void setProperty(@NotNull String key, @NotNull Serializable value); /** * Remove given property (if property key does not exist, do nothing) * * @param key key identifier (unique) * @throws IllegalStateException if configuration is for read-only use * @see #addConfigurationListener(ConfigurationListener) to register a listener on remove */ void removeProperty(@NotNull String key); // ************************************************************************** // -> changes listener // ************************************************************************** /** * add a configuration changes listener * * @param listener */ void addConfigurationListener(ConfigurationListener listener); /** * remove a configuration changes listener * * @param listener */ void removeConfigurationListener(ConfigurationListener listener); /** * fire all configuration changes events (create, update, remove) since the last call<br/> * events are fired in the order of creation * * @return report of configurations changes which have been fired */ FireChangesReport fireConfigurationChangesEvents(); // ************************************************************************** // -> Keys management // ************************************************************************** /** * @return Iterator for all declared property keys * @see #keySet() */ @NotNull Iterator<String> keysIterator(); /** * @param prefix prefix key name filtering * @return keys iterator filtered * @see #keySet(String) */ @NotNull Iterator<String> keysIterator(@NotNull String prefix); /** * <p> * For the top class properties example, implements by{@link PropertiesConfiguration} : * * <pre> * configuration.keySet()= {"//application/name", "//application/version", "//application/description", "//application/date", "//application/librairies", "application.modules.sales", ...} * </pre> * * </p> * * @return a set (clone) of all the declared property keys <br/> */ @NotNull Set<String> keySet(); /** * @param prefix prefix key name filtering * @return a set (clone) of all declared property keys filtered by prefix argument */ @NotNull Set<String> keySet(@NotNull String prefix); /** * @param key property key to find * @return <code>true</code>if key exists, <code>false</code> otherwise */ boolean containsKey(String key); /** * @param key property key to find * @param prefixKey property name prefix filtering * @return <code>true</code>if key exists, <code>false</code> otherwise */ boolean containsKey(String key, @NotNull String prefixKey); // ************************************************************************** // -> Roots management // ************************************************************************** /** * @return Roots iterator * @see #roots() */ @NotNull Iterator<String> rootsIterator(); /** * @param prefix root prefix filtered * @return Roots iterator, which began with prefix arg * @see #roots(String) */ @NotNull Iterator<String> rootsIterator(@NotNull String prefix); /** * @return All existing root keys of a configuration file<br/> * <p> * For the following properties file, implements by{@link PropertiesConfiguration} : * * <pre> * application.name=app * application.version=1.0.0 * application.description=description of the application... * application.date=2006-09-01T00:00:00 * application.librairies=dom4j.jar log4j.jar mail.jar * * application.modules.sales=Sales * application.modules.sales.version=1.1.0 * application.modules.marketing=Market. * application.modules.netbusiness= * </pre> * * <pre> * configuration.roots()= {"application"} * </pre> * * </p> */ @NotNull Set<String> roots(); /** * @param prefix root prefix filtered * @return All existing root keys, that begins by prefix argument <br/> * <p> * For the following properties file (application.properties), implements by{@link PropertiesConfiguration} : * * <pre> * application.name=app * application.version=1.0.0 * application.description=description of the application... * application.date=2006-09-01T00:00:00 * application.librairies=dom4j.jar log4j.jar mail.jar * * application.modules.sales=Sales * application.modules.sales.version=1.1.0 * application.modules.marketing=Market. * application.modules.netbusiness= * </pre> * * Java program sample : * * <pre> * configuration = ... // create via instance injection, method injection, or manually new ...Configuration() implementation * configuration.load(); * configuration.roots("//application/modules") = {"sales", "marketing", "netbusiness"} * </pre> * * </p> */ @NotNull Set<String> roots(@NotNull String prefix); /** * @param rootKey name of the root to find * @param prefix Search prefix for the requested root * @return <code>true</code>if rootKey exists, <code>false</code> otherwise <br/> * <p> * For the following properties file (application.properties), implements by{@link PropertiesConfiguration} : * * <pre> * application.name=app * application.version=1.0.0 * application.description=description of the application... * application.date=2006-09-01T00:00:00 * application.librairies=dom4j.jar log4j.jar mail.jar * * application.modules.sales=Sales * application.modules.sales.version=1.1.0 * application.modules.marketing=Market. * application.modules.netbusiness= * </pre> * * Java program sample : * * <pre> * configuration = ... // create via instance injection, method injection, or manually new ...Configuration() implementation * configuration.load(); * configuration.containsRoot("sales", "//application/modules")) -> true * configuration.containsRoot("foo", "//application/modules")) -> false * </pre> * * </p> */ boolean containsRoot(String rootKey, @NotNull String prefix); // ************************************************************************** // -> Tools // ************************************************************************** /** * @return Properties converter (clone copy) */ @NotNull Properties toProperties(); /** * @param prefix prefix keys filtered * @return Properties converter, filtered by root prefix */ @NotNull Properties toProperties(String prefix); /** * @return String Representation */ String toString(); /** * @param prefix prefix filtered * @param outConfiguration configuration identifier * @return an extraction a subset of the current configuration instance for keys starting with prefix argument<br/> * it will returns the outConfiguration argument instance, with the addition of the current extracting values <br/> * <p> * For the following properties file (application.properties), implements by{@link PropertiesConfiguration} : * * <pre> * application.name=app * application.version=1.0.0 * application.description=description of the application... * application.date=2006-09-01T00:00:00 * application.librairies=dom4j.jar log4j.jar mail.jar * * application.modules.sales=Sales * application.modules.sales.version=1.1.0 * application.modules.marketing=Market. * application.modules.netbusiness= * </pre> * * Java program sample : * * <pre> * configuration = ... // create via instance injection, method injection, or manually new ...Configuration() implementation * outputConfigration = ... // create via instance injection, method injection, or manually new ...Configuration() implementation * * configuration.load(); * * configuration.extractConfiguration("//application/modules", emptyConfiguration); * outputConfigration.store(); * * </pre> * * Output configuration will containing : * * <pre> * sales=Sales * sales.version=1.1.0 * marketing=Market. * netbusiness= * </pre> */ Configuration extractConfiguration(@NotNull String prefix, @NotNull Configuration outConfiguration); /** * Add another configuration content to current instance.<br/> * The configuration argument overides the current configuration content<br/> * * @param configuration configuration to add * @return Merge configuration (configuration argument crushes same existing * properties) */ Configuration addConfiguration(@NotNull Configuration configuration); // ************************************************************************** // -> Load / store management // ************************************************************************** /** * load configuration content * * @throws ResourceException * @throws ConfigurationException if configuration is already loaded */ void load() throws ResourceException, ConfigurationException; /** * unload configuration content * * @throws ResourceException * @throws ConfigurationException if configuration is not loaded * @see #addConfigurationListener(ConfigurationListener) to register a listener on unload */ void unload() throws ResourceException, ConfigurationException; /** * reload all configuration content * * @throws ConfigurationException if configuration is not loaded * @see #addConfigurationListener(ConfigurationListener) to register a listener for changed values */ void reload() throws ResourceException, ConfigurationException; /** * @return Configuration have been loaded ? <code>true/false</code> */ boolean isLoaded(); /** * Persist all configuration datas (with updade) * * @throws ResourceException * @throws ConfigurationException if configuration is not loaded, or is for readonly use */ void store() throws ResourceException, ConfigurationException; /** * @return does configuration allowed storage */ boolean isStorable(); /** * @return does configuration allowed item updates */ boolean isUpdateable(); // ************************************************************************** // -> Property value accessors // ************************************************************************** /** * @param key requested property key * @return value of the property requested (null if not defined) */ @Nullable String getString(@NotNull String key); /** * @param key requested property key * @param defaultValue Default value if property content is null * @return value of the property requested if defined, otherwise defaultValue argument */ @Nullable String getString(@NotNull String key, String defaultValue); /** * @param key requested property key * @return values of the property requested */ @Nullable List<String> getStringList(@NotNull String key); // ************************************************************************** // -> Typed property value accessors // ************************************************************************** /** * @param key requested property key * @return value of the property requested (null if not defined) */ @Nullable Character getCharacter(@NotNull String key); /** * @param key requested property key * @param defaultValue Default value if property content is null * @return value of the property requested if defined, otherwise defaultValue argument */ @Nullable Character getCharacter(@NotNull String key, Character defaultValue); /** * @param key requested property key * @return values of the property requested */ @Nullable List<Character> getCharacterList(@NotNull String key); /** * @param key requested property key * @return values of the property requested * @throws NumberFormatException */ @Nullable BigDecimal getBigDecimal(@NotNull String key) throws NumberFormatException; /** * @param key requested property key * @param defaultValue Default value if property content is null * @return value of the property requested if defined, otherwise defaultValue argument * @throws NumberFormatException */ @Nullable BigDecimal getBigDecimal(@NotNull String key, BigDecimal defaultValue) throws NumberFormatException; /** * @param key requested property key * @return Multiple values of the requested property (null if not defined) * @throws NumberFormatException */ @Nullable List<BigDecimal> getBigDecimalList(@NotNull String key) throws NumberFormatException; /** * @param key requested property key * @return value of the property requested (null if not defined) * @throws NumberFormatException */ @Nullable BigInteger getBigInteger(@NotNull String key) throws NumberFormatException; /** * @param key requested property key * @param defaultValue Default value if property content is null * @return value of the property requested if defined, otherwise defaultValue argument * @throws NumberFormatException */ @Nullable BigInteger getBigInteger(@NotNull String key, BigInteger defaultValue) throws NumberFormatException; /** * @param key requested property key * @return Multiple values of the requested property (null if not defined) * @throws NumberFormatException */ @Nullable List<BigInteger> getBigIntegerList(@NotNull String key) throws NumberFormatException; /** * @param key requested property key * @return value of the property requested (null if not defined) */ @Nullable Boolean getBoolean(@NotNull String key); /** * @param key requested property key * @param defaultValue Default value if property content is null * @return value of the property requested if defined, otherwise defaultValue argument */ @Nullable Boolean getBoolean(@NotNull String key, Boolean defaultValue); /** * @param key requested property key * @return Multiple values of the requested property (null if not defined) */ @Nullable List<Boolean> getBooleanList(@NotNull String key); /** * @param key requested property key * @return value of the property requested (null if not defined) */ @Nullable Byte getByte(@NotNull String key); /** * @param key requested property key * @param defaultValue Default value if property content is null * @return value of the property requested if defined, otherwise defaultValue argument */ @Nullable Byte getByte(@NotNull String key, Byte defaultValue); /** * @param key requested property key * @return Multiple values of the requested property (null if not defined) */ @Nullable List<Byte> getByteList(@NotNull String key); /** * @param key requested property key * @return value of the property requested (null if not defined) * @throws NumberFormatException */ @Nullable Double getDouble(@NotNull String key); /** * @param key requested property key * @param defaultValue Default value if property content is null * @return value of the property requested if defined, otherwise defaultValue argument * @throws NumberFormatException */ @Nullable Double getDouble(@NotNull String key, Double defaultValue); /** * @param key requested property key * @return Multiple values of the requested property (null if not defined) * @throws NumberFormatException */ @Nullable List<Double> getDoubleList(@NotNull String key); /** * @param key requested property key * @return value of the property requested (null if not defined) * @throws NumberFormatException */ @Nullable Float getFloat(@NotNull String key) throws NumberFormatException; /** * @param key requested property key * @param defaultValue Default value if property content is null * @return value of the property requested if defined, otherwise defaultValue argument * @throws NumberFormatException */ @Nullable Float getFloat(@NotNull String key, Float defaultValue) throws NumberFormatException; /** * @param key requested property key * @return Multiple values of the requested property (null if not defined) * @throws NumberFormatException */ @Nullable List<Float> getFloatList(@NotNull String key) throws NumberFormatException; /** * @param key requested property key * @return value of the property requested (null if not defined) * @throws NumberFormatException */ @Nullable Integer getInteger(@NotNull String key) throws NumberFormatException; /** * @param key requested property key * @param defaultValue Default value if property content is null * @return value of the property requested if defined, otherwise defaultValue argument * @throws NumberFormatException */ @Nullable Integer getInteger(@NotNull String key, Integer defaultValue) throws NumberFormatException; /** * @param key requested property key * @return Multiple values of the requested property (null if not defined) * @throws NumberFormatException */ @Nullable List<Integer> getIntegerList(@NotNull String key) throws NumberFormatException; /** * @param key requested property key * @return value of the property requested (null if not defined) * @throws NumberFormatException */ @Nullable Long getLong(@NotNull String key) throws NumberFormatException; /** * @param key requested property key * @param defaultValue Default value if property content is null * @return value of the property requested if defined, otherwise defaultValue argument * @throws NumberFormatException */ @Nullable Long getLong(@NotNull String key, Long defaultValue) throws NumberFormatException; /** * @param key requested property key * @return Multiple values of the requested property (null if not defined) * @throws NumberFormatException */ @Nullable List<Long> getLongList(@NotNull String key) throws NumberFormatException; /** * @param key requested property key * @return value of the property requested (null if not defined) * @throws NumberFormatException */ @Nullable Short getShort(@NotNull String key) throws NumberFormatException; /** * @param key requested property key * @param defaultValue Default value if property content is null * @return value of the property requested if defined, otherwise defaultValue argument * @throws NumberFormatException */ @Nullable Short getShort(@NotNull String key, Short defaultValue) throws NumberFormatException; /** * @param key requested property key * @return Multiple values of the requested property (null if not defined) * @throws NumberFormatException */ @Nullable List<Short> getShortList(@NotNull String key) throws NumberFormatException; /** * @param key requested property key * @return value of the property requested (null if not defined) */ @Nullable Date getDate(@NotNull String key); /** * @param key requested property key * @param defaultValue Default value if property content is null * @return value of the property requested if defined, otherwise defaultValue argument */ @Nullable Date getDate(@NotNull String key, Date defaultValue); /** * @param key requested property key * @return Multiple values of the requested property (null if not defined) */ @Nullable List<Date> getDateList(final @NotNull String key); }