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 2016/10/30 22:06:26 UTC
[04/15] incubator-tamaya-extensions git commit: TAMAYA-189: Moved
format and injection modules into separate subtrees.
http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/fe7cd8f1/modules/injection/src/test/java/org/apache/tamaya/inject/internal/DefaultDynamicValueTest.java
----------------------------------------------------------------------
diff --git a/modules/injection/src/test/java/org/apache/tamaya/inject/internal/DefaultDynamicValueTest.java b/modules/injection/src/test/java/org/apache/tamaya/inject/internal/DefaultDynamicValueTest.java
deleted file mode 100644
index dd16f36..0000000
--- a/modules/injection/src/test/java/org/apache/tamaya/inject/internal/DefaultDynamicValueTest.java
+++ /dev/null
@@ -1,315 +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.inject.internal;
-
-import org.apache.tamaya.ConfigException;
-import org.apache.tamaya.ConfigurationProvider;
-import org.apache.tamaya.builder.ConfigurationBuilder;
-import org.apache.tamaya.inject.api.ConfiguredItemSupplier;
-import org.apache.tamaya.inject.api.DynamicValue;
-import org.apache.tamaya.inject.api.Config;
-import org.apache.tamaya.inject.api.UpdatePolicy;
-import org.apache.tamaya.spi.ConversionContext;
-import org.apache.tamaya.spi.PropertyConverter;
-import org.apache.tamaya.spi.PropertySource;
-import org.apache.tamaya.spi.PropertyValue;
-import org.junit.Test;
-
-import org.apache.tamaya.Configuration;
-
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-import java.util.HashMap;
-import java.util.Map;
-
-import static org.junit.Assert.*;
-
-/**
- * Tests for {@link org.apache.tamaya.inject.internal.DefaultDynamicValue}.
- */
-public class DefaultDynamicValueTest {
-
- @Config("a")
- String myValue;
-
- @Config("a")
- String myValue2;
-
- @Config("a")
- void setterMethod(String value){
-
- }
-
- private PropertyChangeEvent event;
-
- private PropertyChangeListener consumer = new PropertyChangeListener() {
- @Override
- public void propertyChange(PropertyChangeEvent evt) {
- event = evt;
- }
- };
-
- private Map<String,String> properties = new HashMap<>();
- private Configuration config = new ConfigurationBuilder().addPropertySources(
- new PropertySource() {
- @Override
- public int getOrdinal() {
- return 0;
- }
-
- @Override
- public String getName() {
- return "test";
- }
-
- @Override
- public PropertyValue get(String key) {
- return PropertyValue.of(key,properties.get(key),getName());
- }
-
- @Override
- public Map<String, String> getProperties() {
- return properties;
- }
-
- @Override
- public boolean isScannable() {
- return false;
- }
- }
- ).build();
-
- @Test
- public void testOf_Field() throws Exception {
- DynamicValue val = DefaultDynamicValue.of(getClass().getDeclaredField("myValue"),
- ConfigurationProvider.getConfiguration());
- assertNotNull(val);
- }
-
- @Test
- public void testOf_Method() throws Exception {
- DynamicValue val = DefaultDynamicValue.of(getClass().getDeclaredMethod("setterMethod", String.class),
- config);
- assertNotNull(val);
- }
-
- @Test
- public void testCommitAndGet() throws Exception {
- properties.put("a","aValue");
- DynamicValue val = DefaultDynamicValue.of(getClass().getDeclaredField("myValue"),
- config);
- assertNotNull(val);
- assertEquals("aValue",val.evaluateValue());
- }
-
- @Test
- public void testCommitAndGets() throws Exception {
- properties.put("a","aValue");
- DynamicValue val = DefaultDynamicValue.of(getClass().getDeclaredField("myValue"),
- config);
- val.setUpdatePolicy(UpdatePolicy.EXPLCIT);
- assertNotNull(val);
- assertEquals("aValue",val.evaluateValue());
- // change config
- val.get();
- this.properties.put("a", "aValue2");
- assertTrue(val.updateValue());
- assertEquals("aValue2", val.commitAndGet());
- }
-
- @Test
- public void testCommit() throws Exception {
- properties.put("a", "aValue");
- DynamicValue val = DefaultDynamicValue.of(getClass().getDeclaredField("myValue"),
- config);
- val.setUpdatePolicy(UpdatePolicy.EXPLCIT);
- assertNotNull(val);
- assertEquals("aValue", val.evaluateValue());
- // change config
- val.get();
- this.properties.put("a", "aValue2");
- assertEquals("aValue2", val.evaluateValue());
- assertTrue(val.updateValue());
- val.commit();
- assertEquals("aValue2", val.get());
- }
-
- @Test
- public void testGetSetUpdatePolicy() throws Exception {
- DynamicValue val = DefaultDynamicValue.of(getClass().getDeclaredField("myValue"),
- config);
- for(UpdatePolicy pol: UpdatePolicy.values()) {
- val.setUpdatePolicy(pol);
- assertEquals(pol, val.getUpdatePolicy());
- }
- }
-
- @Test
- public void testAddRemoveListener() throws Exception {
- properties.put("a","aValue");
- DynamicValue val = DefaultDynamicValue.of(getClass().getDeclaredField("myValue"),
- config);
- val.setUpdatePolicy(UpdatePolicy.IMMEDEATE);
- val.addListener(consumer);
- // change config
- val.get();
- this.properties.put("a", "aValue2");
- val.get();
- assertNotNull(event);
- event = null;
- val.removeListener(consumer);
- this.properties.put("a", "aValue3");
- val.updateValue();
- assertNull(event);
- }
-
- @Test
- public void testGet() throws Exception {
- properties.put("a", "aValue");
- DynamicValue val = DefaultDynamicValue.of(getClass().getDeclaredField("myValue"),
- config);
- val.setUpdatePolicy(UpdatePolicy.IMMEDEATE);
- properties.put("a", "aValue2");
- val.updateValue();
- assertEquals("aValue2", val.get());
- }
-
- @Test
- public void testUpdateValue() throws Exception {
- properties.put("a","aValue");
- DynamicValue val = DefaultDynamicValue.of(getClass().getDeclaredField("myValue"),
- config);
- val.setUpdatePolicy(UpdatePolicy.EXPLCIT);
- assertNotNull(val.get());
- assertEquals("aValue", val.get());
- val.updateValue();
- assertEquals("aValue", val.get());
- val.setUpdatePolicy(UpdatePolicy.IMMEDEATE);
- val.updateValue();
- assertEquals("aValue",val.get());
- }
-
- @Test
- public void testEvaluateValue() throws Exception {
- properties.put("a","aValue");
- DynamicValue val = DefaultDynamicValue.of(getClass().getDeclaredField("myValue"),
- config);
- val.setUpdatePolicy(UpdatePolicy.EXPLCIT);
- assertNotNull(val.get());
- assertEquals("aValue",val.evaluateValue());
- properties.put("a", "aValue2");
- assertEquals("aValue2", val.evaluateValue());
- }
-
- @Test
- public void testGetNewValue() throws Exception {
- properties.put("a","aValue");
- DynamicValue val = DefaultDynamicValue.of(getClass().getDeclaredField("myValue"),
- config);
- val.setUpdatePolicy(UpdatePolicy.EXPLCIT);
- val.get();
- assertNull(val.getNewValue());
- properties.put("a", "aValue2");
- val.get();
- assertNotNull(val.getNewValue());
- assertEquals("aValue2", val.getNewValue());
- val.commit();
- assertNull(val.getNewValue());
- }
-
- @Test
- public void testIsPresent() throws Exception {
-
- }
-
- @Test
- public void testIfPresent() throws Exception {
- properties.put("a","aValue");
- DynamicValue val = DefaultDynamicValue.of(getClass().getDeclaredField("myValue"),
- config);
- val.setUpdatePolicy(UpdatePolicy.IMMEDEATE);
- assertTrue(val.isPresent());
- properties.remove("a");
- val.updateValue();
- assertFalse(val.isPresent());
- }
-
- @Test
- public void testOrElse() throws Exception {
- DynamicValue val = DefaultDynamicValue.of(getClass().getDeclaredField("myValue"),
- config);
- val.setUpdatePolicy(UpdatePolicy.IMMEDEATE);
- assertEquals("bla", val.orElse("bla"));
- properties.put("a","aValue");
- val.updateValue();
- assertEquals("aValue", val.orElse("bla"));
- }
-
- @Test
- public void testOrElseGet() throws Exception {
- DynamicValue val = DefaultDynamicValue.of(getClass().getDeclaredField("myValue"),
- config);
- val.setUpdatePolicy(UpdatePolicy.IMMEDEATE);
- assertEquals("bla", val.orElseGet(new ConfiguredItemSupplier() {
- @Override
- public Object get() {
- return "bla";
- }
- }));
- properties.put("a", "aValue");
- val.updateValue();
- assertEquals("aValue", val.orElseGet(new ConfiguredItemSupplier() {
- @Override
- public Object get() {
- return "bla";
- }
- }));
- }
-
- @Test(expected = ConfigException.class)
- public void testOrElseThrow() throws Throwable {
- DynamicValue val = DefaultDynamicValue.of(getClass().getDeclaredField("myValue"),
- config);
- val.setUpdatePolicy(UpdatePolicy.EXPLCIT);
- val.get();
- properties.put("a", "aValue");
- assertEquals("aValue", val.orElseThrow(new ConfiguredItemSupplier() {
- @Override
- public ConfigException get() {
- return new ConfigException("bla");
- }
- }));
- properties.remove("a");
- val.updateValue();
- assertEquals("aValue", val.orElseThrow(new ConfiguredItemSupplier() {
- @Override
- public ConfigException get() {
- return new ConfigException("bla");
- }
- }));
- }
-
- private static final class DoublicatingConverter implements PropertyConverter<String>{
-
- @Override
- public String convert(String value, ConversionContext context) {
- return value + value;
- }
- }
-}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/fe7cd8f1/modules/injection/src/test/resources/META-INF/services/org.apache.tamaya.spi.PropertySource
----------------------------------------------------------------------
diff --git a/modules/injection/src/test/resources/META-INF/services/org.apache.tamaya.spi.PropertySource b/modules/injection/src/test/resources/META-INF/services/org.apache.tamaya.spi.PropertySource
deleted file mode 100644
index 5dfb894..0000000
--- a/modules/injection/src/test/resources/META-INF/services/org.apache.tamaya.spi.PropertySource
+++ /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.inject.TestPropertySource
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/fe7cd8f1/modules/injection/standalone/pom.xml
----------------------------------------------------------------------
diff --git a/modules/injection/standalone/pom.xml b/modules/injection/standalone/pom.xml
new file mode 100644
index 0000000..5d5c975
--- /dev/null
+++ b/modules/injection/standalone/pom.xml
@@ -0,0 +1,104 @@
+<!--
+ ~ 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.
+ -->
+<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.ext</groupId>
+ <artifactId>tamaya-injection-all</artifactId>
+ <version>0.3-incubating-SNAPSHOT</version>
+ <relativePath>..</relativePath>
+ </parent>
+ <artifactId>tamaya-injection</artifactId>
+ <name>Apache Tamaya odules - Injection Standalone</name>
+ <packaging>bundle</packaging>
+
+ <properties>
+ <jdkVersion>1.7</jdkVersion>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.tamaya</groupId>
+ <artifactId>tamaya-api</artifactId>
+ <version>${project.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.tamaya.ext</groupId>
+ <artifactId>tamaya-injection-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.tamaya</groupId>
+ <artifactId>tamaya-core</artifactId>
+ <version>${project.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.tamaya.ext</groupId>
+ <artifactId>tamaya-resolver</artifactId>
+ <version>${project.version}</version>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.tamaya.ext</groupId>
+ <artifactId>tamaya-builder</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.tamaya.ext</groupId>
+ <artifactId>tamaya-events</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.hamcrest</groupId>
+ <artifactId>java-hamcrest</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Export-Package>
+ org.apache.tamaya.inject
+ </Export-Package>
+ <Private-Package>
+ org.apache.tamaya.inject.internal
+ </Private-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/fe7cd8f1/modules/injection/standalone/src/main/java/org/apache/tamaya/inject/ConfigurationInjection.java
----------------------------------------------------------------------
diff --git a/modules/injection/standalone/src/main/java/org/apache/tamaya/inject/ConfigurationInjection.java b/modules/injection/standalone/src/main/java/org/apache/tamaya/inject/ConfigurationInjection.java
new file mode 100644
index 0000000..79d6218
--- /dev/null
+++ b/modules/injection/standalone/src/main/java/org/apache/tamaya/inject/ConfigurationInjection.java
@@ -0,0 +1,42 @@
+/*
+ * 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.inject;
+
+import org.apache.tamaya.spi.ServiceContextManager;
+
+/**
+ * Singleton accessor class for accessing {@link ConfigurationInjector} instances.
+ */
+public final class ConfigurationInjection {
+
+ /**
+ * Singleton constructor.
+ */
+ private ConfigurationInjection() {
+ }
+
+ /**
+ * Get the current injector instance.
+ *
+ * @return the current injector, not null.
+ */
+ public static ConfigurationInjector getConfigurationInjector() {
+ return ServiceContextManager.getServiceContext().getService(ConfigurationInjector.class);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/fe7cd8f1/modules/injection/standalone/src/main/java/org/apache/tamaya/inject/ConfigurationInjector.java
----------------------------------------------------------------------
diff --git a/modules/injection/standalone/src/main/java/org/apache/tamaya/inject/ConfigurationInjector.java b/modules/injection/standalone/src/main/java/org/apache/tamaya/inject/ConfigurationInjector.java
new file mode 100644
index 0000000..563ae47
--- /dev/null
+++ b/modules/injection/standalone/src/main/java/org/apache/tamaya/inject/ConfigurationInjector.java
@@ -0,0 +1,94 @@
+/*
+ * 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.inject;
+
+
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.inject.api.ConfiguredItemSupplier;
+
+/**
+ * Accessor interface for injection of configuration and configuration templates.
+ */
+public interface ConfigurationInjector {
+
+ /**
+ * Configures the current instance and registers necessary listener to forward config change events as
+ * defined by the current annotations in place.
+ *
+ * Unannotated types are ignored.
+ *
+ * @param <T> the type of the instance.
+ * @param instance the instance to be configured
+ * @return the configured instance (allows chaining of operations).
+ */
+ <T> T configure(T instance);
+
+ /**
+ * Configures the current instance and registers necessary listener to forward config change events as
+ * defined by the current annotations in place.
+ *
+ * Unannotated types are ignored.
+ *
+ * @param <T> the type of the instance.
+ * @param instance the instance to be configured
+ * @param config the configuration to be used for injection.
+ * @return the configured instance (allows chaining of operations).
+ */
+ <T> T configure(T instance, Configuration config);
+
+ /**
+ * Creates a template implementing the annotated methods based on current configuration data.
+ *
+ * @param <T> the type of the template.
+ * @param templateType the type of the template to be created.
+ * @return the configured template.
+ */
+ <T> T createTemplate(Class<T> templateType);
+
+ /**
+ * Creates a template implementting the annotated methods based on current configuration data.
+ *
+ * @param <T> the type of the template.
+ * @param config the configuration to be used for backing the template.
+ * @param templateType the type of the template to be created.
+ * @return the configured template.
+ */
+ <T> T createTemplate(Class<T> templateType, Configuration config);
+
+
+ /**
+ * Creates a supplier for configured instances of the given type {@code T}.
+ *
+ * @param supplier the supplier to create new instances.
+ * @param <T> the target type.
+ * @return a supplier creating configured instances of {@code T}.
+ */
+ <T> ConfiguredItemSupplier<T> getConfiguredSupplier(ConfiguredItemSupplier<T> supplier);
+
+ /**
+ * Creates a supplier for configured instances of the given type {@code T}.
+ *
+ * @param supplier the supplier to create new instances.
+ * @param config the configuration to be used for backing the supplier.
+ * @param <T> the target type.
+ * @return a supplier creating configured instances of {@code T}.
+ */
+ <T> ConfiguredItemSupplier<T> getConfiguredSupplier(ConfiguredItemSupplier<T> supplier, Configuration config);
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/fe7cd8f1/modules/injection/standalone/src/main/java/org/apache/tamaya/inject/internal/ConfigTemplateInvocationHandler.java
----------------------------------------------------------------------
diff --git a/modules/injection/standalone/src/main/java/org/apache/tamaya/inject/internal/ConfigTemplateInvocationHandler.java b/modules/injection/standalone/src/main/java/org/apache/tamaya/inject/internal/ConfigTemplateInvocationHandler.java
new file mode 100644
index 0000000..5d634e1
--- /dev/null
+++ b/modules/injection/standalone/src/main/java/org/apache/tamaya/inject/internal/ConfigTemplateInvocationHandler.java
@@ -0,0 +1,73 @@
+/*
+ * 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.inject.internal;
+
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.ConfigurationProvider;
+import org.apache.tamaya.TypeLiteral;
+import org.apache.tamaya.inject.api.DynamicValue;
+import org.apache.tamaya.inject.spi.ConfiguredType;
+
+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 {
+
+ /**
+ * The configured type.
+ */
+ private final ConfiguredType type;
+
+ /**
+ * Creates a new handler instance.
+ *
+ * @param type the target type, not null.
+ */
+ public ConfigTemplateInvocationHandler(Class<?> type) {
+ this.type = new ConfiguredTypeImpl(Objects.requireNonNull(type));
+ if (!type.isInterface()) {
+ throw new IllegalArgumentException("Can only proxy interfaces as configuration templates.");
+ }
+ InjectionHelper.sendConfigurationEvent(this.type);
+ }
+
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ Configuration config = ConfigurationProvider.getConfiguration();
+ if ("toString".equals(method.getName())) {
+ return "Configured Proxy -> " + this.type.getType().getName();
+ } else if ("hashCode".equals(method.getName())) {
+ return Objects.hashCode(proxy);
+ } else if ("equals".equals(method.getName())) {
+ return Objects.equals(proxy, args[0]);
+ } else if ("get".equals(method.getName())) {
+ return config;
+ }
+ if (method.getReturnType() == DynamicValue.class) {
+ return DefaultDynamicValue.of(method, config);
+ }
+ String[] retKey = new String[1];
+ String configValue = InjectionHelper.getConfigValue(method, retKey, config);
+ return InjectionHelper.adaptValue(method, TypeLiteral.of(method.getReturnType()), retKey[0], configValue);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/fe7cd8f1/modules/injection/standalone/src/main/java/org/apache/tamaya/inject/internal/ConfiguredFieldImpl.java
----------------------------------------------------------------------
diff --git a/modules/injection/standalone/src/main/java/org/apache/tamaya/inject/internal/ConfiguredFieldImpl.java b/modules/injection/standalone/src/main/java/org/apache/tamaya/inject/internal/ConfiguredFieldImpl.java
new file mode 100644
index 0000000..64b0c95
--- /dev/null
+++ b/modules/injection/standalone/src/main/java/org/apache/tamaya/inject/internal/ConfiguredFieldImpl.java
@@ -0,0 +1,170 @@
+/*
+ * 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.inject.internal;
+
+import org.apache.tamaya.ConfigException;
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.ConfigurationProvider;
+import org.apache.tamaya.TypeLiteral;
+import org.apache.tamaya.inject.api.DynamicValue;
+import org.apache.tamaya.inject.api.InjectionUtils;
+import org.apache.tamaya.inject.spi.ConfiguredField;
+
+import java.lang.reflect.Field;
+import java.security.AccessController;
+import java.security.PrivilegedExceptionAction;
+import java.util.Collection;
+import java.util.Objects;
+
+/**
+ * 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 ConfiguredFieldImpl implements ConfiguredField{
+ /**
+ * The configured field instance.
+ */
+ protected final Field annotatedField;
+
+ /**
+ * Models a configured field and provides mechanisms for injection.
+ *
+ * @param field the field instance.
+ */
+ public ConfiguredFieldImpl(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.
+ * @throws ConfigException if evaluation or conversion failed.
+ */
+ public void configure(Object target, Configuration config) throws ConfigException {
+ if (this.annotatedField.getType() == DynamicValue.class) {
+ applyDynamicValue(target);
+ } else {
+ applyValue(target, config, false);
+ }
+ }
+
+
+ /**
+ * This method instantiates and assigns a dynamic value.
+ *
+ * @param target the target instance, not null.
+ * @throws ConfigException if the configuration required could not be resolved or converted.
+ */
+ private void applyDynamicValue(Object target) throws ConfigException {
+ Objects.requireNonNull(target);
+ try {
+ AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
+ @Override
+ public Object run() throws Exception {
+ annotatedField.setAccessible(true);
+ return annotatedField;
+ }
+ });
+ annotatedField.set(target,
+ DefaultDynamicValue.of(annotatedField, ConfigurationProvider.getConfiguration()));
+ } catch (Exception e) {
+ throw new ConfigException("Failed to annotation configured field: " + this.annotatedField.getDeclaringClass()
+ .getName() + '.' + annotatedField.getName(), e);
+ }
+ }
+
+ /**
+ * This method applies a configuration to the field.
+ *
+ * @param target the target instance, not null.
+ * @param config The configuration to be used.
+ * @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.
+ */
+ private void applyValue(Object target, Configuration config, boolean resolve) throws ConfigException {
+ Objects.requireNonNull(target);
+ try {
+ String[] retKey = new String[1];
+ String configValue = InjectionHelper.getConfigValue(this.annotatedField, retKey, config);
+ // Next step perform expression resolution, if any
+ String evaluatedValue = resolve && configValue != null
+ ? InjectionHelper.evaluateValue(configValue)
+ : configValue;
+
+ // Check for adapter/filter
+ Object value = InjectionHelper.adaptValue(this.annotatedField,
+ TypeLiteral.of(this.annotatedField.getType()), retKey[0], evaluatedValue);
+ AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
+ @Override
+ public Object run() throws Exception {
+ annotatedField.setAccessible(true);
+ return annotatedField;
+ }
+ });
+ if(value!=null) {
+ annotatedField.set(target, value);
+ }
+ } catch (Exception e) {
+ throw new ConfigException("Failed to evaluate annotated field: " + this.annotatedField.getDeclaringClass()
+ .getName() + '.' + annotatedField.getName(), e);
+ }
+ }
+
+ /**
+ * Get the field's type.
+ * @return the field's type, not null.
+ */
+ @Override
+ public Class<?> getType(){
+ return this.annotatedField.getType();
+ }
+
+ /**
+ * Access the applyable configuration keys for this field.
+ * @return the configuration keys, never null.
+ */
+ @Override
+ public Collection<String> getConfiguredKeys(){
+ return InjectionUtils.getKeys(this.annotatedField);
+ }
+
+ @Override
+ public String toString() {
+ return "ConfiguredField[" + getSignature() + ']';
+ }
+
+ @Override
+ public String getName() {
+ return annotatedField.getName();
+ }
+
+ @Override
+ public String getSignature() {
+ return getName()+':'+getType().getName();
+ }
+
+ @Override
+ public Field getAnnotatedField() {
+ return annotatedField;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/fe7cd8f1/modules/injection/standalone/src/main/java/org/apache/tamaya/inject/internal/ConfiguredSetterMethod.java
----------------------------------------------------------------------
diff --git a/modules/injection/standalone/src/main/java/org/apache/tamaya/inject/internal/ConfiguredSetterMethod.java b/modules/injection/standalone/src/main/java/org/apache/tamaya/inject/internal/ConfiguredSetterMethod.java
new file mode 100644
index 0000000..b69df20
--- /dev/null
+++ b/modules/injection/standalone/src/main/java/org/apache/tamaya/inject/internal/ConfiguredSetterMethod.java
@@ -0,0 +1,139 @@
+/*
+ * 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.inject.internal;
+
+import org.apache.tamaya.ConfigException;
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.TypeLiteral;
+import org.apache.tamaya.inject.api.InjectionUtils;
+import org.apache.tamaya.inject.spi.ConfiguredMethod;
+
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedExceptionAction;
+import java.util.Collection;
+import java.util.Objects;
+
+/**
+ * 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 implements ConfiguredMethod {
+
+ /**
+ * The configured field instance.
+ */
+ private Method setterMethod;
+ private Collection<String> configuredKeys;
+
+ /**
+ * Models a configured field and provides mechanisms for injection.
+ *
+ * @param method the method instance.
+ */
+ public ConfiguredSetterMethod(Method method) {
+ if (void.class.equals(method.getReturnType()) &&
+ method.getParameterTypes().length == 1) {
+ this.setterMethod = method;
+ }
+ }
+
+ @Override
+ public void configure(Object target, Configuration config) throws ConfigException {
+ String[] retKey = new String[1];
+ String configValue = InjectionHelper.getConfigValue(this.setterMethod, retKey, config);
+ Objects.requireNonNull(target);
+ try {
+ String evaluatedString = configValue != null
+ ? InjectionHelper.evaluateValue(configValue)
+ : configValue;
+
+ // Check for adapter/filter
+ Object value = InjectionHelper.adaptValue(
+ this.setterMethod, TypeLiteral.of(this.setterMethod.getParameterTypes()[0]),
+ retKey[0], evaluatedString);
+
+ AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
+ @Override
+ public Object run() throws Exception {
+ setterMethod.setAccessible(true);
+ return setterMethod;
+ }
+ });
+
+ setterMethod.invoke(target, value);
+ } catch (Exception e) {
+ throw new ConfigException("Failed to annotation configured method: " + this.setterMethod.getDeclaringClass()
+ .getName() + '.' + setterMethod.getName(), e);
+ }
+ }
+
+
+ /**
+ * Access the applyable configuration keys for this field.
+ *
+ * @return the configuration keys, never null.
+ */
+ @Override
+ public Collection<String> getConfiguredKeys() {
+ return InjectionUtils.getKeys(this.setterMethod);
+ }
+
+ /**
+ * Get the type to be set on the setter method.
+ * @return the setter type.
+ */
+ @Override
+ public Class<?>[] getParameterTypes() {
+ return this.setterMethod.getParameterTypes();
+ }
+
+ /**
+ * Access the annotated method.
+ * @return the annotated method, not null.
+ */
+ @Override
+ public Method getAnnotatedMethod() {
+ return this.setterMethod;
+ }
+
+ @Override
+ public String getName() {
+ return this.setterMethod.getName();
+ }
+
+ @Override
+ public String getSignature() {
+ return "void " + this.setterMethod.getName()+'('+ printTypes(getParameterTypes())+')';
+ }
+
+ private String printTypes(Class<?>[] parameterTypes) {
+ StringBuilder b = new StringBuilder();
+ for(Class cl:parameterTypes){
+ b.append(cl.getName());
+ b.append(',');
+ }
+ if(b.length()>0){
+ b.setLength(b.length()-1);
+ }
+ return b.toString();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/fe7cd8f1/modules/injection/standalone/src/main/java/org/apache/tamaya/inject/internal/ConfiguredTypeImpl.java
----------------------------------------------------------------------
diff --git a/modules/injection/standalone/src/main/java/org/apache/tamaya/inject/internal/ConfiguredTypeImpl.java b/modules/injection/standalone/src/main/java/org/apache/tamaya/inject/internal/ConfiguredTypeImpl.java
new file mode 100644
index 0000000..b40f6c9
--- /dev/null
+++ b/modules/injection/standalone/src/main/java/org/apache/tamaya/inject/internal/ConfiguredTypeImpl.java
@@ -0,0 +1,237 @@
+/*
+ * 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.inject.internal;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.*;
+import java.util.logging.Logger;
+
+import org.apache.tamaya.ConfigException;
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.ConfigurationProvider;
+import org.apache.tamaya.inject.api.ConfigAutoInject;
+import org.apache.tamaya.inject.api.NoConfig;
+import org.apache.tamaya.inject.api.Config;
+import org.apache.tamaya.inject.api.ConfigDefaultSections;
+import org.apache.tamaya.inject.spi.ConfiguredField;
+import org.apache.tamaya.inject.spi.ConfiguredMethod;
+import org.apache.tamaya.inject.spi.ConfiguredType;
+
+/**
+ * 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 ConfiguredTypeImpl implements ConfiguredType{
+ /** The log used. */
+ private static final Logger LOG = Logger.getLogger(ConfiguredTypeImpl.class.getName());
+ /**
+ * A list with all annotated instance variables.
+ */
+ private final List<ConfiguredField> configuredFields = new ArrayList<>();
+ /**
+ * A list with all annotated methods (templates).
+ */
+ private final List<ConfiguredMethod> configuredSetterMethods = new ArrayList<>();
+ /**
+ * The basic type.
+ */
+ private final 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 ConfiguredTypeImpl(Class type) {
+ this.type = Objects.requireNonNull(type);
+ if(!isConfigured(type)){
+ LOG.info("Auto-Configuring type: " + type.getName());
+ initFields(type, true);
+ initMethods(type, true);
+ }else {
+ ConfigAutoInject autoInject = (ConfigAutoInject) type.getAnnotation(ConfigAutoInject.class);
+ if (autoInject != null) {
+ initFields(type, autoInject != null);
+ initMethods(type, autoInject != null);
+ } else {
+ initFields(type, false);
+ initMethods(type, false);
+ }
+ }
+ }
+
+ private void initFields(Class type, boolean autoConfigure) {
+ for (Field f : type.getDeclaredFields()) {
+ if (f.isAnnotationPresent(NoConfig.class)) {
+ LOG.finest("Ignored @NoConfig annotated field " + f.getClass().getName() + "#" +
+ f.toGenericString());
+ continue;
+ }
+ if (Modifier.isFinal(f.getModifiers())) {
+ LOG.finest("Ignored final field " + f.getClass().getName() + "#" +
+ f.toGenericString());
+ continue;
+ }
+ if (f.isSynthetic()) {
+ LOG.finest("Ignored synthetic field " + f.getClass().getName() + "#" +
+ f.toGenericString());
+ continue;
+ }
+ try {
+ if(isConfiguredField(f) || autoConfigure) {
+ ConfiguredField configuredField = new ConfiguredFieldImpl(f);
+ configuredFields.add(configuredField);
+ LOG.finer("Registered field " + f.getClass().getName() + "#" +
+ f.toGenericString());
+ }
+ } catch (Exception e) {
+ throw new ConfigException("Failed to initialized configured field: " +
+ f.getDeclaringClass().getName() + '.' + f.getName(), e);
+ }
+ }
+ }
+
+ private void initMethods(Class type, boolean autoConfigure) {
+ // TODO revisit this logic here...
+ for (Method m : type.getDeclaredMethods()) {
+ if (m.isAnnotationPresent(NoConfig.class)) {
+ LOG.finest("Ignored @NoConfig annotated method " + m.getClass().getName() + "#" +
+ m.toGenericString());
+ continue;
+ }
+ if (m.isSynthetic()) {
+ LOG.finest("Ignored synthetic method " + m.getClass().getName() + "#" +
+ m.toGenericString());
+ continue;
+ }
+ if(isConfiguredMethod(m) || autoConfigure) {
+ Config propAnnot = m.getAnnotation(Config.class);
+ if (addPropertySetter(m, propAnnot)) {
+ LOG.finer("Added configured setter: " + m.getClass().getName() + "#" +
+ m.toGenericString());
+ }
+ }
+ }
+ }
+
+ private boolean addPropertySetter(Method m, Config prop) {
+ if (prop!=null) {
+ if (m.getParameterTypes().length == 1) {
+ // 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;
+ }
+
+
+ /**
+ * Method called to configure an instance.
+ *
+ * @param instance The instance to be configured.
+ */
+ public void configure(Object instance) {
+ configure(instance, ConfigurationProvider.getConfiguration());
+ }
+
+ @Override
+ public void configure(Object instance, Configuration config) {
+ for (ConfiguredField field : configuredFields) {
+ field.configure(instance, config);
+ }
+ for (ConfiguredMethod method : configuredSetterMethods) {
+ method.configure(instance, config);
+// // TODO, if method should be recalled on changes, corresponding callbacks could be registered here
+ }
+ }
+
+
+ public static boolean isConfigured(Class type) {
+ if (type.getAnnotation(ConfigDefaultSections.class) != null) {
+ return true;
+ }
+ // if no class level annotation is there we might have field level annotations only
+ for (Field field : type.getDeclaredFields()) {
+ if (isConfiguredField(field)) {
+ return true;
+ }
+ }
+ // if no class level annotation is there we might have method level annotations only
+ for (Method method : type.getDeclaredMethods()) {
+ if(isConfiguredMethod(method)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static boolean isConfiguredField(Field field) {
+ return field.isAnnotationPresent(Config.class);
+ }
+
+ public static boolean isConfiguredMethod(Method method) {
+ return method.isAnnotationPresent(Config.class);
+ }
+
+ @Override
+ public Class getType() {
+ return this.type;
+ }
+
+ @Override
+ public String getName() {
+ return this.type.getName();
+ }
+
+ /**
+ * Get the registered configured fields.
+ * @return the registered configured fields, never null.
+ */
+ @Override
+ public Collection<ConfiguredField> getConfiguredFields(){
+ return configuredFields;
+ }
+
+ /**
+ * Get the registered annotated setter methods.
+ * @return the registered annotated setter methods, never null.
+ */
+ @Override
+ public Collection<ConfiguredMethod> getConfiguredMethods(){
+ return configuredSetterMethods;
+ }
+
+ @Override
+ public String toString() {
+ return "ConfigDefaultSections{"+ this.getType().getName() + '}';
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/fe7cd8f1/modules/injection/standalone/src/main/java/org/apache/tamaya/inject/internal/DefaultConfigurationInjector.java
----------------------------------------------------------------------
diff --git a/modules/injection/standalone/src/main/java/org/apache/tamaya/inject/internal/DefaultConfigurationInjector.java b/modules/injection/standalone/src/main/java/org/apache/tamaya/inject/internal/DefaultConfigurationInjector.java
new file mode 100644
index 0000000..a3a7015
--- /dev/null
+++ b/modules/injection/standalone/src/main/java/org/apache/tamaya/inject/internal/DefaultConfigurationInjector.java
@@ -0,0 +1,179 @@
+/*
+ * 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.inject.internal;
+
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.ConfigurationProvider;
+import org.apache.tamaya.inject.ConfigurationInjector;
+
+import javax.annotation.Priority;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.logging.Logger;
+
+import org.apache.tamaya.inject.api.ConfiguredItemSupplier;
+import org.apache.tamaya.inject.api.NoConfig;
+import org.apache.tamaya.inject.api.Config;
+import org.apache.tamaya.inject.api.ConfigDefaultSections;
+import org.apache.tamaya.inject.spi.ConfiguredType;
+
+/**
+ * Simple injector singleton that also registers instances configured using weak references.
+ */
+@Priority(0)
+public final class DefaultConfigurationInjector implements ConfigurationInjector {
+
+ private final Map<Class<?>, ConfiguredType> configuredTypes = new ConcurrentHashMap<>();
+
+ private static final Logger LOG = Logger.getLogger(DefaultConfigurationInjector.class.getName());
+
+ private boolean autoConfigureEnabled = true;
+
+ /**
+ * 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 ConfiguredType registerType(Class<?> type) {
+ ConfiguredType confType = configuredTypes.get(type);
+ if (confType == null) {
+ if(!isConfigAnnotated(type) && !autoConfigureEnabled){
+ return null;
+ }
+ confType = new ConfiguredTypeImpl(type);
+ configuredTypes.put(type, confType);
+ InjectionHelper.sendConfigurationEvent(confType);
+ }
+ return confType;
+ }
+
+ /**
+ * If set also non annotated instances can be configured or created as templates.
+ * @return true, if autoConfigureEnabled.
+ */
+ public boolean isAutoConfigureEnabled(){
+ return autoConfigureEnabled;
+ }
+
+ /**
+ * Setting to true enables also configuration/templating of non annotated classes or
+ * interfaces.
+ * @param enabled true enables also configuration/templating of
+ */
+ public void setAutoConfigureEnabled(boolean enabled){
+ this.autoConfigureEnabled = enabled;
+ }
+
+ /**
+ * CHecks if type is eligible for configuration injection.
+ * @param type the target type, not null.
+ * @return true, if the type, a method or field has Tamaya config annotation on it.
+ */
+ private boolean isConfigAnnotated(Class<?> type) {
+ if(type.getClass().isAnnotationPresent(ConfigDefaultSections.class)){
+ return true;
+ }
+ for (Field f : type.getDeclaredFields()) {
+ if (f.isAnnotationPresent(NoConfig.class) || f.isAnnotationPresent(Config.class)) {
+ return true;
+ }
+ }
+ for (Method m : type.getDeclaredMethods()) {
+ if (m.isAnnotationPresent(NoConfig.class) || m.isAnnotationPresent(Config.class)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * 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
+ */
+ @Override
+ public <T> T configure(T instance) {
+ return configure(instance, ConfigurationProvider.getConfiguration());
+ }
+
+ /**
+ * 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 config the target configuration, not null.
+ */
+ @Override
+ public <T> T configure(T instance, Configuration config) {
+ Class<?> type = Objects.requireNonNull(instance).getClass();
+ ConfiguredType configuredType = registerType(type);
+ if(configuredType!=null){
+ configuredType.configure(instance, config);
+ }else{
+ LOG.info("Instance passed is not configurable: " + instance);
+ }
+ return instance;
+ }
+
+ /**
+ * Create a template implementting the annotated methods based on current configuration data.
+ *
+ * @param templateType the type of the template to be created.
+ */
+ @Override
+ public <T> T createTemplate(Class<T> templateType) {
+ return createTemplate(templateType, ConfigurationProvider.getConfiguration());
+ }
+
+ /**
+ * Create a template implementting the annotated methods based on current configuration data.
+ *
+ * @param templateType the type of the template to be created.
+ * @param config the target configuration, not null.
+ */
+ @Override
+ public <T> T createTemplate(Class<T> templateType, Configuration config) {
+ ClassLoader cl = Thread.currentThread().getContextClassLoader();
+ if(cl==null){
+ cl = this.getClass().getClassLoader();
+ }
+ return templateType.cast(Proxy.newProxyInstance(cl, new Class[]{ConfiguredItemSupplier.class, Objects.requireNonNull(templateType)},
+ new ConfigTemplateInvocationHandler(templateType)));
+ }
+
+ @Override
+ public <T> ConfiguredItemSupplier<T> getConfiguredSupplier(final ConfiguredItemSupplier<T> supplier) {
+ return getConfiguredSupplier(supplier, ConfigurationProvider.getConfiguration());
+ }
+
+ @Override
+ public <T> ConfiguredItemSupplier<T> getConfiguredSupplier(final ConfiguredItemSupplier<T> supplier, final Configuration config) {
+ return new ConfiguredItemSupplier<T>() {
+ public T get() {
+ return configure(supplier.get(), config);
+ }
+ };
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/fe7cd8f1/modules/injection/standalone/src/main/java/org/apache/tamaya/inject/internal/DefaultDynamicValue.java
----------------------------------------------------------------------
diff --git a/modules/injection/standalone/src/main/java/org/apache/tamaya/inject/internal/DefaultDynamicValue.java b/modules/injection/standalone/src/main/java/org/apache/tamaya/inject/internal/DefaultDynamicValue.java
new file mode 100644
index 0000000..2f051b3
--- /dev/null
+++ b/modules/injection/standalone/src/main/java/org/apache/tamaya/inject/internal/DefaultDynamicValue.java
@@ -0,0 +1,498 @@
+/*
+ * 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.inject.internal;
+
+import org.apache.tamaya.ConfigException;
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.TypeLiteral;
+import org.apache.tamaya.inject.api.BaseDynamicValue;
+import org.apache.tamaya.inject.api.DynamicValue;
+import org.apache.tamaya.inject.api.InjectionUtils;
+import org.apache.tamaya.inject.api.LoadPolicy;
+import org.apache.tamaya.inject.api.UpdatePolicy;
+import org.apache.tamaya.inject.api.WithPropertyConverter;
+import org.apache.tamaya.spi.ConversionContext;
+import org.apache.tamaya.spi.PropertyConverter;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Objects;
+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 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>
+ *
+ * @param <T> The type of the value.
+ */
+final class DefaultDynamicValue<T> extends BaseDynamicValue<T> {
+
+ private static final long serialVersionUID = -2071172847144537443L;
+
+ /**
+ * The property name of the entry.
+ */
+ private final String propertyName;
+ /**
+ * The keys to be resolved.
+ */
+ private final String[] keys;
+ /**
+ * Back reference to the base configuration instance. This reference is used reevalaute the given property and
+ * compare the result with the previous value after a configuration change was triggered.
+ */
+ private final Configuration configuration;
+ /**
+ * The target type of the property used to lookup a matching {@link PropertyConverter}.
+ * If null, {@code propertyConverter} is set and used instead.
+ */
+ private final TypeLiteral<T> targetType;
+ /**
+ * The property converter to be applied, may be null. In the ladder case targetType is not null.
+ */
+ private final PropertyConverter<T> propertyConverter;
+ /**
+ * Policy that defines how new values are applied, be default it is applied initially once, but never updated
+ * anymore.
+ */
+ private UpdatePolicy updatePolicy;
+ /**
+ * Load policy.
+ */
+ private final LoadPolicy loadPolicy;
+
+ /**
+ * The current value, never null.
+ */
+ private transient T value;
+ /**
+ * The new value, or null.
+ */
+ private transient Object[] newValue;
+ /**
+ * List of listeners that listen for changes.
+ */
+ private transient WeakList<PropertyChangeListener> listeners;
+
+ /**
+ * Constructor.
+ *
+ * @param propertyName the name of the fields' property/method.
+ * @param keys the keys of the property, not null.
+ * @param configuration the configuration, not null.
+ * @param targetType the target type, not null.
+ * @param propertyConverter the optional converter to be used.
+ */
+ private DefaultDynamicValue(String propertyName, Configuration configuration, TypeLiteral<T> targetType,
+ PropertyConverter<T> propertyConverter, List<String> keys, LoadPolicy loadPolicy,
+ UpdatePolicy updatePolicy) {
+ this.propertyName = Objects.requireNonNull(propertyName);
+ this.keys = keys.toArray(new String[keys.size()]);
+ this.configuration = Objects.requireNonNull(configuration);
+ this.propertyConverter = propertyConverter;
+ this.targetType = targetType;
+ this.loadPolicy = Objects.requireNonNull(loadPolicy);
+ this.updatePolicy = Objects.requireNonNull(updatePolicy);
+ if(loadPolicy == LoadPolicy.INITIAL){
+ this.value = evaluateValue();
+ }
+ }
+
+ public static DynamicValue of(Field annotatedField, Configuration configuration) {
+ return of(annotatedField, configuration, LoadPolicy.ALWAYS, UpdatePolicy.IMMEDEATE);
+ }
+
+ public static DynamicValue of(Field annotatedField, Configuration configuration, LoadPolicy loadPolicy) {
+ return of(annotatedField, configuration, loadPolicy, UpdatePolicy.IMMEDEATE);
+ }
+
+ public static DynamicValue of(Field annotatedField, Configuration configuration, UpdatePolicy updatePolicy) {
+ return of(annotatedField, configuration, LoadPolicy.ALWAYS, updatePolicy);
+ }
+
+ public static DynamicValue of(Field annotatedField, Configuration configuration, LoadPolicy loadPolicy, UpdatePolicy updatePolicy) {
+ // Check for adapter/filter
+ Type targetType = annotatedField.getGenericType();
+ if (targetType == null) {
+ throw new ConfigException("Failed to evaluate target type for " + annotatedField.getDeclaringClass().getName()
+ + '.' + annotatedField.getName());
+ }
+ if (targetType instanceof ParameterizedType) {
+ ParameterizedType pt = (ParameterizedType) targetType;
+ Type[] types = pt.getActualTypeArguments();
+ if (types.length != 1) {
+ throw new ConfigException("Failed to evaluate target type for " + annotatedField.getDeclaringClass().getName()
+ + '.' + annotatedField.getName());
+ }
+ targetType = types[0];
+ }
+ PropertyConverter<?> propertyConverter = null;
+ WithPropertyConverter annot = annotatedField.getAnnotation(WithPropertyConverter.class);
+ if (annot != null) {
+ try {
+ propertyConverter = annot.value().newInstance();
+ } catch (Exception e) {
+ throw new ConfigException("Failed to instantiate annotated PropertyConverter on " +
+ annotatedField.getDeclaringClass().getName()
+ + '.' + annotatedField.getName(), e);
+ }
+ }
+ List<String> keys = InjectionUtils.getKeys(annotatedField);
+ return new DefaultDynamicValue(annotatedField.getName(), configuration,
+ TypeLiteral.of(targetType), propertyConverter, keys, loadPolicy, updatePolicy);
+ }
+
+ public static DynamicValue of(Method method, Configuration configuration) {
+ return of(method, configuration, LoadPolicy.ALWAYS, UpdatePolicy.IMMEDEATE);
+ }
+
+ public static DynamicValue of(Method method, Configuration configuration, UpdatePolicy updatePolicy) {
+ return of(method, configuration, LoadPolicy.ALWAYS, updatePolicy);
+ }
+
+ public static DynamicValue of(Method method, Configuration configuration, LoadPolicy loadPolicy) {
+ return of(method, configuration, loadPolicy, UpdatePolicy.IMMEDEATE);
+ }
+
+ public static DynamicValue of(Method method, Configuration configuration, LoadPolicy loadPolicy, UpdatePolicy updatePolicy) {
+ // Check for adapter/filter
+ Type targetType = method.getGenericReturnType();
+ if (targetType == null) {
+ throw new ConfigException("Failed to evaluate target type for " + method.getDeclaringClass()
+ .getName() + '.' + method.getName());
+ }
+ if (targetType instanceof ParameterizedType) {
+ ParameterizedType pt = (ParameterizedType) targetType;
+ Type[] types = pt.getActualTypeArguments();
+ if (types.length != 1) {
+ throw new ConfigException("Failed to evaluate target type for " + method.getDeclaringClass()
+ .getName() + '.' + method.getName());
+ }
+ targetType = types[0];
+ }
+ PropertyConverter<Object> propertyConverter = null;
+ WithPropertyConverter annot = method.getAnnotation(WithPropertyConverter.class);
+ if (annot != null) {
+ try {
+ propertyConverter = (PropertyConverter<Object>) annot.value().newInstance();
+ } catch (Exception e) {
+ throw new ConfigException("Failed to instantiate annotated PropertyConverter on " +
+ method.getDeclaringClass().getName()
+ + '.' + method.getName(), e);
+ }
+ }
+ return new DefaultDynamicValue<>(method.getName(),
+ configuration, TypeLiteral.of(targetType), propertyConverter, InjectionUtils.getKeys(method),
+ loadPolicy, updatePolicy);
+ }
+
+
+ /**
+ * 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() {
+ T oldValue = value;
+ value = newValue==null?null:(T)newValue[0];
+ newValue = null;
+ informListeners(oldValue, value);
+ }
+
+ private void informListeners(T value, T newValue) {
+ synchronized (this) {
+ PropertyChangeEvent evt = new PropertyChangeEvent(this, propertyName, value,
+ newValue);
+ if (listeners != null) {
+ for (PropertyChangeListener consumer : listeners.get()) {
+ consumer.propertyChange(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;
+ }
+
+ /**
+ * Sets a new {@link UpdatePolicy}.
+ *
+ * @param updatePolicy the new policy, not null.
+ */
+ public void setUpdatePolicy(UpdatePolicy updatePolicy) {
+ this.updatePolicy = Objects.requireNonNull(updatePolicy);
+ }
+
+ /**
+ * Add a listener to be called as weak reference, when this value has been changed.
+ *
+ * @param l the listener, not null
+ */
+ public void addListener(PropertyChangeListener 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(PropertyChangeListener l) {
+ if (listeners != null) {
+ listeners.remove(l);
+ }
+ }
+
+ /**
+ * If a value is present in this {@code DynamicValue}, returns the value,
+ * otherwise throws {@code ConfigException}.
+ *
+ * @return the non-null value held by this {@code Optional}
+ * @throws ConfigException if there is no value present
+ * @see DefaultDynamicValue#isPresent()
+ */
+ public T get() {
+ T newLocalValue;
+ if(loadPolicy!=LoadPolicy.INITIAL) {
+ newLocalValue = evaluateValue();
+ if (this.value == null) {
+ this.value = newLocalValue;
+ }
+ if(!Objects.equals(this.value, newLocalValue)){
+ switch (updatePolicy){
+ case IMMEDEATE:
+ commit();
+ break;
+ case EXPLCIT:
+ this.newValue = new Object[]{newLocalValue};
+ break;
+ case LOG_ONLY:
+ informListeners(this.value, newLocalValue);
+ this.newValue = null;
+ break;
+ case NEVER:
+ this.newValue = null;
+ break;
+ default:
+ this.newValue = null;
+ break;
+ }
+ }
+ }
+ return value;
+ }
+
+ /**
+ * Method to check for and apply a new value. Depending on the {@link UpdatePolicy}
+ * the value is immediately or deferred visible (or it may even be ignored completely).
+ *
+ * @return true, if a new value has been detected. The value may not be visible depending on the current
+ * {@link UpdatePolicy} in place.
+ */
+ public boolean updateValue() {
+ if(this.value==null && this.newValue==null){
+ this.value = evaluateValue();
+ return false;
+ }
+ T newValue = evaluateValue();
+ if (Objects.equals(newValue, this.value)) {
+ return false;
+ }
+ switch (this.updatePolicy) {
+ case LOG_ONLY:
+ Logger.getLogger(getClass().getName()).info("Discard change on " + this + ", newValue=" + newValue);
+ informListeners(value, newValue);
+ this.newValue = null;
+ break;
+ case NEVER:
+ this.newValue = null;
+ break;
+ case EXPLCIT:
+ case IMMEDEATE:
+ default:
+ this.newValue = new Object[]{newValue};
+ commit();
+ break;
+ }
+ return true;
+ }
+
+ /**
+ * Evaluates the current value dynamically from the underlying configuration.
+ *
+ * @return the current actual value, or null.
+ */
+ public T evaluateValue() {
+ T value = null;
+
+ for (String key : keys) {
+ ConversionContext ctx = new ConversionContext.Builder(key, targetType).build();
+ if (propertyConverter == null) {
+ value = configuration.get(key, targetType);
+ } else {
+ String source = configuration.get(key);
+ value = propertyConverter.convert(source, ctx);
+ }
+
+ if (value != null) {
+ break;
+ }
+ }
+
+ return value;
+ }
+
+ /**
+ * Access a new value that has not yet been committed.
+ *
+ * @return the uncommitted new value, or null.
+ */
+ public T getNewValue() {
+ T nv = newValue==null?null:(T)newValue[0];
+ if (nv != null) {
+ return nv;
+ }
+ return null;
+ }
+
+
+ /**
+ * 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(getUpdatePolicy());
+ oos.writeObject(get());
+ }
+
+ /**
+ * 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 = (T) ois.readObject();
+ }
+ newValue = null;
+ }
+
+
+ /**
+ * Simple helper that allows keeping the listeners registered as weak references, hereby avoiding any
+ * memory leaks.
+ *
+ * @param <I> the type
+ */
+ private class WeakList<I> {
+ final List<WeakReference<I>> refs = new LinkedList<>();
+
+ /**
+ * Adds a new instance.
+ *
+ * @param t the new instance, not null.
+ */
+ void add(I t) {
+ refs.add(new WeakReference<>(t));
+ }
+
+ /**
+ * Removes a instance.
+ *
+ * @param t the instance to be removed.
+ */
+ void remove(I t) {
+ synchronized (refs) {
+ for (Iterator<WeakReference<I>> iterator = refs.iterator(); iterator.hasNext(); ) {
+ WeakReference<I> ref = iterator.next();
+ I 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<I> get() {
+ synchronized (refs) {
+ List<I> res = new ArrayList<>();
+ for (Iterator<WeakReference<I>> iterator = refs.iterator(); iterator.hasNext(); ) {
+ WeakReference<I> ref = iterator.next();
+ I instance = ref.get();
+ if (instance == null) {
+ iterator.remove();
+ } else {
+ res.add(instance);
+ }
+ }
+ return res;
+ }
+ }
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/fe7cd8f1/modules/injection/standalone/src/main/java/org/apache/tamaya/inject/internal/InjectionHelper.java
----------------------------------------------------------------------
diff --git a/modules/injection/standalone/src/main/java/org/apache/tamaya/inject/internal/InjectionHelper.java b/modules/injection/standalone/src/main/java/org/apache/tamaya/inject/internal/InjectionHelper.java
new file mode 100644
index 0000000..305a660
--- /dev/null
+++ b/modules/injection/standalone/src/main/java/org/apache/tamaya/inject/internal/InjectionHelper.java
@@ -0,0 +1,244 @@
+/*
+ * 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.inject.internal;
+
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.apache.tamaya.ConfigException;
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.ConfigurationProvider;
+import org.apache.tamaya.TypeLiteral;
+import org.apache.tamaya.events.ConfigEventManager;
+import org.apache.tamaya.events.spi.BaseConfigEvent;
+import org.apache.tamaya.inject.api.Config;
+import org.apache.tamaya.inject.api.ConfigDefaultSections;
+import org.apache.tamaya.inject.api.InjectionUtils;
+import org.apache.tamaya.inject.api.WithPropertyConverter;
+import org.apache.tamaya.inject.spi.ConfiguredType;
+import org.apache.tamaya.resolver.spi.ExpressionEvaluator;
+import org.apache.tamaya.spi.ConfigurationContext;
+import org.apache.tamaya.spi.ConversionContext;
+import org.apache.tamaya.spi.PropertyConverter;
+import org.apache.tamaya.spi.ServiceContextManager;
+
+
+/**
+ * Utility class containing several aspects used in this module.
+ */
+@SuppressWarnings("unchecked")
+final class InjectionHelper {
+
+ private static final Logger LOG = Logger.getLogger(InjectionHelper.class.getName());
+
+ private static final boolean RESOLUTION_MODULE_LOADED = checkResolutionModuleLoaded();
+
+ private static final boolean EVENTS_AVAILABLE = checkForEvents();
+
+ private static boolean checkForEvents() {
+ try{
+ Class.forName("org.apache.tamaya.events.FrozenConfiguration");
+ LOG.info("Detected tamaya-events is loaded, will trigger ConfigEvents...");
+ return true;
+ } catch(Exception e){
+ LOG.info("Detected tamaya-events not found, will not trigger any ConfigEvents...");
+ return false;
+ }
+ }
+
+ private static boolean checkResolutionModuleLoaded() {
+ try {
+ Class.forName("org.apache.tamaya.resolver.internal.DefaultExpressionEvaluator");
+ return true;
+ } catch (ClassNotFoundException e) {
+ return false;
+ }
+ }
+
+ private InjectionHelper() {
+ }
+
+ /**
+ * Internally evaluated the current valid configuration keys based on the given annotations present.
+ * @param method the method
+ * @return the keys to be returned, or null.
+ */
+ public static String getConfigValue(Method method, Configuration config) {
+ return getConfigValue(method, null, config);
+ }
+
+ /**
+ * Internally evaluated the current valid configuration keys based on the given annotations present.
+ * @param method the method
+ * @param retKey the array to return the key found, or null.
+ * @return the keys to be returned, or null.
+ */
+ public static String getConfigValue(Method method, String[] retKey, Configuration config) {
+ ConfigDefaultSections areasAnnot = method.getDeclaringClass().getAnnotation(ConfigDefaultSections.class);
+ return getConfigValueInternal(method, areasAnnot, retKey, config);
+ }
+
+ /**
+ * Internally evaluated the current valid configuration keys based on the given annotations present.
+ * @param field the field
+ * @return the keys to be returned, or null.
+ */
+ public static String getConfigValue(Field field, Configuration config) {
+ return getConfigValue(field, null, config);
+ }
+
+ /**
+ * Internally evaluated the current valid configuration keys based on the given annotations present.
+ * @param field the field
+ * @param retKey the array to return the key found, or null.
+ * @return the keys to be returned, or null.
+ */
+ public static String getConfigValue(Field field, String[] retKey, Configuration config) {
+ ConfigDefaultSections areasAnnot = field.getDeclaringClass().getAnnotation(ConfigDefaultSections.class);
+ return getConfigValueInternal(field, areasAnnot, retKey, config);
+ }
+
+ /**
+ * Internally evaluated the current valid configuration keys based on the given annotations present.
+ *
+ * @return the keys to be returned, or null.
+ */
+ private static String getConfigValueInternal(AnnotatedElement element, ConfigDefaultSections areasAnnot, String[] retKey, Configuration config) {
+ Config prop = element.getAnnotation(Config.class);
+ List<String> keys;
+ if (prop == null) {
+ keys = InjectionUtils.evaluateKeys((Member) element, areasAnnot);
+ } else {
+ keys = InjectionUtils.evaluateKeys((Member) element, areasAnnot, prop);
+ }
+ String configValue = evaluteConfigValue(keys, retKey, config);
+ if (configValue == null) {
+ if(prop==null || prop.defaultValue().isEmpty()){
+ return null;
+ }
+ return prop.defaultValue();
+ }
+ return configValue;
+ }
+
+
+ private static String evaluteConfigValue(List<String> keys, String[] retKey, Configuration config) {
+ String configValue = null;
+ for (String key : keys) {
+ configValue = config.get(key);
+ if (configValue != null) {
+ if(retKey!=null && retKey.length>0){
+ retKey[0] = key;
+ }
+ break;
+ }
+ }
+ return configValue;
+ }
+
+
+ @SuppressWarnings("rawtypes")
+ public static <T> T adaptValue(AnnotatedElement element, TypeLiteral<T> targetType, String key, String configValue) {
+ // Check for adapter/filter
+ T adaptedValue = null;
+ WithPropertyConverter converterAnnot = element.getAnnotation(WithPropertyConverter.class);
+ Class<? extends PropertyConverter<T>> converterType;
+ if (converterAnnot != null) {
+ converterType = (Class<? extends PropertyConverter<T>>) converterAnnot.value();
+ if (!converterType.getName().equals(WithPropertyConverter.class.getName())) {
+ try {
+ // TODO cache here...
+ ConversionContext ctx = new ConversionContext.Builder(key,targetType)
+ .setAnnotatedElement(element).build();
+
+ PropertyConverter<T> converter = PropertyConverter.class.cast(converterType.newInstance());
+ adaptedValue = converter.convert(configValue, ctx);
+ } catch (Exception e) {
+ LOG.log(Level.SEVERE, "Failed to convert using explicit PropertyConverter on " + element +
+ ", trying default conversion.", e);
+ }
+ }
+ }
+ if (adaptedValue != null) {
+ return adaptedValue;
+ }
+ if (String.class == targetType.getType()) {
+ return (T) configValue;
+ } else{
+ if(configValue==null) {
+ return null;
+ }
+ ConfigurationContext configContext = ConfigurationProvider.getConfiguration().getContext();
+ List<PropertyConverter<T>> converters = configContext
+ .getPropertyConverters(targetType);
+ ConversionContext ctx = new ConversionContext.Builder(ConfigurationProvider.getConfiguration(),
+ configContext, key, targetType).setAnnotatedElement(element).build();
+ for (PropertyConverter<T> converter : converters) {
+ adaptedValue = converter.convert(configValue, ctx);
+ if (adaptedValue != null) {
+ return adaptedValue;
+ }
+ }
+ }
+ throw new ConfigException("Non convertible property type: " + element);
+ }
+
+ /**
+ * Method that allows to statically check, if the resolver module is loaded. If the module is loaded
+ * value expressions are automatically forwarded to the resolver module for resolution.
+ *
+ * @return true, if the resolver module is on the classpath.
+ */
+ public static boolean isResolutionModuleLoaded() {
+ return RESOLUTION_MODULE_LOADED;
+ }
+
+ /**
+ * Evaluates the given expression.
+ *
+ * @param expression the expression, not null.
+ * @return the evaluated expression.
+ */
+ public static String evaluateValue(String expression) {
+ if (!RESOLUTION_MODULE_LOADED) {
+ return expression;
+ }
+ ExpressionEvaluator evaluator = ServiceContextManager.getServiceContext().getService(ExpressionEvaluator.class);
+ if (evaluator != null) {
+ return evaluator.evaluateExpression("<injection>", expression, true);
+ }
+ return expression;
+ }
+
+ /**
+ * This method distributes the configuration event, if the Tamaya event module is accessible.
+ * When Tamaya events are not available, the call simply returns.
+ * @param event the event to be distributed, not null.
+ */
+ static void sendConfigurationEvent(ConfiguredType event) {
+ if(EVENTS_AVAILABLE){
+ ConfigEventManager.fireEvent(new BaseConfigEvent<ConfiguredType>(event, ConfiguredType.class) {});
+ }
+ }
+}