You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tamaya.apache.org by an...@apache.org on 2015/01/03 12:59:13 UTC
[04/27] incubator-tamaya git commit: TAMAYA-19: Reorganized dormant
part for better focus of future discussions.
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/dormant/modules/metamodels/simple/src/main/resources/META-INF/services/org.apache.tamaya.core.spi.ConfigurationProviderSpi
----------------------------------------------------------------------
diff --git a/dormant/modules/metamodels/simple/src/main/resources/META-INF/services/org.apache.tamaya.core.spi.ConfigurationProviderSpi b/dormant/modules/metamodels/simple/src/main/resources/META-INF/services/org.apache.tamaya.core.spi.ConfigurationProviderSpi
deleted file mode 100644
index b3a2634..0000000
--- a/dormant/modules/metamodels/simple/src/main/resources/META-INF/services/org.apache.tamaya.core.spi.ConfigurationProviderSpi
+++ /dev/null
@@ -1,19 +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 current 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.
-#
-org.apache.tamaya.metamodel.simple.SimpleConfigProvider
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/dormant/modules/pom.xml
----------------------------------------------------------------------
diff --git a/dormant/modules/pom.xml b/dormant/modules/pom.xml
deleted file mode 100644
index e012023..0000000
--- a/dormant/modules/pom.xml
+++ /dev/null
@@ -1,60 +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 current 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.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
-
- <parent>
- <groupId>org.apache.tamaya</groupId>
- <artifactId>tamaya-all</artifactId>
- <version>0.1-SNAPSHOT</version>
- <relativePath>..</relativePath>
- </parent>
- <artifactId>tamaya-ext-all</artifactId>
- <groupId>org.apache.tamaya.ext</groupId>
- <name>Apache Tamaya Modules</name>
- <packaging>pom</packaging>
-
- <properties>
- <github.global.server>github</github.global.server>
- <jdkVersion>1.8</jdkVersion>
- <maven.compile.targetLevel>${jdkVersion}</maven.compile.targetLevel>
- <maven.compile.sourceLevel>${jdkVersion}</maven.compile.sourceLevel>
- </properties>
-
- <dependencies>
- <dependency>
- <groupId>org.apache.tamaya</groupId>
- <artifactId>tamaya-core</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.openejb</groupId>
- <artifactId>mbean-annotation-api</artifactId>
- <version>4.7.1</version>
- </dependency>
- </dependencies>
-
- <modules>
- <module>metamodels</module>
- <module>integration</module>
- <!-- <module>environment</module> -->
- </modules>
-
-</project>
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/modules/injection/pom.xml
----------------------------------------------------------------------
diff --git a/modules/injection/pom.xml b/modules/injection/pom.xml
new file mode 100644
index 0000000..90f0b59
--- /dev/null
+++ b/modules/injection/pom.xml
@@ -0,0 +1,40 @@
+<!--
+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 current 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.tamaya.integration</groupId>
+ <artifactId>tamaya-extensions-all</artifactId>
+ <version>0.2-SNAPSHOT</version>
+ <relativePath>..</relativePath>
+ </parent>
+ <artifactId>tamaya-injection</artifactId>
+ <name>Apache Tamaya Injection Support</name>
+ <packaging>jar</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.tamaya</groupId>
+ <artifactId>tamaya-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+</project>
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/modules/injection/src/main/java/org/apache/tamaya/inject/ConfiguredProperties.java
----------------------------------------------------------------------
diff --git a/modules/injection/src/main/java/org/apache/tamaya/inject/ConfiguredProperties.java b/modules/injection/src/main/java/org/apache/tamaya/inject/ConfiguredProperties.java
new file mode 100644
index 0000000..e1d773d
--- /dev/null
+++ b/modules/injection/src/main/java/org/apache/tamaya/inject/ConfiguredProperties.java
@@ -0,0 +1,41 @@
+/*
+ * 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.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation container to enable injection current multiple {@link org.apache.tamaya.annotation.ConfiguredProperty}
+ * annotations. Hereby the ordering current annotations imply the defaulting. The first keys that
+ * could be resolved successfully in the chain current annotations will be used.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(value = { ElementType.FIELD, ElementType.METHOD })
+public @interface ConfiguredProperties {
+
+ /**
+ * Get the different configuration keys to be looked up, in order current precedence. The first non null keys
+ * found will be used.
+ */
+ ConfiguredProperty[] value() default {};
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/modules/injection/src/main/java/org/apache/tamaya/inject/ConfiguredProperty.java
----------------------------------------------------------------------
diff --git a/modules/injection/src/main/java/org/apache/tamaya/inject/ConfiguredProperty.java b/modules/injection/src/main/java/org/apache/tamaya/inject/ConfiguredProperty.java
new file mode 100644
index 0000000..21d4e3a
--- /dev/null
+++ b/modules/injection/src/main/java/org/apache/tamaya/inject/ConfiguredProperty.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.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * Annotation to enable injection current a configured property or define the returned data for
+ * a configuration template method. Hereby this annotation can be used in multiple ways and combined
+ * with other annotations such as {@link org.apache.tamaya.annotation.DefaultValue},
+ * {@link org.apache.tamaya.annotation.WithLoadPolicy}, {@link org.apache.tamaya.annotation.WithConfig},
+ * {@link org.apache.tamaya.annotation.WithConfigOperator}, {@link WithPropertyAdapter}.
+ *
+ * Below the most simple variant current a configured class is given:
+ * {@code
+ * pubic class ConfiguredItem{
+ *
+ * @ConfiguredProperty
+ * private String aValue;
+ * }
+ * When this class is configured, e.g. by passing it to {@link org.apache.tamaya.Configuration#configure(Object)},
+ * the following is happening:
+ * <ul>
+ * <li>The current valid Configuration is evaluated by calling {@code Configuration cfg = Configuration.current();}</li>
+ * <li>The current property String keys is evaluated by calling {@code cfg.get("aValue");}</li>
+ * <li>if not successful, an error is thrown ({@link org.apache.tamaya.ConfigException}.</li>
+ * <li>On success, since no type conversion is involved, the keys is injected.</li>
+ * <li>The configured bean is registered as a weak change listener in the config system's underlying
+ * configuration, so future config changes can be propagated (controlled by {@link org.apache.tamaya.annotation.WithLoadPolicy}
+ * annotations).</li>
+ * </ul>
+ *
+ * In the next example we explicitly define the property keys:
+ * {@code
+ * pubic class ConfiguredItem{
+ *
+ * @ConfiguredProperty
+ * @ConfiguredProperty({"a.b.value", "a.b.deprecated.keys", "${env:java.version}"})
+ * @ConfiguredProperty(configuration={"a", "b"}
+ * @ConfiguredProperty(configuration={"a", "b", keys={"a.b.keys", "a.b.deprecated.keys", "${env:java.version}"}}
+ * private String aValue;
+ * }
+ *
+ * Within this example we evaluate multiple possible keys. Evaluation is aborted if a key could be successfully
+ * resolved. Hereby the ordering current the annotations define the ordering current resolution, so in the example above
+ * resolution equals to {@code "aValue", "a.b.keys", "a.b.deprecated.keys"}. If no keys could be read
+ * fromMap the configuration, it uses the keys fromMap the {@code DefaultValue} annotation. Interesting here
+ * is that this keys is not static, it is evaluated by calling
+ * {@link org.apache.tamaya.Configuration#evaluateValue(String, org.apache.tamaya.Configuration...)}.
+ */
+@Repeatable(ConfiguredProperties.class)
+@Retention(RetentionPolicy.RUNTIME)
+@Target(value = { ElementType.FIELD, ElementType.METHOD })
+public @interface ConfiguredProperty {
+
+ /**
+ * Annotation to reference an explicit {@link org.apache.tamaya.Configuration} to be used to
+ * resolve the required properties. the configured keys is passed to {@code Configuration.current(String)}
+ * to evaluate the required configuration required.
+ * @return the configurations to be looked up for the given keys.
+ */
+ String config() default "";
+
+ /**
+ * Get the property names to be used. Hereby the first non null keys evaluated is injected as property keys.
+ *
+ * @return the property names, not null. If missing the field or method name being injected is used by default.
+ */
+ String[] keys() default {};
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/modules/injection/src/main/java/org/apache/tamaya/inject/DefaultAreas.java
----------------------------------------------------------------------
diff --git a/modules/injection/src/main/java/org/apache/tamaya/inject/DefaultAreas.java b/modules/injection/src/main/java/org/apache/tamaya/inject/DefaultAreas.java
new file mode 100644
index 0000000..63ea137
--- /dev/null
+++ b/modules/injection/src/main/java/org/apache/tamaya/inject/DefaultAreas.java
@@ -0,0 +1,43 @@
+/*
+ * 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.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation to control injection and resolution current a configured bean. The configuration keys
+ * to be resolved are basically determined by the {@link org.apache.tamaya.annotation.ConfiguredProperty}
+ * annotation(s). Nevertheless these annotations can also have relative key names. This annotation allows
+ * to define a configuration area that is prefixed to all relative configuration keys within the
+ * corresponding class/template interface.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(value = { ElementType.TYPE })
+public @interface DefaultAreas {
+
+ /**
+ * Allows to declare an operator that should be applied before injecting values into the bean.
+ * @return the operator class to be used.
+ */
+ String[] value();
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/modules/injection/src/main/java/org/apache/tamaya/inject/DefaultValue.java
----------------------------------------------------------------------
diff --git a/modules/injection/src/main/java/org/apache/tamaya/inject/DefaultValue.java b/modules/injection/src/main/java/org/apache/tamaya/inject/DefaultValue.java
new file mode 100644
index 0000000..c4b2e3a
--- /dev/null
+++ b/modules/injection/src/main/java/org/apache/tamaya/inject/DefaultValue.java
@@ -0,0 +1,41 @@
+/*
+ * 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.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation to define a default keys to be returned, when no configured keys could be
+ * determined for a property/template accessor. The keys hereby can also contain a
+ * dynamic expression that is evaluated by the configuration system.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(value = { ElementType.FIELD, ElementType.METHOD })
+public @interface DefaultValue {
+
+ /**
+ * The default keys to be injected, if no such configuration entry was found. If keys was found and no default
+ * is defined, it is handled as a deployment error.
+ */
+ String value() default "";
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/modules/injection/src/main/java/org/apache/tamaya/inject/DynamicValue.java
----------------------------------------------------------------------
diff --git a/modules/injection/src/main/java/org/apache/tamaya/inject/DynamicValue.java b/modules/injection/src/main/java/org/apache/tamaya/inject/DynamicValue.java
new file mode 100644
index 0000000..b8e0cf5
--- /dev/null
+++ b/modules/injection/src/main/java/org/apache/tamaya/inject/DynamicValue.java
@@ -0,0 +1,500 @@
+/*
+ * 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;
+
+import java.beans.PropertyChangeEvent;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.lang.ref.WeakReference;
+import java.util.*;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+import java.util.logging.Logger;
+
+/**
+ * A accessor for a single configured value. This can be used to support values that may change during runtime, reconfigured or
+ * final. Hereby external code (could be Tamaya configuration listners or client code), can set a new value. Depending on the
+ * {@link org.apache.tamaya.DynamicValue.UpdatePolicy} the new value is immedeately active or it requires an active commit
+ * by client code. Similarly an instance also can ignore all later changes to the value.
+ * <h3>Implementation Details</h3>
+ * This class is
+ * <ul>
+ * <li>Serializable, when also the item stored is serializable</li>
+ * <li>Thread safe</li>
+ * </ul>
+ */
+public final class DynamicValue<T> implements Serializable{
+
+ /**
+ * Policy to control how new values are applied to this instance.
+ */
+ enum UpdatePolicy{
+ /** New values are applied immedately and registered listeners are informed about the change. */
+ IMMEDIATE,
+ /** New values or not applied, but stored in the newValue property. Explcit call to #commit
+ of #commitAndGet are required to accept the change and inform the listeners about the change.
+ */
+ EXPLCIT,
+ /**
+ * New values are always immedately discarded.
+ */
+ NEVER,
+ /**
+ * Changes are logged before the are discarded.
+ */
+ LOG_AND_DISCARD
+ }
+
+
+ /** The property name of the entry. */
+ private String propertyName;
+ /**
+ * Policy that defines how new values are applied, be default it is applied initially once, but never updated anymore.
+ */
+ private UpdatePolicy updatePolicy = UpdatePolicy.NEVER;
+ /** The current value, never null. */
+ private transient Optional<T> value;
+ /** The new value, or null. */
+ private transient Optional<T> newValue;
+ /** List of listeners that listen for changes. */
+ private transient WeakList<Consumer<PropertyChangeEvent>> listeners;
+
+ /**
+ * Returns an empty {@code Optional} instance. No value is present for this
+ * Optional.
+ *
+ * @apiNote Though it may be tempting to do so, avoid testing if an object
+ * is empty by comparing with {@code ==} against instances returned by
+ * {@code Option.empty()}. There is no guarantee that it is a singleton.
+ * Instead, use {@link #isPresent()}.
+ *
+ * @param <T> Type of the non-existent value
+ * @return an empty {@code Optional}
+ */
+ public static <T> DynamicValue<T> empty(String propertyName) {
+ DynamicValue v = new DynamicValue<T>(propertyName, null);
+ return v;
+ }
+
+ /**
+ * Constructor.
+ * @param propertyName the name of the value in the format {@code <configName>:<propertyName>}.</config>
+ * @param item the initial value.
+ */
+ private DynamicValue(String propertyName, Optional<T> item){
+ this.propertyName = Objects.requireNonNull(propertyName);
+ this.value = item;
+ }
+
+ /**
+ * Creates a new instance.
+ * @param propertyName the name of the value in the format {@code <configName>:<propertyName>}.</config>
+ * @param value the initial value, not null.
+ * @param <T> the type
+ * @return a new instance, never null
+ */
+ public static <T> DynamicValue<T> of(String propertyName, T value){
+ return new DynamicValue(propertyName, Optional.of(value));
+ }
+
+ /**
+ * Creates a new instance.
+ * @param propertyName the name of the value in the format {@code <configName>:<propertyName>}.</config>
+ * @param value the initial value
+ * @param <T> the target type.
+ * @return a new instance, never null
+ */
+ public static <T> DynamicValue<T> ofNullable(String propertyName, T value){
+ return value == null ? empty(propertyName) : of(propertyName, value);
+ }
+
+ /**
+ * Performs a commit, if necessary and returns the current value.
+ * otherwise throws {@code ConfigException}.
+ *
+ * @return the non-null value held by this {@code Optional}
+ * @throws org.apache.tamaya.ConfigException if there is no value present
+ *
+ * @see DynamicValue#isPresent()
+ */
+ public T commitAndGet(){
+ commit();
+ return get();
+ }
+
+ /**
+ * Commits a new value that has not been committed yet, make it the new value of the instance. On change any registered listeners will be triggered.
+ */
+ public void commit(){
+ synchronized (value){
+ if(newValue!=null){
+ PropertyChangeEvent evt = new PropertyChangeEvent(this, propertyName, value.orElse(null), newValue.orElse(null));
+ value = newValue;
+ newValue = null;
+ for(Consumer<PropertyChangeEvent> consumer: listeners.get()){
+ consumer.accept(evt);
+ }
+ }
+ }
+ }
+
+ /**
+ * Discards a new value that was published. No listeners will be informed.
+ */
+ public void discard(){
+ newValue = null;
+ }
+
+
+
+ /**
+ * Access the {@link UpdatePolicy} used for updating this value.
+ * @return the update policy, never null.
+ */
+ public UpdatePolicy getUpdatePolicy() {
+ return updatePolicy;
+ }
+
+ /**
+ * Add a listener to be called as weak reference, when this value has been changed.
+ * @param l the listner, not null
+ */
+ public void addListener(Consumer<PropertyChangeEvent> l) {
+ if(listeners==null){
+ listeners = new WeakList<>();
+ }
+ listeners.add(l);
+ }
+
+ /**
+ * Removes a listener to be called, when this value has been changed.
+ * @param l the listner to be removed, not null
+ */
+ public void removeListener(Consumer<PropertyChangeEvent> l) {
+ if(listeners!=null){
+ listeners.remove(l);
+ }
+ }
+
+ /**
+ * If a value is present in this {@code ConfiguredValue}, returns the value,
+ * otherwise throws {@code ConfigException}.
+ *
+ * @return the non-null value held by this {@code Optional}
+ * @throws org.apache.tamaya.ConfigException if there is no value present
+ *
+ * @see DynamicValue#isPresent()
+ */
+ public T get() {
+ return value.get();
+ }
+
+ /**
+ * Method to apply a new value. Depending on the {@link org.apache.tamaya.DynamicValue.UpdatePolicy}
+ * the value is immediately or deferred visible (or it may even be ignored completely).
+ * @param newValue the new value, may also be null.
+ */
+ public void setNewValue(T newValue){
+ switch(this.updatePolicy){
+ case IMMEDIATE:
+ this.newValue = Optional.ofNullable(newValue);
+ commit();
+ break;
+ case EXPLCIT:
+ this.newValue = Optional.ofNullable(newValue);
+ break;
+ case LOG_AND_DISCARD:
+ Logger.getLogger(getClass().getName()).info("Discard change on " + this + ", newValue="+newValue);
+ this.newValue = null;
+ break;
+ case NEVER:
+ this.newValue = null;
+ break;
+ }
+
+ }
+
+ /**
+ * Sets a new {@link org.apache.tamaya.DynamicValue.UpdatePolicy}.
+ * @param updatePolicy the new policy, not null.
+ */
+ public void setUpdatePolicy(UpdatePolicy updatePolicy){
+ this.updatePolicy = Objects.requireNonNull(updatePolicy);
+ }
+
+ /**
+ * Access a new value that has not yet been committed.
+ * @return the uncommitted new value, or null.
+ */
+ public T getNewValue(){
+ Optional<T> nv = newValue;
+ if(nv!=null){
+ return nv.orElse(null);
+ }
+ return null;
+ }
+
+ /**
+ * Return {@code true} if there is a value present, otherwise {@code false}.
+ *
+ * @return {@code true} if there is a value present, otherwise {@code false}
+ */
+ public boolean isPresent() {
+ return value.isPresent();
+ }
+
+ /**
+ * If a value is present, invoke the specified consumer with the value,
+ * otherwise do nothing.
+ *
+ * @param consumer block to be executed if a value is present
+ * @throws NullPointerException if value is present and {@code consumer} is
+ * null
+ */
+ public void ifPresent(Consumer<? super T> consumer) {
+ value.ifPresent(consumer);
+ }
+
+ /**
+ * If a value is present, and the value matches the given predicate,
+ * return an {@code Optional} describing the value, otherwise return an
+ * empty {@code Optional}.
+ *
+ * @param predicate a predicate to apply to the value, if present
+ * @return an {@code Optional} describing the value of this {@code Optional}
+ * if a value is present and the value matches the given predicate,
+ * otherwise an empty {@code Optional}
+ * @throws NullPointerException if the predicate is null
+ */
+ public DynamicValue<T> filter(Predicate<? super T> predicate) {
+ Objects.requireNonNull(predicate);
+ if (!isPresent())
+ return this;
+ else
+ return predicate.test(value.get()) ? this : empty(propertyName);
+ }
+
+ /**
+ * If a value is present, apply the provided mapping function to it,
+ * and if the result is non-null, return an {@code Optional} describing the
+ * result. Otherwise return an empty {@code Optional}.
+ *
+ * @apiNote This method supports post-processing on optional values, without
+ * the need to explicitly check for a return status. For example, the
+ * following code traverses a stream of file names, selects one that has
+ * not yet been processed, and then opens that file, returning an
+ * {@code Optional<FileInputStream>}:
+ *
+ * <pre>{@code
+ * Optional<FileInputStream> fis =
+ * names.stream().filter(name -> !isProcessedYet(name))
+ * .findFirst()
+ * .map(name -> new FileInputStream(name));
+ * }</pre>
+ *
+ * Here, {@code findFirst} returns an {@code Optional<String>}, and then
+ * {@code map} returns an {@code Optional<FileInputStream>} for the desired
+ * file if one exists.
+ *
+ * @param <U> The type of the result of the mapping function
+ * @param mapper a mapping function to apply to the value, if present
+ * @return an {@code Optional} describing the result of applying a mapping
+ * function to the value of this {@code Optional}, if a value is present,
+ * otherwise an empty {@code Optional}
+ * @throws NullPointerException if the mapping function is null
+ */
+ public <U> DynamicValue<U> map(Function<? super T, ? extends U> mapper) {
+ Objects.requireNonNull(mapper);
+ if (!isPresent())
+ return empty(propertyName);
+ else {
+ return DynamicValue.ofNullable(propertyName, mapper.apply(value.get()));
+ }
+ }
+
+ /**
+ * If a value is present, apply the provided {@code Optional}-bearing
+ * mapping function to it, return that result, otherwise return an empty
+ * {@code Optional}. This method is similar to {@link #map(Function)},
+ * but the provided mapper is one whose result is already an {@code Optional},
+ * and if invoked, {@code flatMap} does not wrap it with an additional
+ * {@code Optional}.
+ *
+ * @param <U> The type parameter to the {@code Optional} returned by
+ * @param mapper a mapping function to apply to the value, if present
+ * the mapping function
+ * @return the result of applying an {@code Optional}-bearing mapping
+ * function to the value of this {@code Optional}, if a value is present,
+ * otherwise an empty {@code Optional}
+ * @throws NullPointerException if the mapping function is null or returns
+ * a null result
+ */
+ public <U> DynamicValue<U> flatMap(Function<? super T, DynamicValue<U>> mapper) {
+ Objects.requireNonNull(mapper);
+ if (!isPresent())
+ return empty(propertyName);
+ else {
+ return Objects.requireNonNull(mapper.apply(value.get()));
+ }
+ }
+
+ /**
+ * Return the value if present, otherwise return {@code other}.
+ *
+ * @param other the value to be returned if there is no value present, may
+ * be null
+ * @return the value, if present, otherwise {@code other}
+ */
+ public T orElse(T other) {
+ return value.orElse(other);
+ }
+
+ /**
+ * Return the value if present, otherwise invoke {@code other} and return
+ * the result of that invocation.
+ *
+ * @param other a {@code Supplier} whose result is returned if no value
+ * is present
+ * @return the value if present otherwise the result of {@code other.get()}
+ * @throws NullPointerException if value is not present and {@code other} is
+ * null
+ */
+ public T orElseGet(Supplier<? extends T> other) {
+ return value.orElseGet(other);
+ }
+
+ /**
+ * Return the contained value, if present, otherwise throw an exception
+ * to be created by the provided supplier.
+ *
+ * @apiNote A method reference to the exception constructor with an empty
+ * argument list can be used as the supplier. For example,
+ * {@code IllegalStateException::new}
+ *
+ * @param <X> Type of the exception to be thrown
+ * @param exceptionSupplier The supplier which will return the exception to
+ * be thrown
+ * @return the present value
+ * @throws X if there is no value present
+ * @throws NullPointerException if no value is present and
+ * {@code exceptionSupplier} is null
+ */
+ public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
+ return value.orElseThrow(exceptionSupplier);
+ }
+
+ /**
+ * Converts the instance to an {@link java.util.Optional} instance.
+ * @return the corresponding Optional value.
+ */
+ public Optional<T> toOptional(){
+ return value;
+ }
+
+ /**
+ * Serialization implementation that strips away the non serializable Optional part.
+ * @param oos the output stream
+ * @throws IOException if serialization fails.
+ */
+ private void writeObject(ObjectOutputStream oos)throws IOException {
+ oos.writeObject(updatePolicy);
+ if(isPresent()) {
+ oos.writeObject(this.value.get());
+ }
+ else{
+ oos.writeObject(null);
+ }
+ }
+
+ /**
+ * Reads an instance from the input stream.
+ * @param ois the object input stream
+ * @throws IOException if deserialization fails.
+ * @throws ClassNotFoundException
+ */
+ private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
+ this.updatePolicy = (UpdatePolicy)ois.readObject();
+ if(isPresent()) {
+ this.value = Optional.of((T) ois.readObject());
+ }
+ newValue = null;
+ }
+
+
+ /**
+ * Simple helper that allows keeping the listeners registered as weak references, hereby avoiding any
+ * memory leaks.
+ * @param <T> the type
+ */
+ private class WeakList<T>{
+ List<WeakReference<T>> refs = new LinkedList<>();
+
+ /**
+ * Adds a new instance.
+ * @param t the new instance, not null.
+ */
+ void add(T t){
+ refs.add(new WeakReference(t));
+ }
+
+ /**
+ * Removes a instance.
+ * @param t the instance to be removed.
+ */
+ void remove(T t){
+ synchronized (refs){
+ for(Iterator<WeakReference<T>> iterator = refs.iterator();iterator.hasNext();){
+ WeakReference<T> ref = iterator.next();
+ T instance = ref.get();
+ if(instance==null || instance == t){
+ iterator.remove();
+ break;
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Access a list (copy) of the current instances that were not discarded by the GC.
+ * @return the list of accessible items.
+ */
+ public List<T> get() {
+ synchronized (refs) {
+ List<T> res = new ArrayList<>();
+ for (Iterator<WeakReference<T>> iterator = refs.iterator(); iterator.hasNext(); ) {
+ WeakReference<T> ref = iterator.next();
+ T instance = ref.get();
+ if(instance==null){
+ iterator.remove();
+ }
+ else{
+ res.add(instance);
+ }
+ }
+ return res;
+ }
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/modules/injection/src/main/java/org/apache/tamaya/inject/LoadPolicy.java
----------------------------------------------------------------------
diff --git a/modules/injection/src/main/java/org/apache/tamaya/inject/LoadPolicy.java b/modules/injection/src/main/java/org/apache/tamaya/inject/LoadPolicy.java
new file mode 100644
index 0000000..116a2c1
--- /dev/null
+++ b/modules/injection/src/main/java/org/apache/tamaya/inject/LoadPolicy.java
@@ -0,0 +1,48 @@
+/*
+ * 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.annotation;
+
+/**
+ * Available policies that describe how changes affecting configured values are published/reinjected.
+ * The policy also affects the cases were any configured listeners/listener methods are called for
+ * propagation current configuration changes.
+ */
+public enum LoadPolicy {
+ /**
+ * The configuration keys is evaluated once, when the owning component is loaded/configured, but never updated later.
+ */
+ INITIAL,
+ /**
+ * The configuration keys is evaluated exactly once on its first use lazily, but never updated later.
+ * This feature is not applicable on field injection, but only on configuration template methods.
+ */
+ LAZY,
+ /**
+ * The configuration keys is evaluated once, when the owning component is loaded/configured.
+ * Later changes on this configuration entry will be reinjected/updated and additionally triggered
+ * as {@link java.beans.PropertyChangeEvent}.
+ */
+ MANAGED,
+ /**
+ * The configuration keys is evaluated once, when the owning component is loaded/configured.
+ * Later changes on this configuration entry will be reinjected/updated, but no {@link java.beans.PropertyChangeEvent}
+ * will be triggered.
+ */
+ SILENT
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/modules/injection/src/main/java/org/apache/tamaya/inject/NoConfig.java
----------------------------------------------------------------------
diff --git a/modules/injection/src/main/java/org/apache/tamaya/inject/NoConfig.java b/modules/injection/src/main/java/org/apache/tamaya/inject/NoConfig.java
new file mode 100644
index 0000000..845ec4c
--- /dev/null
+++ b/modules/injection/src/main/java/org/apache/tamaya/inject/NoConfig.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.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * This is a small marker annotations to inform Tamaya that the annotated element should never be injected with
+ * configured data. This is useful because by default Tamaya tries to lookup and inject configuration also by
+ * using property or method names without annotations. With that annotation none of these will be happen.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(value = { ElementType.FIELD, ElementType.METHOD })
+public @interface NoConfig {
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/modules/injection/src/main/java/org/apache/tamaya/inject/ObservesConfigChange.java
----------------------------------------------------------------------
diff --git a/modules/injection/src/main/java/org/apache/tamaya/inject/ObservesConfigChange.java b/modules/injection/src/main/java/org/apache/tamaya/inject/ObservesConfigChange.java
new file mode 100644
index 0000000..ef92b25
--- /dev/null
+++ b/modules/injection/src/main/java/org/apache/tamaya/inject/ObservesConfigChange.java
@@ -0,0 +1,38 @@
+/*
+ * 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.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation to annotate a method on a class to be informed on config changes.
+ * The exact behaviour, when configuration change events are sent can be configured
+ * on each configured property/method by adding the {@link org.apache.tamaya.annotation.WithLoadPolicy}
+ * annotation. By default listeners are informed on all changes of configurations that were used as
+ * input configurations for configuring a class/instance. Additionally {@link org.apache.tamaya.annotation.ConfiguredProperty}
+ * annotations can be added that allows to constrain changes to some limited properties.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(value = { ElementType.METHOD })
+public @interface ObservesConfigChange {
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/modules/injection/src/main/java/org/apache/tamaya/inject/WithConfigOperator.java
----------------------------------------------------------------------
diff --git a/modules/injection/src/main/java/org/apache/tamaya/inject/WithConfigOperator.java b/modules/injection/src/main/java/org/apache/tamaya/inject/WithConfigOperator.java
new file mode 100644
index 0000000..9f6c4f5
--- /dev/null
+++ b/modules/injection/src/main/java/org/apache/tamaya/inject/WithConfigOperator.java
@@ -0,0 +1,45 @@
+/*
+ * 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.annotation;
+
+import org.apache.tamaya.Configuration;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.function.UnaryOperator;
+
+/**
+ * Annotation to define an configuration operator to be used before accessing a configured keys.
+ * This allows filtering current configuration, e.g. for realizing views or ensuring security
+ * constraints.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(value = { ElementType.FIELD, ElementType.METHOD, ElementType.TYPE })
+public @interface WithConfigOperator {
+
+ /**
+ * Define a custom adapter that should be used to adapt the configuration entry injected. This overrides any
+ * general org.apache.tamaya.core.internal registered. If no adapter is defined (default) and no corresponding adapter is
+ * registered, it is handled as a deployment error.
+ */
+ Class<? extends UnaryOperator<Configuration>> value();
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/modules/injection/src/main/java/org/apache/tamaya/inject/WithLoadPolicy.java
----------------------------------------------------------------------
diff --git a/modules/injection/src/main/java/org/apache/tamaya/inject/WithLoadPolicy.java b/modules/injection/src/main/java/org/apache/tamaya/inject/WithLoadPolicy.java
new file mode 100644
index 0000000..e469f5a
--- /dev/null
+++ b/modules/injection/src/main/java/org/apache/tamaya/inject/WithLoadPolicy.java
@@ -0,0 +1,40 @@
+/*
+ * 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.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation to define how config changes are handled for a type or per property/template method.
+ * @see org.apache.tamaya.annotation.LoadPolicy
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(value = { ElementType.FIELD, ElementType.METHOD, ElementType.TYPE })
+public @interface WithLoadPolicy {
+
+ /**
+ * The load policy to be used. If this annotation is present a load policy must be defined.
+ * @return The load policy to be used, not null.
+ */
+ LoadPolicy value();
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/modules/injection/src/main/java/org/apache/tamaya/inject/WithPropertyAdapter.java
----------------------------------------------------------------------
diff --git a/modules/injection/src/main/java/org/apache/tamaya/inject/WithPropertyAdapter.java b/modules/injection/src/main/java/org/apache/tamaya/inject/WithPropertyAdapter.java
new file mode 100644
index 0000000..fa9cfdf
--- /dev/null
+++ b/modules/injection/src/main/java/org/apache/tamaya/inject/WithPropertyAdapter.java
@@ -0,0 +1,45 @@
+/*
+ * 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.annotation;
+
+import org.apache.tamaya.PropertyAdapter;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation to define a type adapter to be used before injecting a configured keys, or for applying changes.
+ * This will override any other adapter for performing the type conversion before
+ * injecting the field keys.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(value = { ElementType.FIELD, ElementType.METHOD })
+public @interface WithPropertyAdapter {
+
+ /**
+ * Define a custom adapter or codec that should be used to adapt the configuration entry injected. This overrides any
+ * general org.apache.tamaya.core.internal registered. If no adapter is defined (default) and no corresponding adapter is
+ * registered, it is handled as a deployment error.
+ */
+ @SuppressWarnings("rawtypes")
+ Class<? extends PropertyAdapter> value();
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/modules/injection/src/main/java/org/apache/tamaya/inject/internal/ConfigChangeCallbackMethod.java
----------------------------------------------------------------------
diff --git a/modules/injection/src/main/java/org/apache/tamaya/inject/internal/ConfigChangeCallbackMethod.java b/modules/injection/src/main/java/org/apache/tamaya/inject/internal/ConfigChangeCallbackMethod.java
new file mode 100644
index 0000000..f929f8e
--- /dev/null
+++ b/modules/injection/src/main/java/org/apache/tamaya/inject/internal/ConfigChangeCallbackMethod.java
@@ -0,0 +1,67 @@
+/*
+ * 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.core.internal.inject;
+
+import org.apache.tamaya.core.properties.PropertyChangeSet;
+import org.apache.tamaya.Configuration;
+
+import java.lang.reflect.Method;
+import java.util.Optional;
+import java.util.function.Consumer;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * This class holds a method object that is annotated to be a callback method to be called on configuration
+ * changes.
+ */
+public final class ConfigChangeCallbackMethod {
+
+ private static final Logger LOG = Logger.getLogger(ConfigChangeCallbackMethod.class.getName());
+
+ private Method callbackMethod;
+
+ public ConfigChangeCallbackMethod(Method callbackMethod) {
+ this.callbackMethod = Optional.of(callbackMethod).filter(
+ (m) -> void.class.equals(m.getReturnType()) &&
+ m.getParameterCount() == 1 &&
+ m.getParameterTypes()[0].equals(PropertyChangeSet.class)).get();
+ }
+
+ public Consumer<PropertyChangeSet> createConsumer(Object instance, Configuration... configurations){
+ // TODO consider also environment !
+ return event -> {
+ for(Configuration cfg:configurations){
+ if(event.getPropertySource().getName().equals(cfg.getName())){
+ return;
+ }
+ }
+ call(instance, event);
+ };
+ }
+
+ public void call(Object instance, PropertyChangeSet configChangeEvent) {
+ try {
+ callbackMethod.setAccessible(true);
+ callbackMethod.invoke(instance, configChangeEvent);
+ } catch (Exception e) {
+ LOG.log(Level.SEVERE, e, () -> "Error calling ConfigChange callback method " + callbackMethod.getDeclaringClass().getName() + '.' + callbackMethod.getName() + " on " + instance);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/modules/injection/src/main/java/org/apache/tamaya/inject/internal/ConfigTemplateInvocationHandler.java
----------------------------------------------------------------------
diff --git a/modules/injection/src/main/java/org/apache/tamaya/inject/internal/ConfigTemplateInvocationHandler.java b/modules/injection/src/main/java/org/apache/tamaya/inject/internal/ConfigTemplateInvocationHandler.java
new file mode 100644
index 0000000..ff2c309
--- /dev/null
+++ b/modules/injection/src/main/java/org/apache/tamaya/inject/internal/ConfigTemplateInvocationHandler.java
@@ -0,0 +1,76 @@
+/*
+ * 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.core.internal.inject;
+
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.core.internal.inject.ConfiguredType;
+import org.apache.tamaya.core.internal.inject.InjectionUtils;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.util.Objects;
+
+/**
+ * Invocation handler that handles request against a configuration template.
+ */
+public final class ConfigTemplateInvocationHandler implements InvocationHandler {
+
+ /*
+ TODO
+ the given method (in case of a template) can use different caching strategies:
+ 1) no caching (always evaluate the values completely) - slow.
+ 2) instance caching (a cache per instance).
+ 3) classloader caching...
+ 4) global shared cache.
+ */
+
+
+ /**
+ * Any overriding configurations.
+ */
+ private Configuration[] configurations;
+ /**
+ * The configured type.
+ */
+ private ConfiguredType type;
+
+ /**
+ * Creates a new handler instance.
+ * @param type the target type, not null.
+ * @param configurations overriding configurations to be used for evaluating the values for injection into {@code instance}, not null.
+ * If no such config is passed, the default configurationa provided by the current
+ * registered providers are used.
+ */
+ public ConfigTemplateInvocationHandler(Class<?> type, Configuration... configurations) {
+ this.configurations = Objects.requireNonNull(configurations).clone();
+ this.type = new ConfiguredType(Objects.requireNonNull(type));
+ if (!type.isInterface()) {
+ throw new IllegalArgumentException("Can only proxy interfaces as configuration templates.");
+ }
+ }
+
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ if ("toString".equals(method.getName())) {
+ return "Configured Proxy -> " + this.type.getType().getName();
+ }
+ String configValue = InjectionUtils.getConfigValue(method, configurations);
+ return InjectionUtils.adaptValue(method, method.getReturnType(), configValue);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/modules/injection/src/main/java/org/apache/tamaya/inject/internal/ConfigurationInjector.java
----------------------------------------------------------------------
diff --git a/modules/injection/src/main/java/org/apache/tamaya/inject/internal/ConfigurationInjector.java b/modules/injection/src/main/java/org/apache/tamaya/inject/internal/ConfigurationInjector.java
new file mode 100644
index 0000000..8a51375
--- /dev/null
+++ b/modules/injection/src/main/java/org/apache/tamaya/inject/internal/ConfigurationInjector.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.core.internal.inject;
+
+import org.apache.tamaya.Configuration;
+
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Simple injector singleton that also registers instances configured using weak references.
+ */
+@SuppressWarnings("rawtypes")
+public final class ConfigurationInjector {
+
+ private static final ConfigurationInjector INSTANCE = new ConfigurationInjector();
+
+ private Map<Class, ConfiguredType> configuredTypes = new ConcurrentHashMap<>();
+
+ /**
+ * Extract the configuration annotation config and registers it per class, for later reuse.
+ * @param type the type to be configured.
+ * @return the configured type registered.
+ */
+ public static ConfiguredType registerType(Class<?> type){
+ return INSTANCE.configuredTypes.computeIfAbsent(type, ConfiguredType::new);
+ }
+
+ /**
+ * Configured the current instance and reigsterd necessary listener to forward config change events as
+ * defined by the current annotations in place.
+ * @param instance the instance to be configured
+ * @param configurations Configuration instances that replace configuration served by services. This allows
+ * more easily testing and adaption.
+ */
+ public static void configure(Object instance, Configuration... configurations){
+ Class type = Objects.requireNonNull(instance).getClass();
+ ConfiguredType configuredType = registerType(type);
+ Objects.requireNonNull(configuredType).configure(instance, configurations);
+ }
+
+
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/modules/injection/src/main/java/org/apache/tamaya/inject/internal/ConfiguredField.java
----------------------------------------------------------------------
diff --git a/modules/injection/src/main/java/org/apache/tamaya/inject/internal/ConfiguredField.java b/modules/injection/src/main/java/org/apache/tamaya/inject/internal/ConfiguredField.java
new file mode 100644
index 0000000..51c3904
--- /dev/null
+++ b/modules/injection/src/main/java/org/apache/tamaya/inject/internal/ConfiguredField.java
@@ -0,0 +1,126 @@
+/*
+ * 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.core.internal.inject;
+
+import java.lang.reflect.Field;
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+
+import org.apache.tamaya.ConfigException;
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.annotation.ConfiguredProperties;
+import org.apache.tamaya.annotation.ConfiguredProperty;
+import org.apache.tamaya.annotation.DefaultAreas;
+import org.apache.tamaya.core.internal.Utils;
+
+/**
+ * Small class that contains and manages all information anc access to a configured field and a concrete instance current
+ * it (referenced by a weak reference). It also implements all aspects current keys filtering, converting any applying the
+ * final keys by reflection.
+ */
+public class ConfiguredField {
+
+
+ /**
+ * The configured field instance.
+ */
+ private Field annotatedField;
+
+ /**
+ * Models a configured field and provides mechanisms for injection.
+ *
+ * @param field the field instance.
+ */
+ public ConfiguredField(Field field) {
+ Objects.requireNonNull(field);
+ this.annotatedField = field;
+ }
+
+ /**
+ * Evaluate the initial keys fromMap the configuration and applyChanges it to the field.
+ *
+ * @param target the target instance.
+ * @param configurations Configuration instances that replace configuration served by services. This allows
+ * more easily testing and adaption.
+ * @throws ConfigException if evaluation or conversion failed.
+ */
+ public void applyInitialValue(Object target, Configuration... configurations) throws ConfigException {
+ String configValue = InjectionUtils.getConfigValue(this.annotatedField, configurations);
+ applyValue(target, configValue, false, configurations);
+ }
+
+
+ /**
+ * This method reapplies a changed configuration keys to the field.
+ *
+ * @param target the target instance, not null.
+ * @param configValue the new keys to be applied, null will trigger the evaluation current the configured default keys.
+ * @param resolve set to true, if expression resolution should be applied on the keys passed.
+ * @throws ConfigException if the configuration required could not be resolved or converted.
+ */
+ public void applyValue(Object target, String configValue, boolean resolve, Configuration... configurations) throws ConfigException {
+ Objects.requireNonNull(target);
+ try {
+ if (resolve && configValue != null) {
+ // net step perform exression resolution, if any
+ configValue = Configuration.evaluateValue(configValue, configurations);
+ }
+ // Check for adapter/filter
+ Object value = InjectionUtils.adaptValue(this.annotatedField, this.annotatedField.getType(), configValue);
+ annotatedField.setAccessible(true);
+ annotatedField.set(target, value);
+ } catch (Exception e) {
+ throw new ConfigException("Failed to annotation configured field: " + this.annotatedField.getDeclaringClass()
+ .getName() + '.' + annotatedField.getName(), e);
+ }
+ }
+
+
+ /**
+ * This method checks if the given (qualified) configuration key is referenced fromMap this field.
+ * This is useful to determine, if a key changed in a configuration should trigger any change events
+ * on the related instances.
+ *
+ * @param key the (qualified) configuration key, not null.
+ * @return true, if the key is referenced.
+ */
+ public boolean matchesKey(String configName, String key) {
+ Collection<ConfiguredProperty> configuredProperties = Utils.getAnnotations(this.annotatedField, ConfiguredProperty.class,
+ ConfiguredProperties.class );
+ for(ConfiguredProperty prop: configuredProperties){
+ String currentName = prop.config().trim();
+ if(currentName.isEmpty()){
+ if(!"default".equals(configName)){
+ continue;
+ }
+ }
+ else if(!currentName.equals(configName)){
+ continue;
+ }
+ DefaultAreas areasAnnot = this.annotatedField.getDeclaringClass().getAnnotation(DefaultAreas.class);
+ List<String> keys = InjectionUtils.evaluateKeys(this.annotatedField, areasAnnot, prop);
+ if( keys.contains(key)){
+ return true;
+ }
+ }
+ return false;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/modules/injection/src/main/java/org/apache/tamaya/inject/internal/ConfiguredSetterMethod.java
----------------------------------------------------------------------
diff --git a/modules/injection/src/main/java/org/apache/tamaya/inject/internal/ConfiguredSetterMethod.java b/modules/injection/src/main/java/org/apache/tamaya/inject/internal/ConfiguredSetterMethod.java
new file mode 100644
index 0000000..90497ae
--- /dev/null
+++ b/modules/injection/src/main/java/org/apache/tamaya/inject/internal/ConfiguredSetterMethod.java
@@ -0,0 +1,136 @@
+/*
+ * 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.core.internal.inject;
+
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.function.Consumer;
+
+import org.apache.tamaya.core.properties.PropertyChangeSet;
+import org.apache.tamaya.ConfigException;
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.annotation.*;
+import org.apache.tamaya.core.internal.Utils;
+
+/**
+ * Small class that contains and manages all information and access to a configured field and a concrete instance current
+ * it (referenced by a weak reference). It also implements all aspects current keys filtering, conversions any applying the
+ * final keys by reflection.
+ */
+public class ConfiguredSetterMethod {
+
+ /**
+ * The configured field instance.
+ */
+ private Method setterMethod;
+
+ /**
+ * Models a configured field and provides mechanisms for injection.
+ *
+ * @param method the method instance.
+ */
+ public ConfiguredSetterMethod(Method method) {
+ this.setterMethod = Optional.of(method).filter(
+ (m) -> void.class.equals(m.getReturnType()) &&
+ m.getParameterCount() == 1).get();
+ }
+
+ public Consumer<PropertyChangeSet> createConsumer(Object instance, Configuration... configurations){
+ // TODO consider environment as well
+ return event -> {
+ for(Configuration cfg:configurations){
+ if(event.getPropertySource().getName().equals(cfg.getName())){
+ // ignore these changes, since this config is overridden.
+ return;
+ }
+ }
+ String configValue = InjectionUtils.getConfigValue(setterMethod, configurations);
+ applyValue(instance,configValue, false, configurations);
+ };
+ }
+
+
+ /**
+ * Evaluate the initial keys fromMap the configuration and applyChanges it to the field.
+ *
+ * @param target the target instance.
+ * @param configurations Configuration instances that replace configuration served by services. This allows
+ * more easily testing and adaption.
+ * @throws ConfigException if evaluation or conversion failed.
+ */
+ public void applyInitialValue(Object target, Configuration... configurations) throws ConfigException {
+ String configValue = InjectionUtils.getConfigValue(this.setterMethod, configurations);
+ applyValue(target, configValue, false, configurations);
+ }
+
+ /**
+ * This method reapplies a changed configuration keys to the field.
+ *
+ * @param target the target instance, not null.
+ * @param configValue the new keys to be applied, null will trigger the evaluation current the configured default keys.
+ * @param resolve set to true, if expression resolution should be applied on the keys passed.
+ * @throws org.apache.tamaya.ConfigException if the configuration required could not be resolved or converted.
+ */
+ public void applyValue(Object target, String configValue, boolean resolve, Configuration... configurations) throws ConfigException {
+ Objects.requireNonNull(target);
+ try {
+ if (resolve && configValue != null) {
+ // net step perform exression resolution, if any
+ configValue = Configuration.evaluateValue(configValue, configurations);
+ }
+ // Check for adapter/filter
+ Object value = InjectionUtils.adaptValue(this.setterMethod, this.setterMethod.getParameterTypes()[0], configValue);
+ setterMethod.setAccessible(true);
+ setterMethod.invoke(target, value);
+ } catch (Exception e) {
+ throw new ConfigException("Failed to annotation configured method: " + this.setterMethod.getDeclaringClass()
+ .getName() + '.' + setterMethod.getName(), e);
+ }
+ }
+
+
+
+ /**
+ * This method checks if the given (qualified) configuration key is referenced fromMap this field.
+ * This is useful to determine, if a key changed in a configuration should trigger any change events
+ * on the related instances.
+ *
+ * @param key the (qualified) configuration key, not null.
+ * @return true, if the key is referenced.
+ */
+ public boolean matchesKey(String key) {
+ DefaultAreas areasAnnot = this.setterMethod.getDeclaringClass().getAnnotation(DefaultAreas.class);
+ Collection<ConfiguredProperty> configuredProperties =
+ Utils.getAnnotations(this.setterMethod, ConfiguredProperty.class, ConfiguredProperties.class);
+ for(ConfiguredProperty prop: configuredProperties) {
+ if (InjectionUtils.evaluateKeys(this.setterMethod, areasAnnot, prop).contains(key)) {
+ return true;
+ }
+ }
+ if (InjectionUtils.evaluateKeys(this.setterMethod, areasAnnot).contains(key)) {
+ return true;
+ }
+ return false;
+ }
+
+
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/modules/injection/src/main/java/org/apache/tamaya/inject/internal/ConfiguredType.java
----------------------------------------------------------------------
diff --git a/modules/injection/src/main/java/org/apache/tamaya/inject/internal/ConfiguredType.java b/modules/injection/src/main/java/org/apache/tamaya/inject/internal/ConfiguredType.java
new file mode 100644
index 0000000..879d54a
--- /dev/null
+++ b/modules/injection/src/main/java/org/apache/tamaya/inject/internal/ConfiguredType.java
@@ -0,0 +1,222 @@
+/*
+ * 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.core.internal.inject;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.*;
+
+import org.apache.tamaya.core.properties.PropertyChangeSet;
+import org.apache.tamaya.ConfigException;
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.PropertySource;
+import org.apache.tamaya.annotation.*;
+import org.apache.tamaya.core.internal.Utils;
+
+/**
+ * Structure that contains and manages configuration related things for a configured type registered.
+ * Created by Anatole on 03.10.2014.
+ */
+@SuppressWarnings({"rawtypes", "unchecked"})
+public class ConfiguredType {
+ /**
+ * A list with all annotated instance variables.
+ */
+ private List<ConfiguredField> configuredFields = new ArrayList<>();
+ /**
+ * A list with all annotated methods (templates).
+ */
+ private List<ConfiguredSetterMethod> configuredSetterMethods = new ArrayList<>();
+ /**
+ * A list with all callback methods listening to config changes.
+ */
+ private List<ConfigChangeCallbackMethod> callbackMethods = new ArrayList<>();
+ /**
+ * The basic type.
+ */
+ private Class type;
+
+ /**
+ * Creates an instance of this class hereby evaluating the config annotations given for later effective
+ * injection (configuration) of instances.
+ *
+ * @param type the instance type.
+ */
+
+ public ConfiguredType(Class type) {
+ this.type = Objects.requireNonNull(type);
+ initFields(type);
+ initMethods(type);
+ }
+
+ private void initFields(Class type) {
+ for (Field f : type.getDeclaredFields()) {
+ if (f.isAnnotationPresent(NoConfig.class)) {
+ continue;
+ }
+ try {
+ ConfiguredField configuredField = new ConfiguredField(f);
+ configuredFields.add(configuredField);
+ } catch (Exception e) {
+ throw new ConfigException("Failed to initialized configured field: " +
+ f.getDeclaringClass().getName() + '.' + f.getName(), e);
+ }
+ }
+ }
+
+ private void initMethods(Class type) {
+ // TODO revisit this logic here...
+ for (Method m : type.getDeclaredMethods()) {
+ if (m.isAnnotationPresent(NoConfig.class)) {
+ continue;
+ }
+ ObservesConfigChange mAnnot = m.getAnnotation(ObservesConfigChange.class);
+ Collection<ConfiguredProperty> propertiesAnnots = Utils.getAnnotations(m, ConfiguredProperty.class, ConfiguredProperties.class);
+ if (type.isInterface()) {
+ // it is a template
+ if (mAnnot != null) {
+ if (m.isDefault()) {
+ addObserverMethod(m);
+ }
+ } else {
+ if (m.isDefault()) {
+ addPropertySetter(m, propertiesAnnots);
+ }
+ }
+ } else {
+ if (mAnnot != null) {
+ addObserverMethod(m);
+ } else {
+ addPropertySetter(m, propertiesAnnots);
+ }
+ }
+ }
+ }
+
+ private boolean addPropertySetter(Method m, Collection<ConfiguredProperty> propertiesAnnots) {
+ if (!propertiesAnnots.isEmpty()) {
+ if (m.getParameterTypes().length == 0) {
+ // getter method
+ Class<?> returnType = m.getReturnType();
+ if (!void.class.equals(returnType)) {
+ try {
+ configuredSetterMethods.add(new ConfiguredSetterMethod(m));
+ return true;
+ } catch (Exception e) {
+ throw new ConfigException("Failed to initialized configured setter method: " +
+ m.getDeclaringClass().getName() + '.' + m.getName(), e);
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+
+
+ private void addObserverMethod(Method m) {
+ if (m.getParameterTypes().length != 1) {
+ return;
+ }
+ if (!m.getParameterTypes()[0].equals(PropertyChangeSet.class)) {
+ return;
+ }
+ if (!void.class.equals(m.getReturnType())) {
+ return;
+ }
+ try {
+ this.callbackMethods.add(new ConfigChangeCallbackMethod(m));
+ } catch (Exception e) {
+ throw new ConfigException("Failed to initialized configured callback method: " +
+ m.getDeclaringClass().getName() + '.' + m.getName(), e);
+ }
+ }
+
+
+ /**
+ * Method called to configure an instance.
+ *
+ * @param instance The instance to be configured.
+ * @param configurations Configuration instances that replace configuration served by services. This allows
+ * more easily testing and adaption.
+ */
+ public void configure(Object instance, Configuration... configurations) {
+ for (ConfiguredField field : configuredFields) {
+ field.applyInitialValue(instance, configurations);
+ }
+ for (ConfiguredSetterMethod method : configuredSetterMethods) {
+ method.applyInitialValue(instance, configurations);
+ // TODO, if method should be recalled on changes, corresponding callbacks could be registered here
+ WeakConfigListenerManager.of().registerConsumer(instance, method.createConsumer(instance, configurations));
+ }
+ // Register callbacks for this intance (weakly)
+ for (ConfigChangeCallbackMethod callback : callbackMethods) {
+ WeakConfigListenerManager.of().registerConsumer(instance, callback.createConsumer(instance, configurations));
+ }
+ }
+
+
+ private String getName(Object source) {
+ if (source instanceof PropertySource) {
+ PropertySource ps = (PropertySource) source;
+ return ps.getName();
+ }
+ return "N/A";
+ }
+
+
+ public boolean isConfiguredBy(Configuration configuration) {
+ // TODO implement this
+ return true;
+ }
+
+ public static boolean isConfigured(Class type) {
+ if (type.getAnnotation(DefaultAreas.class) != null) {
+ return true;
+ }
+ // if no class level annotation is there we might have field level annotations only
+ for (Field field : type.getDeclaredFields()) {
+ if (field.isAnnotationPresent(ConfiguredProperties.class)) {
+ return true;
+ }
+ }
+ // if no class level annotation is there we might have method level annotations only
+ for (Method method : type.getDeclaredMethods()) {
+ if (method.isAnnotationPresent(ConfiguredProperties.class)) {
+ return true;
+ }
+ }
+ for (Field field : type.getDeclaredFields()) {
+ if (field.isAnnotationPresent(ConfiguredProperty.class)) {
+ return true;
+ }
+ }
+ // if no class level annotation is there we might have method level annotations only
+ for (Method method : type.getDeclaredMethods()) {
+ if (method.isAnnotationPresent(ConfiguredProperty.class)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public Class getType() {
+ return this.type;
+ }
+}