Added tests for OSGI support, simplified OSGI support. Implemented base functionality for metamodel support, including first testing.
Project: http://git-wip-us.apache.org/repos/asf/incubator-tamaya-sandbox/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-tamaya-sandbox/commit/afc19d0e Tree: http://git-wip-us.apache.org/repos/asf/incubator-tamaya-sandbox/tree/afc19d0e Diff: http://git-wip-us.apache.org/repos/asf/incubator-tamaya-sandbox/diff/afc19d0e Branch: refs/heads/master Commit: afc19d0e74cde66603dc3d440d6799b917efb815 Parents: f0dfa86 Author: anatole <anat...@apache.org> Authored: Mon Dec 12 17:12:06 2016 +0100 Committer: anatole <anat...@apache.org> Committed: Mon Dec 12 17:12:06 2016 +0100 ---------------------------------------------------------------------- metamodel/pom.xml | 7 + .../org/apache/tamaya/metamodel/Context.java | 171 ----- .../metamodel/FilteredPropertySource.java | 166 +++++ .../tamaya/metamodel/MetaConfiguration.java | 144 ++++ .../apache/tamaya/metamodel/MetaContext.java | 330 ++++++++++ .../apache/tamaya/metamodel/Refreshable.java | 32 + .../metamodel/RefreshablePropertySource.java | 150 +++++ .../RefreshablePropertySourceProvider.java | 106 +++ .../tamaya/metamodel/dsl/MetaConfiguration.java | 122 ---- .../metamodel/dsl/TamayaConfigurator.java | 234 ------- .../metamodel/dsl/WrappedPropertySource.java | 127 ---- .../DSLLoadingConfigurationProviderSpi.java | 81 --- .../NamedDSLPropertySourceProvider.java | 53 -- .../ResourceDSLPropertySourceProvider.java | 82 --- .../internal/CombinationPolicyReader.java | 61 ++ .../internal/ComponentConfigurator.java | 87 +++ .../metamodel/internal/ComponentFactory.java | 112 ++++ .../metamodel/internal/ContextReader.java | 66 ++ .../DSLLoadingConfigurationProviderSpi.java | 114 ++++ ...efaultRefreshablePropertySourceProvider.java | 72 -- .../metamodel/internal/FactoryManager.java | 140 ---- .../internal/PropertyConverterReader.java | 88 +++ .../internal/PropertyFilterOrderingReader.java | 63 ++ .../internal/PropertyFilterReader.java | 83 +++ .../internal/PropertySourceOrderingReader.java | 64 ++ .../internal/PropertySourceReader.java | 103 +++ .../tamaya/metamodel/internal/Refreshable.java | 37 -- .../tamaya/metamodel/internal/SourceConfig.java | 466 ++++++------- .../internal/factories/CLIArgumentsFactory.java | 47 ++ .../factories/EnvPropertiesFactory.java | 46 ++ .../factories/FilePropertySourceFactory.java | 77 +++ .../ResourcePropertySourceFactory.java | 64 ++ .../ResourcePropertySourceProviderFactory.java | 115 ++++ .../factories/SysPropertiesFactory.java | 46 ++ .../factories/URLPropertySourceFactory.java | 152 +++++ .../tamaya/metamodel/spi/ItemFactory.java | 51 ++ .../metamodel/spi/ItemFactoryManager.java | 145 ++++ .../metamodel/spi/MetaConfigurationReader.java | 8 +- .../metamodel/spi/PropertySourceFactory.java | 48 -- .../spi/PropertySourceProviderFactory.java | 49 -- ...maya.metamodel.spi.DSLPropertySourceProvider | 20 - .../org.apache.tamaya.metamodel.spi.ItemFactory | 26 + ...tamaya.metamodel.spi.MetaConfigurationReader | 26 + ...g.apache.tamaya.spi.ConfigurationProviderSpi | 3 +- .../resources/IntegrationTests/empty-config.xml | 24 + metamodel/src/test/resources/tamaya-config.xml | 73 ++- pom.xml | 657 ++++++++++++++++++- 47 files changed, 3529 insertions(+), 1509 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-tamaya-sandbox/blob/afc19d0e/metamodel/pom.xml ---------------------------------------------------------------------- diff --git a/metamodel/pom.xml b/metamodel/pom.xml index 13c5c47..a103441 100644 --- a/metamodel/pom.xml +++ b/metamodel/pom.xml @@ -71,6 +71,13 @@ <artifactId>tamaya-formats</artifactId> <version>${project.version}</version> </dependency> + <dependency> + <groupId>org.apache.tamaya.ext</groupId> + <artifactId>tamaya-resources</artifactId> + <version>${project.version}</version> + <scope>provided</scope> + <optional>true</optional> + </dependency> <!--<dependency>--> <!--<groupId>org.apache.tamaya.ext</groupId>--> <!--<artifactId>tamaya-json</artifactId>--> http://git-wip-us.apache.org/repos/asf/incubator-tamaya-sandbox/blob/afc19d0e/metamodel/src/main/java/org/apache/tamaya/metamodel/Context.java ---------------------------------------------------------------------- diff --git a/metamodel/src/main/java/org/apache/tamaya/metamodel/Context.java b/metamodel/src/main/java/org/apache/tamaya/metamodel/Context.java deleted file mode 100644 index b4b65d2..0000000 --- a/metamodel/src/main/java/org/apache/tamaya/metamodel/Context.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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.apache.tamaya.metamodel; - -import java.util.Collections; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -/** - * Class managing the configuration system's shared context. This - * context is used by the configuration system to evaluate the - * right properties, e.g. by defining the current stage or labels - * that apply to the current configuration. - */ -public final class Context { - - private static final ThreadLocal<Context> THREAD_CONTEXT = new ThreadLocal<Context>(){ - @Override - protected Context initialValue() { - return new Context(); - } - }; - - private final Map<String,String> properties = new ConcurrentHashMap<>(); - - /** - * Access the thread-based context. If no such context - * exists a new one will be created. - * @return the corresponding context, never null. - */ - public static Context getThreadInstance(){ - return THREAD_CONTEXT.get(); - } - - /** - * Access the current context, which actually is the current context, combined with the thread based - * context (overriding). - * @return the corresponding context, never null. - */ - public Context getCurrentInstance(){ - return this.combineWith(THREAD_CONTEXT.get()); - } - - /** - * Combine this context with the other contexts given. - * @param contexts the context to merge with this context. - * @return the newly created Context. - */ - public Context combineWith(Context... contexts) { - Context newContext = new Context(); - newContext.properties.putAll(getProperties()); - for(Context ctx:contexts) { - newContext.properties.putAll(ctx.getProperties()); - } - return newContext; - } - - /** - * Access the given context property. - * @param key the key, not null - * @return the value, or null. - */ - public String getProperty(String key){ - return getProperty(key, null); - } - - /** - * Access the given context property. - * @param key the key, not the default value. - * @param defaultValue the default value to be returned, if no value is defined. - * @return the value, default value or null. - */ - public String getProperty(String key, String defaultValue){ - String value = this.properties.get(key); - if(value==null){ - return defaultValue; - } - return value; - } - - /** - * Sets the given context property. - * @param key the key, not null. - * @param value the value, not null. - * @return the porevious value, or null. - */ - public String setProperty(String key, String value){ - return this.properties.put(key,value); - } - - /** - * Sets the given property unless there is already a value defined. - * @param key the key, not null. - * @param value the value, not null. - */ - public void setPropertyIfAbsent(String key, String value){ - String prev = this.properties.get(key); - if(prev==null){ - this.properties.put(key, prev); - } - } - - /** - * Adds all properties given, overriding any existing properties. - * @param properties the properties, not null. - */ - public void setProperties(Map<String,String> properties){ - this.properties.putAll(properties); - } - - /** - * Checks if all the given properties are present. - * @param keys the keys to check, not null. - * @return true, if all the given keys are existing. - */ - public boolean checkProperties(String... keys){ - for(String key:keys) { - if (getProperty(key, null) == null) { - return false; - } - } - return true; - } - - /** - * Access all the current context properties. - * @return the properties, never null. - */ - public Map<String,String> getProperties(){ - return Collections.unmodifiableMap(this.properties); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof Context)) return false; - - Context context = (Context) o; - - return getProperties().equals(context.getProperties()); - - } - - @Override - public int hashCode() { - return getProperties().hashCode(); - } - - @Override - public String toString() { - return "Context{" + - properties + - '}'; - } -} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-sandbox/blob/afc19d0e/metamodel/src/main/java/org/apache/tamaya/metamodel/FilteredPropertySource.java ---------------------------------------------------------------------- diff --git a/metamodel/src/main/java/org/apache/tamaya/metamodel/FilteredPropertySource.java b/metamodel/src/main/java/org/apache/tamaya/metamodel/FilteredPropertySource.java new file mode 100644 index 0000000..b4f95f5 --- /dev/null +++ b/metamodel/src/main/java/org/apache/tamaya/metamodel/FilteredPropertySource.java @@ -0,0 +1,166 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.tamaya.metamodel; + +import org.apache.tamaya.spi.FilterContext; +import org.apache.tamaya.spi.PropertyFilter; +import org.apache.tamaya.spi.PropertySource; +import org.apache.tamaya.spi.PropertyValue; +import org.apache.tamaya.spisupport.BasePropertySource; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +/** + * Property source that allows filtering on property source level. This class is thread-safe, accesses using or + * changing the filter list are synchronized. + */ +public final class FilteredPropertySource extends BasePropertySource { + + private PropertySource wrapped; + private List<PropertyFilter> filters = new ArrayList<>(); + + /** + * Constructor used privately. Use {@link #of(PropertySource)} for making a {@link PropertySource} filterable. + * @param propertySource the property source to be filtered. + */ + private FilteredPropertySource(PropertySource propertySource){ + this.wrapped = Objects.requireNonNull(propertySource); + } + + + /** + * Wraps a given property source. + * @param propertySource the property source to be wrapped. + * @return a wrapped property source. + */ + public static FilteredPropertySource of(PropertySource propertySource){ + if(propertySource instanceof FilteredPropertySource){ + return (FilteredPropertySource)propertySource; + } + return new FilteredPropertySource(propertySource); + } + + @Override + public int getOrdinal() { + int ordinalSet = super.getOrdinal(); + if(ordinalSet == 0){ + return this.wrapped.getOrdinal(); + } + return ordinalSet; + } + + @Override + public String getName() { + return wrapped.getName(); + } + + @Override + public PropertyValue get(String key) { + PropertyValue value = wrapped.get(key); + if(value != null && value.getValue()!=null){ + if(filters!=null){ + String filteredValue = value.getValue(); + for(PropertyFilter pf:filters){ + filteredValue = pf.filterProperty(filteredValue, new FilterContext(key, value.getConfigEntries(), true)); + } + if(filteredValue!=null){ + return PropertyValue.builder(key, filteredValue, getName()) + .setContextData(value.getConfigEntries()).build(); + } + } + } + return value; + } + + @Override + public Map<String, String> getProperties() { + Map<String, String> wrappedProps = wrapped.getProperties(); + if(!filters.isEmpty()){ + Map<String, String> result = new HashMap<>(); + synchronized (filters) { + for (String key : wrappedProps.keySet()) { + PropertyValue value = wrapped.get(key); + FilterContext filterContext = new FilterContext(key, value.getConfigEntries(), true); + String filteredValue = value.getValue(); + for (PropertyFilter pf : filters) { + filteredValue = pf.filterProperty(filteredValue, filterContext); + } + if (filteredValue != null) { + result.putAll(value.getConfigEntries()); + result.put(key, filteredValue); + } + + } + } + return result; + } + return wrappedProps; + } + + @Override + public boolean isScannable() { + return wrapped.isScannable(); + } + + /** + * Adds the given filters to this property source. + * @param filter the filters, not null. + */ + public void addPropertyFilter(PropertyFilter... filter){ + synchronized(filters){ + this.filters.addAll(Arrays.asList(filter)); + } + } + + /** + * Removes the given filter, if present. + * @param filter the filter to remove, not null. + */ + public void removePropertyFilter(PropertyFilter filter){ + synchronized(filters){ + this.filters.remove(filter); + } + } + + /** + * Access the current filters present. + * @return a copy of the current filter list. + */ + public List<PropertyFilter> getPropertyFilter(){ + synchronized (filters){ + return new ArrayList<>(filters); + } + } + + @Override + public String toString() { + synchronized (filters) { + return "FilteredPropertySource{" + + "\n wrapped=" + wrapped + + "\n filters=" + this.filters + + "\n base=" + super.toString() + + "\n}"; + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-sandbox/blob/afc19d0e/metamodel/src/main/java/org/apache/tamaya/metamodel/MetaConfiguration.java ---------------------------------------------------------------------- diff --git a/metamodel/src/main/java/org/apache/tamaya/metamodel/MetaConfiguration.java b/metamodel/src/main/java/org/apache/tamaya/metamodel/MetaConfiguration.java new file mode 100644 index 0000000..601c851 --- /dev/null +++ b/metamodel/src/main/java/org/apache/tamaya/metamodel/MetaConfiguration.java @@ -0,0 +1,144 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.tamaya.metamodel; + +import org.apache.tamaya.ConfigException; +import org.apache.tamaya.Configuration; +import org.apache.tamaya.ConfigurationProvider; +import org.apache.tamaya.metamodel.spi.MetaConfigurationReader; +import org.apache.tamaya.spi.ConfigurationContext; +import org.apache.tamaya.spi.ConfigurationContextBuilder; +import org.apache.tamaya.spi.ServiceContextManager; +import org.w3c.dom.Document; +import org.xml.sax.SAXException; + +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Objects; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Accessor singleton for accessing/loading meta-configuration. + */ +public final class MetaConfiguration { + + private static final String CONFIG_RESOURCE = "tamaya-config.xml"; + + private static final Logger LOG = Logger.getLogger(MetaConfiguration.class.getName()); + + /** + * Singleton constructor. + */ + private MetaConfiguration(){} + + /** + * Creates a new {@link Configuration} using {@link #createConfiguration(URL)} + * and applies it as default configuration using {@link ConfigurationProvider#setConfiguration(Configuration)}. + * @return the new configuration instance. + */ + public static void configure(){ + LOG.info("TAMAYA: Checking for meta-configuration..."); + URL configFile = getDefaultMetaConfig(); + if(configFile==null){ + LOG.warning("TAMAYA: No tamaya-config.xml found, using defaults."); + } + configure(configFile); + } + + /** + * Creates a new {@link Configuration} using {@link #createConfiguration(URL)} + * and applies it as default configuration using {@link ConfigurationProvider#setConfiguration(Configuration)}. + * @param metaConfig URL for loading the {@code tamaya-config.xml} meta-configuration. + * @return the new configuration instance. + */ + public static void configure(URL metaConfig){ + try { + // Let readers do their work + Configuration config = createConfiguration(metaConfig); + ConfigurationProvider.setConfiguration(config); + }catch(Exception e){ + LOG.log(Level.SEVERE, "TAMAYA: Error loading configuration.", e); + } + } + + private static URL getDefaultMetaConfig() { + // 1: check tamaya-config system property + String tamayaConfig = System.getProperty("tamaya-config"); + if(tamayaConfig!=null){ + File file = new File(tamayaConfig); + if(!file.exists() || !file.canRead() || !file.isFile()){ + LOG.severe("TAMAYA: Not a valid config file: " + tamayaConfig); + }else{ + try { + return file.toURI().toURL(); + } catch (MalformedURLException e) { + LOG.severe("TAMAYA: Invalid file name: " + tamayaConfig); + } + } + } + return MetaConfiguration.class.getClassLoader().getResource(CONFIG_RESOURCE); + } + + /** + * Performs initialization of a new configuration + * context to the {@link MetaConfigurationReader} instances found in the current + * {@link org.apache.tamaya.spi.ServiceContext} and returns the corresponding builder + * instance. + * @param metaConfig URL for loading the {@code tamaya-config.xml} meta-configuration. + * @return a new configuration context builder, never null. + * @throws ConfigException If the URL cannot be read. + */ + public static ConfigurationContextBuilder createContextBuilder(URL metaConfig){ + URL configFile = Objects.requireNonNull(metaConfig); + LOG.info("TAMAYA: Loading tamaya-config.xml..."); + Document document = null; + try { + document = DocumentBuilderFactory.newInstance() + .newDocumentBuilder().parse(configFile.openStream()); + ConfigurationContextBuilder builder = ConfigurationProvider.getConfigurationContextBuilder(); + for(MetaConfigurationReader reader: ServiceContextManager.getServiceContext().getServices( + MetaConfigurationReader.class + )){ + LOG.fine("TAMAYA: Executing MetaConfig-Reader: " + reader.getClass().getName()+"..."); + reader.read(document, builder); + } + return builder; + } catch (SAXException | IOException | ParserConfigurationException e) { + throw new ConfigException("Cannot read meta-config deom " + metaConfig, e); + } + } + + /** + * Reads the meta-configuration and delegates initialization of the current configuration + * context to the {@link MetaConfigurationReader} instances found in the current + * {@link org.apache.tamaya.spi.ServiceContext}. + * @param metaConfig URL for loading the {@code tamaya-config.xml} meta-configuration. + * @return the new configuration instance. + */ + public static Configuration createConfiguration(URL metaConfig){ + ConfigurationContext context = createContextBuilder(metaConfig).build(); + return ConfigurationProvider.createConfiguration(context); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-sandbox/blob/afc19d0e/metamodel/src/main/java/org/apache/tamaya/metamodel/MetaContext.java ---------------------------------------------------------------------- diff --git a/metamodel/src/main/java/org/apache/tamaya/metamodel/MetaContext.java b/metamodel/src/main/java/org/apache/tamaya/metamodel/MetaContext.java new file mode 100644 index 0000000..4032c03 --- /dev/null +++ b/metamodel/src/main/java/org/apache/tamaya/metamodel/MetaContext.java @@ -0,0 +1,330 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.tamaya.metamodel; + +import org.apache.tamaya.functions.Supplier; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.WeakHashMap; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; + +/** + * Class managing the configuration system's shared context. This + * context is used by the configuration system to evaluate the + * right properties, e.g. by defining the current stage or labels + * that apply to the current configuration. Hereby context are + * <ul> + * <li>identified by unique names</li> + * <li>stackable into a context hierarchy, see {@link #combineWith(MetaContext...)}</li> + * <li>optionally be valid only in some contexts or for a limited time, see {@link #isValid()}, + * {@link #getInstance(String, Supplier)}</li> + * <li>providing key/values only valid for a certain time (assigned a TTL), see {@link #setProperty(String, String, int, TimeUnit)}, + * {@link #setProperties(Map, long, TimeUnit)}</li> + * </ul> + * Additionally there is special support for thread related contexts, see {@link #getThreadInstance()}. + * Finally there is also one special globally shared context instance, see {@link #getCurrentInstance()}. + */ +public final class MetaContext { + + private static final ThreadLocal<MetaContext> THREAD_CONTEXT = new ThreadLocal<MetaContext>(){ + @Override + protected MetaContext initialValue() { + return new MetaContext(); + } + }; + + private String id; + + private Supplier<Boolean> validSupplier; + + private final Map<String,Value> properties = new ConcurrentHashMap<>(); + + private static final Map<String,MetaContext> CONTEXTS = new WeakHashMap<>(); + + /** + * Access a context by name. Contexts are managed as weak references in this class. If no + * such context exists, a new instance is created. + * @param contextName the context name, not null. + * @return the context instance, never null. + */ + public static MetaContext getInstance(String contextName) { + return getInstance(contextName, null); + } + + /** + * Access a context by name. Contexts are managed as weak references in this class. If no + * such valid context exists, a new instance is created, using the given {@code validSupplier}. + * @param contextName the context name, not null. + * @return the context instance, never null. + */ + public static MetaContext getInstance(String contextName, Supplier<Boolean> validSupplier){ + synchronized(CONTEXTS){ + MetaContext ctx = CONTEXTS.get(contextName); + if(ctx!=null && ctx.isValid()){ + return ctx; + } + ctx = new MetaContext(); + ctx.id = Objects.requireNonNull(contextName); + ctx.validSupplier = validSupplier; + CONTEXTS.put(contextName, ctx); + return ctx; + } + + } + + /** + * Access the thread-based context. If no such context + * exists a new one will be created. + * @return the corresponding context, never null. + */ + public static MetaContext getThreadInstance(){ + return THREAD_CONTEXT.get(); + } + + /** + * Access the current context, which actually is the current context, combined with the thread based + * context (overriding). + * @return the corresponding context, never null. + */ + public MetaContext getCurrentInstance(){ + return this.combineWith(THREAD_CONTEXT.get()); + } + + /** + * Method to evaluate if a context is valid. This basically depends on the + * {@code validSupplier}, if any is set. If no supplier is present the context is valid. + * + * @return true, if this context is valid. + */ + public boolean isValid(){ + return this.validSupplier == null || validSupplier.get(); + } + + + /** + * Combine this context with the other contexts given, hereby only contexts are included + * which are {@code valid}, see {@link #isValid()}. + * @param contexts the context to merge with this context. + * @return the newly created Context. + */ + public MetaContext combineWith(MetaContext... contexts) { + MetaContext newContext = new MetaContext(); + newContext.properties.putAll(this.properties); + for(MetaContext ctx:contexts) { + if(ctx.isValid()) { + newContext.properties.putAll(ctx.properties); + } + } + return newContext; + } + + /** + * Access the given context property. + * @param key the key, not null + * @return the value, or null. + */ + public String getProperty(String key){ + return getProperty(key, null); + } + + /** + * Access the given context property. + * @param key the key, not the default value. + * @param defaultValue the default value to be returned, if no value is defined, or the + * stored value's TTL has been reached. + * @return the value, default value or null. + */ + public String getProperty(String key, String defaultValue){ + Value value = this.properties.get(key); + if(value==null){ + return defaultValue; + } + if(!value.isValid()){ + this.properties.remove(key); + return null; + } + return value.value; + } + + /** + * Sets the given context property. + * @param key the key, not null. + * @param value the value, not null. + * @return the porevious value, or null. + */ + public String setProperty(String key, String value){ + return setProperty(key, value, 0, TimeUnit.MILLISECONDS); + } + + /** + * Sets the given context property. + * @param key the key, not null. + * @param value the value, not null. + * @param ttl the time to live. Zero or less than zero means, no timeout. + * @param unit the target time unit. + * @return the porevious value, or null. + */ + public String setProperty(String key, String value, int ttl, TimeUnit unit){ + Value previous = this.properties.put(key, new Value(key, value, ttl)); + if(previous!=null && previous.isValid()){ + return previous.value; + } + return null; + } + + /** + * Sets the given property unless there is already a value defined. + * @param key the key, not null. + * @param value the value, not null. + */ + public void setPropertyIfAbsent(String key, String value){ + setPropertyIfAbsent(key, value, 0, TimeUnit.MILLISECONDS); + } + + /** + * Sets the given property unless there is already a value defined. + * @param key the key, not null. + * @param value the value, not null. + * @param ttl the time to live. Zero or less than zero means, no timeout. + * @param unit the target time unit. + */ + public void setPropertyIfAbsent(String key, String value, long ttl, TimeUnit unit){ + Value prev = this.properties.get(key); + if(prev==null){ + this.properties.put(key, new Value(key, value, unit.toMillis(ttl))); + } + } + + /** + * Adds all properties given, overriding any existing properties. + * @param properties the properties, not null. + */ + public void setProperties(Map<String,String> properties){ + setProperties(properties, 0L, TimeUnit.MILLISECONDS); + } + + /** + * Adds all properties given, overriding any existing properties. + * @param properties the properties, not null. + * @param ttl the time to live. Zero or less than zero means, no timeout. + * @param unit the target time unit. + */ + public void setProperties(Map<String,String> properties, long ttl, TimeUnit unit){ + for(Map.Entry en:properties.entrySet()) { + this.properties.put( + en.getKey().toString(), + new Value(en.getKey().toString(), en.getValue().toString(), unit.toMillis(ttl))); + } + } + + /** + * Checks if all the given properties are present. + * @param keys the keys to check, not null. + * @return true, if all the given keys are existing. + */ + public boolean checkProperties(String... keys){ + for(String key:keys) { + if (getProperty(key, null) == null) { + return false; + } + } + return true; + } + + /** + * Access all the current context properties. + * @return the properties, never null. + */ + public Map<String,String> getProperties(){ + Map<String,String> map = new HashMap<>(); + for(Map.Entry<String,Value> en:properties.entrySet()) { + Value val = en.getValue(); + if(val.isValid()){ + map.put(en.getKey(), val.value); + }else{ + this.properties.remove(en.getKey()); + } + } + return Collections.unmodifiableMap(map); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof MetaContext)) return false; + + MetaContext context = (MetaContext) o; + + return getProperties().equals(context.getProperties()); + + } + + @Override + public int hashCode() { + return getProperties().hashCode(); + } + + @Override + public String toString() { + return "Context{" + + properties + + '}'; + } + + private static final class Value{ + String key; + String value; + long validUntil; + + Value(String key, String value, long ttl){ + this.key = Objects.requireNonNull(key); + this.value = Objects.requireNonNull(value); + if(ttl>0) { + this.validUntil = System.currentTimeMillis() + ttl; + } + } + + /** Method to check if a value is still valid. */ + boolean isValid(){ + return this.validUntil<=0 || this.validUntil>=System.currentTimeMillis(); + } + + /** Method that invalidates a value. */ + void invalidate(){ + this.validUntil = 0; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Value)) return false; + Value value = (Value) o; + return Objects.equals(value, value.value); + } + + @Override + public int hashCode() { + return Objects.hash(value); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-sandbox/blob/afc19d0e/metamodel/src/main/java/org/apache/tamaya/metamodel/Refreshable.java ---------------------------------------------------------------------- diff --git a/metamodel/src/main/java/org/apache/tamaya/metamodel/Refreshable.java b/metamodel/src/main/java/org/apache/tamaya/metamodel/Refreshable.java new file mode 100644 index 0000000..dc51554 --- /dev/null +++ b/metamodel/src/main/java/org/apache/tamaya/metamodel/Refreshable.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.tamaya.metamodel; + +import org.apache.tamaya.spi.ConfigurationContext; + +/** + * Common interface for refreshable items. + */ +public interface Refreshable { + + /** + * Refreshes the given instance. + */ + void refresh(); +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-sandbox/blob/afc19d0e/metamodel/src/main/java/org/apache/tamaya/metamodel/RefreshablePropertySource.java ---------------------------------------------------------------------- diff --git a/metamodel/src/main/java/org/apache/tamaya/metamodel/RefreshablePropertySource.java b/metamodel/src/main/java/org/apache/tamaya/metamodel/RefreshablePropertySource.java new file mode 100644 index 0000000..23ca932 --- /dev/null +++ b/metamodel/src/main/java/org/apache/tamaya/metamodel/RefreshablePropertySource.java @@ -0,0 +1,150 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.tamaya.metamodel; + +import org.apache.tamaya.metamodel.internal.ComponentConfigurator; +import org.apache.tamaya.spi.PropertySource; +import org.apache.tamaya.spi.PropertyValue; + +import java.util.Collections; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; +import java.util.logging.Level; +import java.util.logging.Logger; + + +/** + * Wrapped property source that allows refreshing/reloading a property source. Hereby a property source must + * either + * <ul> + * <li>have a public parameterless constructor, used for reloading a new instance.</li> + * <li>implement itself {@link Refreshable}.</li> + * </ul> + */ +public final class RefreshablePropertySource + implements PropertySource, Refreshable { + + private static final Logger LOG = Logger.getLogger(RefreshablePropertySource.class.getName()); + private Map<String,String> metaConfig; + private PropertySource wrapped; + private AtomicLong nextRefresh = new AtomicLong(); + private AtomicLong refreshPeriod = new AtomicLong(); + + private RefreshablePropertySource(Map<String,String> metaConfig, PropertySource wrapped) { + this.metaConfig = Objects.requireNonNull(metaConfig); + this.wrapped = Objects.requireNonNull(wrapped); + } + + /** + * Makes a property source refreshable. If the given property source is already an instance of + * RefreshablePropertySource, the property source is returned. + * @param metaConfig the configuration parameters to be applied when a new PropertySource is created, not null. + * @param propertySource the property source, not null. + * @return a new instance, not null. + */ + public static RefreshablePropertySource of(Map<String,String> metaConfig, PropertySource propertySource) { + if(propertySource instanceof RefreshablePropertySource){ + return (RefreshablePropertySource)propertySource; + } + return new RefreshablePropertySource(metaConfig, propertySource); + } + + /** + * Makes a property source refreshable. If the given property source is already an instance of + * RefreshablePropertySource, the property source is returned. + * @param propertySource the property source, not null. + * @return a new instance, not null. + */ + public static RefreshablePropertySource of(PropertySource propertySource) { + return of(Collections.<String, String>emptyMap(), propertySource); + } + + /** + * Checks if the property source should autorefresh, if so {@link #refresh()} is called. + */ + private void checkRefresh(){ + long next = nextRefresh.get(); + if(next > 0 && next<System.currentTimeMillis()){ + nextRefresh.set(next + refreshPeriod.get()); + refresh(); + } + } + + /** + * Set the refresh period. This will be immedately applied from now. No explicit + * refresh will be triggered now. + * @param units + * @param timeUnit + */ + public void setRefreshPeriod(long units, TimeUnit timeUnit){ + this.refreshPeriod.set(timeUnit.toMillis(units)); + this.nextRefresh.set(System.currentTimeMillis() + this.refreshPeriod.get()); + } + + + @Override + public void refresh() { + try { + if(this.wrapped instanceof Refreshable){ + ((Refreshable) this.wrapped).refresh(); + }else { + this.wrapped = this.wrapped.getClass().newInstance(); + ComponentConfigurator.configure(this.wrapped, metaConfig); + } + } catch (Exception e) { + LOG.log(Level.WARNING, "Failed to reload/refresh PropertySource: " + + wrapped.getClass().getName(), e); + } + } + + @Override + public int getOrdinal() { + return this.wrapped.getOrdinal(); + } + + @Override + public String getName() { + return this.wrapped.getName(); + } + + @Override + public PropertyValue get(String key) { + return this.wrapped.get(key); + } + + @Override + public Map<String, String> getProperties() { + return this.wrapped.getProperties(); + } + + @Override + public boolean isScannable() { + return this.wrapped.isScannable(); + } + + @Override + public String toString() { + return "RefreshablePropertySource{" + + "\n metaConfig=" + metaConfig + + "\n wrapped=" + wrapped + + '}'; + } +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-sandbox/blob/afc19d0e/metamodel/src/main/java/org/apache/tamaya/metamodel/RefreshablePropertySourceProvider.java ---------------------------------------------------------------------- diff --git a/metamodel/src/main/java/org/apache/tamaya/metamodel/RefreshablePropertySourceProvider.java b/metamodel/src/main/java/org/apache/tamaya/metamodel/RefreshablePropertySourceProvider.java new file mode 100644 index 0000000..e71ca56 --- /dev/null +++ b/metamodel/src/main/java/org/apache/tamaya/metamodel/RefreshablePropertySourceProvider.java @@ -0,0 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.tamaya.metamodel; + +import org.apache.tamaya.metamodel.internal.ComponentConfigurator; +import org.apache.tamaya.spi.PropertySource; +import org.apache.tamaya.spi.PropertySourceProvider; + +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.Objects; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Wrapped property source provider that allows refreshing/reloading a property source provider. Hereby a provider must + * either + * <ul> + * <li>have a public parameterless constructor, used for reloading a new instance.</li> + * <li>implement itself {@link Refreshable}.</li> + * </ul> + */ +public final class RefreshablePropertySourceProvider + implements PropertySourceProvider, Refreshable { + + private static final Logger LOG = Logger.getLogger(RefreshablePropertySourceProvider.class.getName()); + private Map<String,String> metaConfig; + private PropertySourceProvider wrapped; + private Collection<PropertySource> propertSources; + + private RefreshablePropertySourceProvider(Map<String,String> metaConfig, PropertySourceProvider wrapped) { + this.metaConfig = Objects.requireNonNull(metaConfig); + this.wrapped = Objects.requireNonNull(wrapped); + this.propertSources = Objects.requireNonNull(wrapped.getPropertySources()); + } + + /** + * Makes a property source provider refreshable. If the given property source provider is already an instance of + * RefreshablePropertySourceProvider, the property source provider is returned unchanged. + * @param metaConfig the configuration parameters to be applied when a new PropertySourceProvider is created, not null. + * @param provider the property source provider, not null. + * @return a new instance, not null. + */ + public static RefreshablePropertySourceProvider of(Map<String,String> metaConfig, PropertySourceProvider provider) { + if(provider instanceof RefreshablePropertySourceProvider){ + return (RefreshablePropertySourceProvider)provider; + } + return new RefreshablePropertySourceProvider(metaConfig, provider); + } + + /** + * Makes a property source refreshable. If the given property source is already an instance of + * RefreshablePropertySource, the property source is returned. + * @param provider the property source provider, not null. + * @return a new instance, not null. + */ + public static RefreshablePropertySourceProvider of(PropertySourceProvider provider) { + return of(Collections.<String, String>emptyMap(), provider); + } + + @Override + public Collection<PropertySource> getPropertySources() { + return this.propertSources; + } + + @Override + public void refresh() { + try { + if(this.wrapped instanceof Refreshable){ + ((Refreshable) this.wrapped).refresh(); + }else { + this.wrapped = this.wrapped.getClass().newInstance(); + ComponentConfigurator.configure(this.wrapped, metaConfig); + } + } catch (Exception e) { + LOG.log(Level.WARNING, "Failed to refresh PropertySourceProvider: " + + wrapped.getClass().getName(), e); + } + this.propertSources = Objects.requireNonNull(wrapped.getPropertySources()); + } + + @Override + public String toString() { + return "RefreshablePropertySourceProvider{" + + "\n metaConfig=" + metaConfig + + "\n wrapped=" + wrapped + + '}'; + } +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-sandbox/blob/afc19d0e/metamodel/src/main/java/org/apache/tamaya/metamodel/dsl/MetaConfiguration.java ---------------------------------------------------------------------- diff --git a/metamodel/src/main/java/org/apache/tamaya/metamodel/dsl/MetaConfiguration.java b/metamodel/src/main/java/org/apache/tamaya/metamodel/dsl/MetaConfiguration.java deleted file mode 100644 index 2e88c6b..0000000 --- a/metamodel/src/main/java/org/apache/tamaya/metamodel/dsl/MetaConfiguration.java +++ /dev/null @@ -1,122 +0,0 @@ -///* -// * Licensed to the Apache Software Foundation (ASF) under one -// * or more contributor license agreements. See the NOTICE file -// * distributed with this work for additional information -// * regarding copyright ownership. The ASF licenses this file -// * to you 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.apache.tamaya.metamodel.dsl; -// -//import org.apache.tamaya.Configuration; -//import org.apache.tamaya.ConfigurationProvider; -//import org.apache.tamaya.format.ConfigurationData; -//import org.apache.tamaya.format.ConfigurationFormat; -//import org.apache.tamaya.format.ConfigurationFormats; -//import org.apache.tamaya.json.YAMLFormat; -//import org.apache.tamaya.resource.ConfigResources; -//import org.apache.tamaya.spi.ConfigurationContextBuilder; -// -//import java.io.InputStream; -//import java.net.URL; -//import java.util.ArrayList; -//import java.util.Arrays; -//import java.util.List; -//import java.util.logging.Level; -//import java.util.logging.Logger; -// -///** -// * Meta environment configuration builder and accessor. Normally this class shoulds never be accessed -// * by client code. But it could be useful for extensions that extend the meta-configuration capabilities -// * of tamaya having access to the meta-configuration, so they can read their own meta-entries to -// * setup whatever features they implement. -// */ -//public final class MetaConfiguration { -// -// private static final Logger LOGGER = Logger.getLogger(MetaConfiguration.class.getName()); -// private static MetaConfiguration INSTANCE = new MetaConfiguration(); -// -// private Configuration config; -// private String resourceExpression; -// private String[] formatNames; -// -// /** -// * Initializes the metaconfiguration. -// * @param resourceExpression the resource expression that defines the resources to load. -// * @param formatNames the format names to be used. -// */ -// private void init(String resourceExpression, String... formatNames){ -// if(this.config!=null){ -// LOGGER.warning(">>> Reset of Meta-Configuration resource : " + resourceExpression); -// LOGGER.warning(">>> Reset of Meta-Configuration formats : " + Arrays.toString(formatNames)); -// } -// if(resourceExpression==null){ -// resourceExpression = "tamaya-config.*"; -// } -// LOGGER.info(">>> Meta-Configuration resource : " + resourceExpression); -// ConfigurationFormat[] formats = loadFormats(formatNames); -// ConfigurationContextBuilder builder = ConfigurationProvider.getConfigurationContextBuilder(); -// for(URL url:ConfigResources.getResourceResolver().getResources(resourceExpression)) { -// for(ConfigurationFormat format:formats) { -// if(format.accepts(url)){ -// try(InputStream is = url.openStream()){ -// ConfigurationData data = format.readConfiguration(url.toString(), is); -// builder.addPropertySources(PropertySourceBuilder( -// url.toString(), data.getCombinedProperties())); -// }catch(Exception e){ -// LOGGER.log(Level.INFO, "Failed to read " + url + " with format " + format, e); -// } -// } -// } -// } -// this.config = ConfigurationProvider.createConfiguration(builder.build()); -// LOGGER.info("Meta-Configuration read: " + this.config.getProperties().size() + " entries."); -// } -// -// -// /** -// * Access the system's meta-configuration, initialize if necessary. Normally this class shoulds never be accessed -// * by client code. But it could be useful for extensions that extend the meta-configuration capabilities -// * of tamaya having access to the meta-configuration, so they can read their own meta-entries to -// * setup whatever features they implement. -// * @return the meta-configuration instance used for setting up the Tamaya's application configuration -// * model. -// */ -// public static Configuration getConfiguration(){ -// if(INSTANCE.config==null) { -// INSTANCE.init(null); -// } -// return INSTANCE.config; -// } -// -// /** -// * Access the system's meta-configuration, initialize if necessary. Normally this class shoulds never be accessed -// * by client code. But it could be useful for extensions that extend the meta-configuration capabilities -// * of tamaya having access to the meta-configuration, so they can read their own meta-entries to -// * setup whatever features they implement. -// * -// * @param resourceExpression the resource expression that defines where the metaconfiguration -// * files/resources are located. -// * @param formatNames the formats supported, if null all formats found are tried for each resource(=URL). -// * @return the meta-configuration instance used for setting up the Tamaya's application configuration -// * model. -// */ -// public static Configuration getConfiguration(String resourceExpression, -// String... formatNames){ -// if(INSTANCE.config==null) { -// INSTANCE.init(resourceExpression, formatNames); -// } -// return INSTANCE.config; -// } -// -//} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-sandbox/blob/afc19d0e/metamodel/src/main/java/org/apache/tamaya/metamodel/dsl/TamayaConfigurator.java ---------------------------------------------------------------------- diff --git a/metamodel/src/main/java/org/apache/tamaya/metamodel/dsl/TamayaConfigurator.java b/metamodel/src/main/java/org/apache/tamaya/metamodel/dsl/TamayaConfigurator.java deleted file mode 100644 index c4570d7..0000000 --- a/metamodel/src/main/java/org/apache/tamaya/metamodel/dsl/TamayaConfigurator.java +++ /dev/null @@ -1,234 +0,0 @@ -///* -// * Licensed to the Apache Software Foundation (ASF) under one -// * or more contributor license agreements. See the NOTICE file -// * distributed with this work for additional information -// * regarding copyright ownership. The ASF licenses this file -// * to you 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.apache.tamaya.metamodel.dsl; -// -//import org.apache.tamaya.Configuration; -//import org.apache.tamaya.ConfigurationProvider; -//import org.apache.tamaya.functions.ConfigurationFunctions; -//import org.apache.tamaya.spi.*; -//import org.apache.tamaya.metamodel.spi.DSLPropertySourceProvider; -// -//import java.util.ArrayList; -//import java.util.Collection; -//import java.util.Collections; -//import java.util.Comparator; -//import java.util.HashMap; -//import java.util.HashSet; -//import java.util.List; -//import java.util.Map; -//import java.util.Set; -//import java.util.logging.Logger; -// -///** -// * Configuration class setting up the Tamaya runtime model. -// */ -//public final class TamayaConfigurator { -// -// private static final Logger LOGGER = Logger.getLogger(MetaConfiguration.class.getName()); -// private static final Comparator<WrappedPropertySource> ORDINAL_COMPARATOR = -// new Comparator<WrappedPropertySource>(){ -// @Override -// public int compare(WrappedPropertySource o1, WrappedPropertySource o2) { -// return o1.getOrdinal() - o2.getOrdinal(); -// } -// }; -// -// private static final TamayaConfigurator INSTANCE = new TamayaConfigurator(); -// -// private ConfigurationContext configurationContext; -// private Set<String> formats = new HashSet<>(); -// private Set<String> suffixes = new HashSet<>(); -// private Map<String,DSLPropertySourceProvider> dslResolvers = new HashMap<>(); -// -// -// private TamayaConfigurator(){ -// configure(null); -// } -// -// /** -// * Get the singleton instance. -// * @return the instance, never null. -// */ -// public static TamayaConfigurator getInstance(){ -// return INSTANCE; -// } -// -// /** -// * Configures the Tamaya runtime using the metamodel configuration found at the default -// * location. -// * @see MetaConfiguration -// */ -// public void configure(){ -// configure(null); -// } -// -// /** -// * Configures the Tamaya runtime using the given resource location expression and (optionally) -// * formats to be used for evaluating the metamodel configuration. -// * @param resourceExpression resource expression for resolving the location of the -// * meta configuration. -// * @param formats the format names to be used, optional, but not null. -// * @see MetaConfiguration -// */ -// public void configure(String resourceExpression, String... formats){ -// loadDSLSourceResolvers(); -// Configuration metaConfig = MetaConfiguration.getConfiguration(resourceExpression, formats); -// Configuration profilesConfig = metaConfig.with( -// ConfigurationFunctions.section("TAMAYA.PROFILES.", true)); -// Configuration metaProfile = profilesConfig.with( -// ConfigurationFunctions.section("<COMMON>.", true)); -// System.out.println(metaProfile.getProperties().keySet()); -// String[] values = metaProfile.getOrDefault("formats","yaml, properties, xml-properties").split(","); -// for(String fmt:values){ -// fmt = fmt.trim(); -// if(fmt.isEmpty()){ -// continue; -// } -// this.formats.add(fmt); -// } -// values = metaProfile.getOrDefault("suffixes", "yml, yaml, properties, xml").split(","); -// for(String sfx:values){ -// sfx = sfx.trim(); -// if(sfx.isEmpty()){ -// continue; -// } -// this.suffixes.add(sfx); -// } -// ConfigurationContextBuilder builder = ConfigurationProvider.getConfigurationContextBuilder(); -// Map<String, PropertySource> loadedPropertySources = loadDefaultPropertySources(); -// int defaultOrdinal = loadSources(builder, "<COMMON>", metaProfile, loadedPropertySources, 0) + 20; -// // Load current profiles -// for(String profile:ProfileManager.getInstance().getActiveProfiles()){ -// metaProfile = profilesConfig.with( -// ConfigurationFunctions.section(profile, true)); -// defaultOrdinal = loadSources(builder, profile, metaProfile, loadedPropertySources, defaultOrdinal) + 20; -// } -// // formats: yaml, properties, xml-properties -// // - SUFFIX: yaml, yml, properties, xml -// // - sources: -// // - "named:env-properties" # provider name, or class name -// // - "named:main-args" -// // - "named:sys-properties" -// // - "resource:classpath:META-INF/config/**/*.SUFFIX" -// -// } -// -// /** -// * Loads all default registered property sources and providers. -// * @return the default property sources available on the system. -// */ -// private Map<String, PropertySource> loadDefaultPropertySources() { -// Map<String, PropertySource> loadedPropertySources = new HashMap<>(); -// for(PropertySource ps: ServiceContextManager.getServiceContext().getServices(PropertySource.class)){ -// loadedPropertySources.put(ps.getName(), ps); -// } -// for(PropertySourceProvider prov: ServiceContextManager.getServiceContext().getServices(PropertySourceProvider.class)){ -// for(PropertySource ps: prov.getPropertySources()){ -// loadedPropertySources.put(ps.getName(), ps); -// } -// } -// return loadedPropertySources; -// } -// -// private int loadSources(ConfigurationContextBuilder builder, String profileId, Configuration metaProfile, Map<String, -// PropertySource> defaultPropertySources, int nextOrdinal) { -// String[] values; -// List<PropertySource> propertySourcesLoaded = new ArrayList<>(); -// values = metaProfile.getOrDefault("sources","<default>").split(","); -// if(values.length==1 && "<default>".equals(values[0])){ -// // load default property sources and providers from config as default. -// // additional providers may be added depending on the active profile... -// LOGGER.info("Using default configuration setup for "+profileId); -// nextOrdinal = addAndGetNextOrdinal(builder, defaultPropertySources.values(), -// propertySourcesLoaded, nextOrdinal); -// }else { -// LOGGER.info("Loading DSL based "+profileId+" configuration context..."); -// int count = 0; -// for (String source : values) { -// source = source.trim(); -// if (source.isEmpty()) { -// continue; -// } -// String sourceKey = getSourceKey(source); -// LOGGER.info("Loading "+profileId+" configuration source: " + source); -// // evaluate DSLSourceResolver and resolve PropertySources, register thm into context -// // apply newMaxOrdinal... -// DSLPropertySourceProvider resolver = dslResolvers.get(sourceKey); -// if(resolver==null){ -// LOGGER.warning("DSL error: unresolvable source expression: "+ source); -// continue; -// } -// List<PropertySource> sources = resolver.resolve(source.substring(sourceKey.length()), -// defaultPropertySources); -// nextOrdinal = addAndGetNextOrdinal(builder, sources, propertySourcesLoaded, nextOrdinal); -// } -// LOGGER.info("Loaded "+count+" DSL based "+profileId+" configuration contexts."); -// } -// return nextOrdinal; -// } -// -// private int addAndGetNextOrdinal(ConfigurationContextBuilder builder, Collection<PropertySource> sourcesToAdd, -// List<PropertySource> allPropertySources, int nextOrdinal) { -// allPropertySources.addAll(wrapOrdinals(nextOrdinal, sourcesToAdd)); -// nextOrdinal = Math.max(calculateHighestOrdinal(allPropertySources)+1, nextOrdinal+1); -// builder.addPropertySources(allPropertySources); -// return nextOrdinal; -// } -// -// private List<WrappedPropertySource> wrapOrdinals(int nextOrdinal, Collection<PropertySource> propertySources) { -// List<WrappedPropertySource> result = new ArrayList<>(); -// for(PropertySource ps: propertySources){ -// result.add(WrappedPropertySource.of(ps)); -// } -// Collections.sort(result, ORDINAL_COMPARATOR); -// for(WrappedPropertySource ps: result){ -// ps.setOrdinal(nextOrdinal++); -// } -// Collections.sort(result, ORDINAL_COMPARATOR); -// return result; -// } -// -// private int calculateHighestOrdinal(Collection<PropertySource> sources) { -// int maxOrdinal = 0; -// for (PropertySource ps : sources) { -// if (ps.getOrdinal() > maxOrdinal) { -// maxOrdinal = ps.getOrdinal(); -// } -// } -// return maxOrdinal; -// } -// -// private String getSourceKey(String source) { -// int index = source.indexOf(':'); -// if(index>0){ -// return source.substring(0,index); -// } -// return source; -// } -// -// private void loadDSLSourceResolvers() { -// // Load the ConfigurationDSLSourceResolvers on the system -// for(DSLPropertySourceProvider res: -// ServiceContextManager.getServiceContext().getServices( -// DSLPropertySourceProvider.class)){ -// this.dslResolvers.put(res.getKey(), res); -// } -// } -// -//} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-sandbox/blob/afc19d0e/metamodel/src/main/java/org/apache/tamaya/metamodel/dsl/WrappedPropertySource.java ---------------------------------------------------------------------- diff --git a/metamodel/src/main/java/org/apache/tamaya/metamodel/dsl/WrappedPropertySource.java b/metamodel/src/main/java/org/apache/tamaya/metamodel/dsl/WrappedPropertySource.java deleted file mode 100644 index 000406b..0000000 --- a/metamodel/src/main/java/org/apache/tamaya/metamodel/dsl/WrappedPropertySource.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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.apache.tamaya.metamodel.dsl; - -import org.apache.tamaya.spi.FilterContext; -import org.apache.tamaya.spi.PropertyFilter; -import org.apache.tamaya.spi.PropertySource; -import org.apache.tamaya.spi.PropertyValue; - -import java.util.List; -import java.util.Map; -import java.util.Objects; - -/** - * Wrapped property source that allows dynamically reassigning the property source's - * ordinal value. This is needed for reordering the property sources to - * match the DSL configured ordering. - */ -final class WrappedPropertySource implements PropertySource { - - private Integer ordinalAssigned; - private PropertySource wrapped; - private List<PropertyFilter> filters; - - private WrappedPropertySource(PropertySource wrapped){ - this.wrapped = Objects.requireNonNull(wrapped); - } - - /** - * Wraps a given property source. - * @param propertySource the property source to be wrapped. - * @return a wrapped property source. - */ - public static WrappedPropertySource of(PropertySource propertySource){ - if(propertySource instanceof WrappedPropertySource){ - return (WrappedPropertySource)propertySource; - } - return new WrappedPropertySource(propertySource); - } - - @Override - public int getOrdinal() { - return ordinalAssigned!=null?ordinalAssigned.intValue():wrapped.getOrdinal(); - } - - /** - * Applies the given ordinal to the instance. - * @param ordinal the new ordinal. - */ - public void setOrdinal(int ordinal){ - this.ordinalAssigned = ordinal; - } - - /** - * Resetting the ordinal to the one of the wrapped property source. - */ - public void resetOrdinal(){ - this.ordinalAssigned = null; - } - - @Override - public String getName() { - return wrapped.getName(); - } - - @Override - public PropertyValue get(String key) { - PropertyValue value = wrapped.get(key); - if(value != null && value.getValue()!=null){ - if(filters!=null){ - String filteredValue = value.getValue(); - for(PropertyFilter pf:filters){ - filteredValue = pf.filterProperty(filteredValue, new FilterContext(key, value.getConfigEntries(), true)); - } - if(filteredValue!=null){ - return PropertyValue.builder(key, filteredValue, getName()) - .setContextData(value.getConfigEntries()).build(); - } - } - } - return value; - } - - @Override - public Map<String, String> getProperties() { - Map<String, String> props = wrapped.getProperties(); - if(filters!=null){ - String filteredValue = value.getValue(); - for(PropertyFilter pf:filters){ - filteredValue = pf.filterProperty(filteredValue, new FilterContext(key, value.getConfigEntries(), true)); - } - if(filteredValue!=null){ - return PropertyValue.builder(key, filteredValue, getName()) - .setContextData(value.getConfigEntries()).build(); - } - } - } - - @Override - public boolean isScannable() { - return wrapped.isScannable(); - } - - @Override - public String toString() { - return "WrappedPropertySource{" + - "ordinalAssigned=" + ordinalAssigned + - ", wrapped=" + wrapped + - '}'; - } -} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-sandbox/blob/afc19d0e/metamodel/src/main/java/org/apache/tamaya/metamodel/dsl/internal/DSLLoadingConfigurationProviderSpi.java ---------------------------------------------------------------------- diff --git a/metamodel/src/main/java/org/apache/tamaya/metamodel/dsl/internal/DSLLoadingConfigurationProviderSpi.java b/metamodel/src/main/java/org/apache/tamaya/metamodel/dsl/internal/DSLLoadingConfigurationProviderSpi.java deleted file mode 100644 index e640e3f..0000000 --- a/metamodel/src/main/java/org/apache/tamaya/metamodel/dsl/internal/DSLLoadingConfigurationProviderSpi.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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.apache.tamaya.metamodel.dsl.internal; - -import org.apache.tamaya.ConfigurationProvider; -import org.apache.tamaya.spi.ConfigurationContext; -import org.apache.tamaya.Configuration; -import org.apache.tamaya.metamodel.dsl.TamayaConfigurator; -import org.apache.tamaya.spi.ConfigurationContextBuilder; -import org.apache.tamaya.spi.ConfigurationProviderSpi; -import org.apache.tamaya.spi.ServiceContextManager; - -import javax.annotation.Priority; - -/** - * ConfigurationContext that uses {@link TamayaConfigurator} to configure the - * Tamaya runtime context. - */ -@Priority(10) -public class DSLLoadingConfigurationProviderSpi implements ConfigurationProviderSpi{ - - private boolean configured; - - private ConfigurationContext context = ConfigurationProvider.getConfigurationContextBuilder().build(); - private Configuration config = ConfigurationProvider.createConfiguration(context); - - - @Override - public ConfigurationContextBuilder getConfigurationContextBuilder() { - return ServiceContextManager.getServiceContext().getService(ConfigurationContextBuilder.class); - } - - @Override - public void setConfigurationContext(ConfigurationContext context){ - // TODO think on a SPI or move event part into API... - this.config = ConfigurationProvider.createConfiguration(context); - this.context = context; - } - - @Override - public boolean isConfigurationContextSettable() { - return true; - } - - @Override - public Configuration getConfiguration() { - checkInitialized(); - return config; - } - - @Override - public ConfigurationContext getConfigurationContext() { - checkInitialized(); - return context; - } - - private void checkInitialized() { - if(!configured){ - synchronized (context) { - TamayaConfigurator.getInstance().configure(); - configured = true; - } - } - } -} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-sandbox/blob/afc19d0e/metamodel/src/main/java/org/apache/tamaya/metamodel/dsl/internal/NamedDSLPropertySourceProvider.java ---------------------------------------------------------------------- diff --git a/metamodel/src/main/java/org/apache/tamaya/metamodel/dsl/internal/NamedDSLPropertySourceProvider.java b/metamodel/src/main/java/org/apache/tamaya/metamodel/dsl/internal/NamedDSLPropertySourceProvider.java deleted file mode 100644 index 6c50dc1..0000000 --- a/metamodel/src/main/java/org/apache/tamaya/metamodel/dsl/internal/NamedDSLPropertySourceProvider.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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.apache.tamaya.metamodel.dsl.internal; - -import org.apache.tamaya.spi.PropertySource; -import org.apache.tamaya.metamodel.spi.DSLPropertySourceProvider; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.logging.Logger; - -/** - * DSL provider implementation that allows to use registered {@link PropertySource} instances - * by matching {@link PropertySource#getName()} with the configured value and overriding the - * {@link PropertySource#getOrdinal()} method. - */ -public class NamedDSLPropertySourceProvider implements DSLPropertySourceProvider{ - - private static final Logger LOG = Logger.getLogger(NamedDSLPropertySourceProvider.class.getName()); - - @Override - public List<PropertySource> resolve(String sourceExpression, Map<String, PropertySource> defaultPropertySources) { - List<PropertySource> result = new ArrayList<>(); - PropertySource ps = defaultPropertySources.get(sourceExpression); - if(ps==null){ - LOG.warning("No such property source provider found: " + sourceExpression); - } - result.add(ps); - return result; - } - - @Override - public String getKey() { - return "named:"; - } -} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-sandbox/blob/afc19d0e/metamodel/src/main/java/org/apache/tamaya/metamodel/dsl/internal/ResourceDSLPropertySourceProvider.java ---------------------------------------------------------------------- diff --git a/metamodel/src/main/java/org/apache/tamaya/metamodel/dsl/internal/ResourceDSLPropertySourceProvider.java b/metamodel/src/main/java/org/apache/tamaya/metamodel/dsl/internal/ResourceDSLPropertySourceProvider.java deleted file mode 100644 index f2f2a71..0000000 --- a/metamodel/src/main/java/org/apache/tamaya/metamodel/dsl/internal/ResourceDSLPropertySourceProvider.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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.apache.tamaya.metamodel.dsl.internal; - -import org.apache.tamaya.metamodel.dsl.DSLFormatManager; -import org.apache.tamaya.format.ConfigurationData; -import org.apache.tamaya.format.ConfigurationFormat; -import org.apache.tamaya.resource.ConfigResources; -import org.apache.tamaya.spi.PropertySource; -import org.apache.tamaya.spisupport.MapPropertySource; -import org.apache.tamaya.metamodel.spi.DSLPropertySourceProvider; - -import java.io.InputStream; -import java.net.URL; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * DSL provider implementation that allows to use registered {@link PropertySource} instances - * by matching {@link PropertySource#getName()} with the configured value and overriding the - * {@link PropertySource#getOrdinal()} method. - */ -public class ResourceDSLPropertySourceProvider implements DSLPropertySourceProvider{ - - private static final Logger LOG = Logger.getLogger(ResourceDSLPropertySourceProvider.class.getName()); - - @Override - public List<PropertySource> resolve(String sourceExpression, Map<String, PropertySource> defaultPropertySources) { - List<PropertySource> result = new ArrayList<>(); - List<URL> resources = new ArrayList<>(); - if(sourceExpression.contains("SUFFIX")) { - for (String suffix : DSLFormatManager.getInstance().getSuffixes()) { - Collection<URL> locations = ConfigResources.getResourceResolver().getResources(getClass().getClassLoader(), - sourceExpression.replace("SUFFIX", suffix)); - loadPropertySources(locations, result); - } - }else { - Collection<URL> locations = ConfigResources.getResourceResolver().getResources(getClass().getClassLoader(), - sourceExpression); - loadPropertySources(locations, result); - } - return result; - } - - private void loadPropertySources(Collection<URL> locations, List<PropertySource> result) { - for(URL url:locations){ - for(ConfigurationFormat format: DSLFormatManager.getInstance().getFormats()) { - try(InputStream is = url.openStream()){ - ConfigurationData data = format.readConfiguration(url.toString(),is); - result.add(new MapPropertySource(url.toString(), data.getCombinedProperties())); - }catch(Exception e){ - LOG.log(Level.FINEST, "Format failed: " + format.getName() + " for " + url, e); - } - } - } - } - - @Override - public String getKey() { - return "resource:"; - } -} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-sandbox/blob/afc19d0e/metamodel/src/main/java/org/apache/tamaya/metamodel/internal/CombinationPolicyReader.java ---------------------------------------------------------------------- diff --git a/metamodel/src/main/java/org/apache/tamaya/metamodel/internal/CombinationPolicyReader.java b/metamodel/src/main/java/org/apache/tamaya/metamodel/internal/CombinationPolicyReader.java new file mode 100644 index 0000000..4c9217d --- /dev/null +++ b/metamodel/src/main/java/org/apache/tamaya/metamodel/internal/CombinationPolicyReader.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.tamaya.metamodel.internal; + +import org.apache.tamaya.ConfigException; +import org.apache.tamaya.metamodel.spi.ItemFactory; +import org.apache.tamaya.metamodel.spi.ItemFactoryManager; +import org.apache.tamaya.metamodel.spi.MetaConfigurationReader; +import org.apache.tamaya.spi.ConfigurationContextBuilder; +import org.apache.tamaya.spi.PropertyValueCombinationPolicy; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import java.util.logging.Logger; + + +/** + * Metaconfiguration reader that reads the configuration combination policy to be used. + */ +public class CombinationPolicyReader implements MetaConfigurationReader{ + + private static final Logger LOG = Logger.getLogger(CombinationPolicyReader.class.getName()); + + @Override + public void read(Document document, ConfigurationContextBuilder contextBuilder) { + NodeList nodeList = document.getDocumentElement().getElementsByTagName("combination-policy"); + if(nodeList.getLength()==0){ + LOG.finest("No explicit combination policy configured, using default."); + return; + } + if(nodeList.getLength()>1){ + throw new ConfigException("Only one combination policy can be applied."); + } + Node node = nodeList.item(0); + String type = node.getAttributes().getNamedItem("type").getNodeValue(); + LOG.finest("Loading combination policy configured: " + type); + ItemFactory<PropertyValueCombinationPolicy> policyFactory = ItemFactoryManager.getInstance().getFactory(PropertyValueCombinationPolicy.class, type); + PropertyValueCombinationPolicy policy = policyFactory.create(ComponentConfigurator.extractParameters(node)); + ComponentConfigurator.configure(policy, node); + contextBuilder.setPropertyValueCombinationPolicy(policy); + } + + +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-sandbox/blob/afc19d0e/metamodel/src/main/java/org/apache/tamaya/metamodel/internal/ComponentConfigurator.java ---------------------------------------------------------------------- diff --git a/metamodel/src/main/java/org/apache/tamaya/metamodel/internal/ComponentConfigurator.java b/metamodel/src/main/java/org/apache/tamaya/metamodel/internal/ComponentConfigurator.java new file mode 100644 index 0000000..93c50da --- /dev/null +++ b/metamodel/src/main/java/org/apache/tamaya/metamodel/internal/ComponentConfigurator.java @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.tamaya.metamodel.internal; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import java.util.*; +import java.util.logging.Logger; + +/** + * Small helper class for loading of configured instances. + */ +public final class ComponentConfigurator<T> { + + private static final Logger LOG = Logger.getLogger(ComponentConfigurator.class.getName()); + + private ComponentConfigurator(){} + + /** + * Configures the given instance with whatever is defined in the current child nodes. + * @param instance the instance to be configured, not null. + * @param node the node containing any configuration child nodes, not null. + */ + public static void configure(Object instance, Node node) { + NodeList entryNodes = node.getChildNodes(); + Map<String,String> params = new HashMap<>(); + for(int c=0;c<entryNodes.getLength();c++) { + Node filterNode = entryNodes.item(c); + if ("param".equals(filterNode.getNodeName())) { + String key = filterNode.getAttributes().getNamedItem("name").getNodeValue(); + String value = filterNode.getTextContent(); + params.put(key, value); + } + } + configure(instance, params); + } + + /** + * Configures the given instance with whatever is defined in the current child nodes. + * @param instance the instance to be configured, not null. + * @param params the node containing any configuration child nodes, not null. + */ + public static void configure(Object instance, Map<String,String> params) { + LOG.finest("Configuring instance: " + instance + " with " + params); + for(Map.Entry<String,String> en:params.entrySet()){ + if(!params.isEmpty()){ + applyParam(instance, en.getKey(), en.getValue()); + } + } + } + + private static void applyParam(Object instance, String param, String value) { + // TODO apply parameters to instance using reflection ,only if found. + } + + public static Map<String, String> extractParameters(Node node) { + NodeList entryNodes = node.getChildNodes(); + Map<String,String> params = new HashMap<>(); + for(int c=0;c<entryNodes.getLength();c++) { + Node filterNode = entryNodes.item(c); + if ("param".equals(filterNode.getNodeName())) { + String key = filterNode.getAttributes().getNamedItem("name").getNodeValue(); + String value = filterNode.getTextContent(); + params.put(key, value); + } + } + return params; + } + +}