http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/7917a9f3/code/core/src/test/java/org/apache/tamaya/core/propertysource/CLIPropertySourceTest.java ---------------------------------------------------------------------- diff --git a/code/core/src/test/java/org/apache/tamaya/core/propertysource/CLIPropertySourceTest.java b/code/core/src/test/java/org/apache/tamaya/core/propertysource/CLIPropertySourceTest.java deleted file mode 100644 index bd6468b..0000000 --- a/code/core/src/test/java/org/apache/tamaya/core/propertysource/CLIPropertySourceTest.java +++ /dev/null @@ -1,58 +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.core.propertysource; - -import org.junit.Test; - -import static org.junit.Assert.*; - -/** - * Tests for PropertySource for reading main arguments as configuration. - */ -public class CLIPropertySourceTest { - - @Test - public void setCLIProps() throws Exception { - System.clearProperty("main.args"); - CLIPropertySource ps = new CLIPropertySource(); - assertTrue(ps.getProperties().isEmpty()); - CLIPropertySource.initMainArgs("-a", "b"); - assertFalse(ps.getProperties().isEmpty()); - assertEquals(ps.getProperties().get("a").getValue(), "b"); - CLIPropertySource.initMainArgs("--c"); - assertFalse(ps.getProperties().isEmpty()); - assertEquals(ps.getProperties().get("c").getValue(), "c"); - CLIPropertySource.initMainArgs("sss"); - assertFalse(ps.getProperties().isEmpty()); - assertEquals("sss", ps.getProperties().get("sss").getValue()); - CLIPropertySource.initMainArgs("-a", "b", "--c", "sss", "--val=vvv"); - assertFalse(ps.getProperties().isEmpty()); - assertEquals("b", ps.getProperties().get("a").getValue()); - assertEquals("c", ps.getProperties().get("c").getValue()); - assertEquals("sss", ps.getProperties().get("sss").getValue()); - // getProperties() throws Exception { - System.setProperty("main.args", "-a b\t--c sss "); - ps = new CLIPropertySource(); - assertFalse(ps.getProperties().isEmpty()); - System.clearProperty("main.args"); - assertEquals("b", ps.getProperties().get("a").getValue()); - assertEquals("c", ps.getProperties().get("c").getValue()); - assertEquals("sss", ps.getProperties().get("sss").getValue()); - } -} \ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/7917a9f3/code/core/src/test/java/org/apache/tamaya/core/propertysource/EnvironmentPropertySourceTest.java ---------------------------------------------------------------------- diff --git a/code/core/src/test/java/org/apache/tamaya/core/propertysource/EnvironmentPropertySourceTest.java b/code/core/src/test/java/org/apache/tamaya/core/propertysource/EnvironmentPropertySourceTest.java deleted file mode 100644 index 477ffb2..0000000 --- a/code/core/src/test/java/org/apache/tamaya/core/propertysource/EnvironmentPropertySourceTest.java +++ /dev/null @@ -1,180 +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.core.propertysource; - -import org.apache.tamaya.spi.PropertyValue; -import org.junit.Before; -import org.junit.Test; - -import java.util.HashMap; -import java.util.Map; - -import static java.lang.Boolean.TRUE; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -/** - * Tests for {@link org.apache.tamaya.core.propertysource.EnvironmentPropertySource}. - */ -public class EnvironmentPropertySourceTest { - private EnvironmentPropertySource envPropertySource; - - @Before - public void setOUT() { - envPropertySource = new EnvironmentPropertySource(); - } - - @Test - public void testGetOrdinal() throws Exception { - assertEquals(EnvironmentPropertySource.DEFAULT_ORDINAL, envPropertySource.getOrdinal()); - } - - @Test - public void testGetName() throws Exception { - assertEquals("environment-properties", envPropertySource.getName()); - } - - @Test - public void testGet() throws Exception { - for (Map.Entry<String, String> envEntry : System.getenv().entrySet()) { - assertEquals(envPropertySource.get(envEntry.getKey()).getValue(), envEntry.getValue()); - } - } - - @Test - public void testGetProperties() throws Exception { - Map<String, PropertyValue> props = envPropertySource.getProperties(); - for(Map.Entry<String,PropertyValue> en: props.entrySet()){ - if(!en.getKey().startsWith("_")){ - assertEquals(System.getenv(en.getKey()), en.getValue().getValue()); - } - } - } - - @Test - public void testIsScannable() throws Exception { - assertTrue(envPropertySource.isScannable()); - } - - @Test - public void ifPrefixHasBeenConfiguredLookedUpEnvVarNameIsPrefixAndKeyName() { - EnvironmentPropertySource.SystemPropertiesProvider provider = - mock(EnvironmentPropertySource.SystemPropertiesProvider.class); - - when(provider.getEnvPropsPrefix()).thenReturn("zzz"); - when(provider.getenv("zzz.VARIABLE")).thenReturn("value"); - - envPropertySource.setPropertiesProvider(provider); - - assertThat(envPropertySource.get("VARIABLE").getValue()).isEqualTo("value"); - } - - @Test - public void ifPrefixHasNotBeenConfiguredLookedUpEnvVarNameIsKeyName() { - EnvironmentPropertySource.SystemPropertiesProvider provider = - mock(EnvironmentPropertySource.SystemPropertiesProvider.class); - - when(provider.getEnvPropsPrefix()).thenReturn(null); - when(provider.getenv("VARIABLE")).thenReturn("value"); - - envPropertySource.setPropertiesProvider(provider); - - assertThat(envPropertySource.get("VARIABLE").getValue()).isEqualTo("value"); - } - - @Test - public void ifPrefixHasBeenSetAllEnvVarsWithPrefixWillBeReturnedByGetProperties() { - EnvironmentPropertySource.SystemPropertiesProvider provider = - mock(EnvironmentPropertySource.SystemPropertiesProvider.class); - - when(provider.getEnvPropsPrefix()).thenReturn("zzz"); - HashMap<String, String> configuredValues = new HashMap<String, String>(); - configuredValues.put("zzz.A", "aaa"); - configuredValues.put("zzz.B", "bbb"); - configuredValues.put("C", "ccc"); - configuredValues.put("D", "ddd"); - - when(provider.getenv()).thenReturn(configuredValues); - - envPropertySource.setPropertiesProvider(provider); - - assertThat(envPropertySource.getProperties()).hasSize(2); - - Map<String, PropertyValue> properties = envPropertySource.getProperties(); - - assertThat(properties.keySet()).containsOnly("A", "B"); - assertThat(properties.get("A").getValue()).isEqualTo("aaa"); - assertThat(properties.get("B").getValue()).isEqualTo("bbb"); - } - - @Test - public void canBeDisableBySystemPropertyTamayaDefaultsDisable() { - EnvironmentPropertySource.SystemPropertiesProvider provider = - mock(EnvironmentPropertySource.SystemPropertiesProvider.class); - - when(provider.getDefaultsDisable()).thenReturn(TRUE.toString()); - when(provider.getenv("VARIABLE")).thenReturn("value"); - - envPropertySource.setPropertiesProvider(provider); - - assertThat(envPropertySource.get("VARIABLE")).isNull(); - } - - @Test - public void canBeDisableBySystemPropertyTamayaEnvpropsDisable() { - EnvironmentPropertySource.SystemPropertiesProvider provider = - mock(EnvironmentPropertySource.SystemPropertiesProvider.class); - - when(provider.getEnvPropsDisable()).thenReturn(TRUE.toString()); - when(provider.getenv("VARIABLE")).thenReturn("value"); - - envPropertySource.setPropertiesProvider(provider); - - assertThat(envPropertySource.get("VARIABLE")).isNull(); - } - - @Test - public void isDisabledIfEvenIsDefaultsDisableIsFalse() throws Exception { - EnvironmentPropertySource.SystemPropertiesProvider provider = - mock(EnvironmentPropertySource.SystemPropertiesProvider.class); - - when(provider.getDefaultsDisable()).thenReturn("false"); - when(provider.getEnvPropsDisable()).thenReturn("true"); - - envPropertySource.setPropertiesProvider(provider); - - assertThat(envPropertySource.isDisabled()).isTrue(); - } - - @Test - public void isDisabledIfEvenIsEnvPropsDisableIsFalse() throws Exception { - EnvironmentPropertySource.SystemPropertiesProvider provider = - mock(EnvironmentPropertySource.SystemPropertiesProvider.class); - - when(provider.getDefaultsDisable()).thenReturn("true"); - when(provider.getEnvPropsDisable()).thenReturn("false"); - - envPropertySource.setPropertiesProvider(provider); - - assertThat(envPropertySource.isDisabled()).isTrue(); - } -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/7917a9f3/code/core/src/test/java/org/apache/tamaya/core/propertysource/PropertiesFilePropertySourceTest.java ---------------------------------------------------------------------- diff --git a/code/core/src/test/java/org/apache/tamaya/core/propertysource/PropertiesFilePropertySourceTest.java b/code/core/src/test/java/org/apache/tamaya/core/propertysource/PropertiesFilePropertySourceTest.java deleted file mode 100644 index d11b48e..0000000 --- a/code/core/src/test/java/org/apache/tamaya/core/propertysource/PropertiesFilePropertySourceTest.java +++ /dev/null @@ -1,59 +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.core.propertysource; - -import org.apache.tamaya.spi.PropertySource; -import org.junit.Assert; -import org.junit.Test; - -public class PropertiesFilePropertySourceTest { - - private final SimplePropertySource testfilePropertySource = new SimplePropertySource(Thread.currentThread() - .getContextClassLoader().getResource("testfile.properties")); - private final SimplePropertySource overrideOrdinalPropertySource = new SimplePropertySource( - Thread.currentThread().getContextClassLoader().getResource("overrideOrdinal.properties")); - - - @Test - public void testGetOrdinal() { - Assert.assertEquals(0, testfilePropertySource.getOrdinal()); - Assert.assertEquals(Integer.parseInt(overrideOrdinalPropertySource.get(PropertySource.TAMAYA_ORDINAL) - .getValue()), - overrideOrdinalPropertySource.getOrdinal()); - } - - - @Test - public void testGet() { - Assert.assertEquals("val3", testfilePropertySource.get("key3").getValue()); - Assert.assertEquals("myval5", overrideOrdinalPropertySource.get("mykey5").getValue()); - Assert.assertNull(testfilePropertySource.get("nonpresentkey")); - } - - - @Test - public void testGetProperties() throws Exception { - Assert.assertEquals(5, testfilePropertySource.getProperties().size()); // double the size for .source values. - Assert.assertTrue(testfilePropertySource.getProperties().containsKey("key1")); - Assert.assertTrue(testfilePropertySource.getProperties().containsKey("key2")); - Assert.assertTrue(testfilePropertySource.getProperties().containsKey("key3")); - Assert.assertTrue(testfilePropertySource.getProperties().containsKey("key4")); - Assert.assertTrue(testfilePropertySource.getProperties().containsKey("key5")); - } -} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/7917a9f3/code/core/src/test/java/org/apache/tamaya/core/propertysource/SimplePropertySourceTest.java ---------------------------------------------------------------------- diff --git a/code/core/src/test/java/org/apache/tamaya/core/propertysource/SimplePropertySourceTest.java b/code/core/src/test/java/org/apache/tamaya/core/propertysource/SimplePropertySourceTest.java deleted file mode 100644 index 2edc466..0000000 --- a/code/core/src/test/java/org/apache/tamaya/core/propertysource/SimplePropertySourceTest.java +++ /dev/null @@ -1,89 +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.core.propertysource; - -import org.apache.tamaya.ConfigException; -import org.apache.tamaya.spi.PropertyValue; -import org.junit.Test; - -import java.net.URL; - -import static org.hamcrest.CoreMatchers.allOf; -import static org.hamcrest.CoreMatchers.endsWith; -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.hamcrest.CoreMatchers.startsWith; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.aMapWithSize; -import static org.hamcrest.Matchers.hasEntry; - -public class SimplePropertySourceTest { - @Test - public void successfulCreationWithPropertiesFromXMLPropertiesFile() { - URL resource = getClass().getResource("/valid-properties.xml"); - - SimplePropertySource source = new SimplePropertySource(resource); - - assertThat(source, notNullValue()); - assertThat(source.getProperties(), aMapWithSize(2)); // double the size for .source values. - assertThat(source.getProperties(), hasEntry("a", PropertyValue.of("a", "b", resource.toString()))); - assertThat(source.getProperties(), hasEntry("b", PropertyValue.of("b", "1", resource.toString()))); - - } - - @Test - public void failsToCreateFromNonXMLPropertiesXMLFile() { - URL resource = getClass().getResource("/non-xml-properties.xml"); - ConfigException catchedException = null; - - try { - new SimplePropertySource(resource); - } catch (ConfigException ce) { - catchedException = ce; - } - - assertThat(catchedException.getMessage(), allOf(startsWith("Error loading properties from"), - endsWith("non-xml-properties.xml"))); - } - - @Test - public void failsToCreateFromInvalidPropertiesXMLFile() { - URL resource = getClass().getResource("/invalid-properties.xml"); - ConfigException catchedException = null; - - try { - new SimplePropertySource(resource); - } catch (ConfigException ce) { - catchedException = ce; - } - - assertThat(catchedException.getMessage(), allOf(startsWith("Error loading properties from"), - endsWith("invalid-properties.xml"))); - } - - - @Test - public void successfulCreationWithPropertiesFromSimplePropertiesFile() { - URL resource = getClass().getResource("/testfile.properties"); - - SimplePropertySource source = new SimplePropertySource(resource); - - assertThat(source, notNullValue()); - assertThat(source.getProperties(), aMapWithSize(5)); // double the size for .source values. - } -} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/7917a9f3/code/core/src/test/java/org/apache/tamaya/core/propertysource/SystemPropertySourceTest.java ---------------------------------------------------------------------- diff --git a/code/core/src/test/java/org/apache/tamaya/core/propertysource/SystemPropertySourceTest.java b/code/core/src/test/java/org/apache/tamaya/core/propertysource/SystemPropertySourceTest.java deleted file mode 100644 index 2b2b61e..0000000 --- a/code/core/src/test/java/org/apache/tamaya/core/propertysource/SystemPropertySourceTest.java +++ /dev/null @@ -1,91 +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.core.propertysource; - -import org.apache.tamaya.spi.PropertySource; -import org.apache.tamaya.spi.PropertyValue; -import org.junit.Assert; -import org.junit.Test; - -import java.util.Map; -import java.util.Properties; - -public class SystemPropertySourceTest { - - private final SystemPropertySource testPropertySource = new SystemPropertySource(); - - - @Test - public void testGetOrdinal() throws Exception { - - // test the default ordinal - Assert.assertEquals(SystemPropertySource.DEFAULT_ORDINAL, testPropertySource.getOrdinal()); - - // set the ordinal to 1001 - System.setProperty(PropertySource.TAMAYA_ORDINAL, "1001"); - Assert.assertEquals(1001, new SystemPropertySource().getOrdinal()); - // currently its not possible to change ordinal at runtime - - // reset it to not destroy other tests!! - System.clearProperty(PropertySource.TAMAYA_ORDINAL); - } - - @Test - public void testGetName() throws Exception { - Assert.assertEquals("system-properties", testPropertySource.getName()); - } - - @Test - public void testGet() throws Exception { - String propertyKeyToCheck = System.getProperties().stringPropertyNames().iterator().next(); - - PropertyValue property = testPropertySource.get(propertyKeyToCheck); - Assert.assertNotNull("Property '" + propertyKeyToCheck + "' is not present in " + - SystemPropertySource.class.getSimpleName(), property); - Assert.assertEquals(System.getProperty(propertyKeyToCheck), property.getValue()); - } - - @Test - public void testGetProperties() throws Exception { - checkWithSystemProperties(testPropertySource.getProperties()); - - // modify system properties - System.setProperty("test", "myTestVal"); - - checkWithSystemProperties(testPropertySource.getProperties()); - - // cleanup - System.clearProperty("test"); - } - - private void checkWithSystemProperties(Map<String,PropertyValue> toCheck) { - Properties systemEntries = System.getProperties(); - int num = 0; - for (PropertyValue propertySourceEntry : toCheck.values()) { - if(propertySourceEntry.getKey().startsWith("_")){ - continue; // meta entry - } - num ++; - Assert.assertEquals("Entry values for key '" + propertySourceEntry.getKey() + "' do not match", - systemEntries.getProperty(propertySourceEntry.getKey()), propertySourceEntry.getValue()); - } - Assert.assertEquals("size of System.getProperties().entrySet() must be the same as SystemPropertySrouce.getProperties().entrySet()", - systemEntries.size(), num); - } -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/7917a9f3/code/core/src/test/java/org/apache/tamaya/core/testdata/TestPropertyDefaultSource.java ---------------------------------------------------------------------- diff --git a/code/core/src/test/java/org/apache/tamaya/core/testdata/TestPropertyDefaultSource.java b/code/core/src/test/java/org/apache/tamaya/core/testdata/TestPropertyDefaultSource.java index 09d86f1..c315ff6 100644 --- a/code/core/src/test/java/org/apache/tamaya/core/testdata/TestPropertyDefaultSource.java +++ b/code/core/src/test/java/org/apache/tamaya/core/testdata/TestPropertyDefaultSource.java @@ -18,7 +18,7 @@ */ package org.apache.tamaya.core.testdata; -import org.apache.tamaya.core.propertysource.BasePropertySource; +import org.apache.tamaya.spisupport.propertysource.BasePropertySource; import org.apache.tamaya.spi.PropertyValue; import java.util.Collections; http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/7917a9f3/code/core/src/test/java/org/apache/tamaya/core/testdata/TestPropertySourceProvider.java ---------------------------------------------------------------------- diff --git a/code/core/src/test/java/org/apache/tamaya/core/testdata/TestPropertySourceProvider.java b/code/core/src/test/java/org/apache/tamaya/core/testdata/TestPropertySourceProvider.java index b93be17..5a427e0 100644 --- a/code/core/src/test/java/org/apache/tamaya/core/testdata/TestPropertySourceProvider.java +++ b/code/core/src/test/java/org/apache/tamaya/core/testdata/TestPropertySourceProvider.java @@ -18,7 +18,7 @@ */ package org.apache.tamaya.core.testdata; -import org.apache.tamaya.core.propertysource.BasePropertySource; +import org.apache.tamaya.spisupport.propertysource.BasePropertySource; import org.apache.tamaya.spi.PropertySource; import org.apache.tamaya.spi.PropertySourceProvider; import org.apache.tamaya.spi.PropertyValue; http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/7917a9f3/code/core/src/test/resources/META-INF/services/org.apache.tamaya.spi.PropertySource ---------------------------------------------------------------------- diff --git a/code/core/src/test/resources/META-INF/services/org.apache.tamaya.spi.PropertySource b/code/core/src/test/resources/META-INF/services/org.apache.tamaya.spi.PropertySource index 409c9cb..14e0c24 100644 --- a/code/core/src/test/resources/META-INF/services/org.apache.tamaya.spi.PropertySource +++ b/code/core/src/test/resources/META-INF/services/org.apache.tamaya.spi.PropertySource @@ -17,6 +17,6 @@ # under the License. # org.apache.tamaya.core.testdata.TestPropertyDefaultSource -org.apache.tamaya.core.propertysource.SystemPropertySource -org.apache.tamaya.core.propertysource.EnvironmentPropertySource +org.apache.tamaya.spisupport.propertysource.SystemPropertySource +org.apache.tamaya.spisupport.propertysource.EnvironmentPropertySource org.apache.tamaya.core.internal.converters.ConverterTestsPropertySource http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/7917a9f3/code/pom.xml ---------------------------------------------------------------------- diff --git a/code/pom.xml b/code/pom.xml index aba365b..719d498 100644 --- a/code/pom.xml +++ b/code/pom.xml @@ -34,6 +34,7 @@ under the License. <modules> <module>api</module> + <module>spi-support</module> <module>core</module> </modules> http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/7917a9f3/code/spi-support/pom.xml ---------------------------------------------------------------------- diff --git a/code/spi-support/pom.xml b/code/spi-support/pom.xml new file mode 100644 index 0000000..bbefa89 --- /dev/null +++ b/code/spi-support/pom.xml @@ -0,0 +1,81 @@ +<!-- +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-code</artifactId> + <version>0.4-incubating-SNAPSHOT</version> + </parent> + + <artifactId>tamaya-spisupport</artifactId> + <name>Apache Tamaya Common Support Classes</name> + <description>Apache Tamaya Support Classes useful when implementing the Tamaya SPI or code independent of the core RI + implementation.</description> + <packaging>jar</packaging> + + <dependencies> + <dependency> + <groupId>org.apache.tamaya</groupId> + <artifactId>tamaya-api</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.osgi</groupId> + <artifactId>org.osgi.compendium</artifactId> + <scope>provided</scope> + <optional>true</optional> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + </dependency> + <dependency> + <groupId>org.hamcrest</groupId> + <artifactId>java-hamcrest</artifactId> + </dependency> + <dependency> + <groupId>org.assertj</groupId> + <artifactId>assertj-core</artifactId> + </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <!-- + ! See https://issues.apache.org/jira/browse/TAMAYA-318 + !--> + <groupId>org.pitest</groupId> + <artifactId>pitest-maven</artifactId> + <configuration> + <skip>true</skip> + </configuration> + </plugin> + </plugins> + </build> + +</project> http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/7917a9f3/code/spi-support/src/main/java/org/apache/tamaya/spisupport/ConfigValueEvaluator.java ---------------------------------------------------------------------- diff --git a/code/spi-support/src/main/java/org/apache/tamaya/spisupport/ConfigValueEvaluator.java b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/ConfigValueEvaluator.java new file mode 100644 index 0000000..92fd614 --- /dev/null +++ b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/ConfigValueEvaluator.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.spisupport; + +import org.apache.tamaya.spi.ConfigurationContext; +import org.apache.tamaya.spi.PropertyValue; + +import java.util.Map; + + +/** + * Component SPI which encapsulates the evaluation of a single or full <b>raw</b>value + * for a {@link ConfigurationContext}. + */ +public interface ConfigValueEvaluator { + + /** + * Evaluates single value using a {@link ConfigurationContext}. + * @param key the config key, not null. + * @param context the context, not null. + * @return the value, or null. + */ + PropertyValue evaluteRawValue(String key, ConfigurationContext context); + + /** + * Evaluates all property values from a {@link ConfigurationContext}. + * @param context the context, not null. + * @return the value, or null. + */ + Map<String, PropertyValue> evaluateRawValues(ConfigurationContext context); + +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/7917a9f3/code/spi-support/src/main/java/org/apache/tamaya/spisupport/ConfigurationBuilder.java ---------------------------------------------------------------------- diff --git a/code/spi-support/src/main/java/org/apache/tamaya/spisupport/ConfigurationBuilder.java b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/ConfigurationBuilder.java new file mode 100644 index 0000000..b764ed6 --- /dev/null +++ b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/ConfigurationBuilder.java @@ -0,0 +1,334 @@ +/* + * 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.spisupport; + + + +import org.apache.tamaya.Configuration; +import org.apache.tamaya.TypeLiteral; +import org.apache.tamaya.spi.*; + +import java.util.Collection; +import java.util.Comparator; +import java.util.List; +import java.util.Map; + +/** + * A builder for creating new or adapting instances of {@link Configuration}. + * Builders can be obtained in exactly two ways: + * <ol> + * <li>By accessing a preinitialized builder from an existing {@link Configuration}, + * by calling {@link org.apache.tamaya.Configuration#toBuilder()}.</li> + * <li>By accessing an empty builder instance from + * {@link org.apache.tamaya.ConfigurationProvider#getConfigurationBuilder()}.</li> + * </ol> + */ +public interface ConfigurationBuilder { + + /** + * Init this builder instance with the given {@link ConfigurationContext} instance. This + * method will use any existing property sources, filters, converters and the combination + * policy of the given {@link ConfigurationContext} and initialize the current builder + * with them. + * + * @param context the {@link ConfigurationContext} instance to be used, not {@code null}. + * @return this builder, for chaining, never null. + */ + ConfigurationBuilder setContext(ConfigurationContext context); + + /** + * This method can be used for adding {@link PropertySource}s. + * Hereby the property source is added to the tail of property sources with + * lowest priority regardless of its current ordinal value. To sort the property + * sources based on their ordinals call {@link #sortPropertySources}. + * + * @param propertySources the PropertySources to add + * @return this builder, for chaining, never null. + * @throws IllegalArgumentException If a property source with a given name already + * exists. + */ + ConfigurationBuilder addPropertySources(PropertySource... propertySources); + + /** + * This method can be used for programmatically adding {@link PropertySource}s. + * Hereby the property source is added to the tail of property sources with + * lowest priority regardless of its current ordinal value. To sort the property + * sources based on their ordinals call {@link #sortPropertySources}. + * + * @param propertySources the PropertySources to add + * @return this builder, for chaining, never null. + * @throws IllegalArgumentException If a property source with a given name already + * exists. + */ + ConfigurationBuilder addPropertySources(Collection<PropertySource> propertySources); + + /** + * Add all registered (default) property sources to the context built. The sources are ordered + * based on their ordinal values and added to the chain of property sources with + * higher priority. + * @return this builder, for chaining, never null. + */ + ConfigurationBuilder addDefaultPropertySources(); + + /** + * Removes the given property sources, if existing. The existing order of property + * sources is preserved. + * + * @param propertySources the property sources to remove, not {@code null}. + * @return the builder for chaining. + */ + ConfigurationBuilder removePropertySources(PropertySource... propertySources); + + /** + * Removes the given property sources, if existing. The existing order of property + * sources is preserved. + * + * @param propertySources the property sources to remove, not {@code null}. + * @return the builder for chaining. + */ + ConfigurationBuilder removePropertySources(Collection<PropertySource> propertySources); + + /** + * Access the current chain of property sources. Items at the end of the list have + * precedence/more significance. + * + * @return the property source chain, never {@code null}. + */ + List<PropertySource> getPropertySources(); + + /** + * Access the current chain of property filters. Items at the end of the list have + * precedence/more significance. + * + * @return the property source chain, never {@code null}. + */ + List<PropertyFilter> getPropertyFilters(); + + /** + * Access the current registered property converters. + * + * @return the current registered property converters. + */ + Map<TypeLiteral<?>, Collection<PropertyConverter<?>>> getPropertyConverter(); + + /** + * Increases the priority of the given property source, by moving it towards the end + * of the chain of property sources. If the property source given is already at the end + * this method has no effect. This operation does not change any ordinal values. + * + * @param propertySource the property source to be incresed regarding its significance. + * @return the builder for chaining. + * @throws IllegalArgumentException If no such property source exists in the current + * chain. + */ + ConfigurationBuilder increasePriority(PropertySource propertySource); + + /** + * Decreases the priority of the given property source, by moving it towards the start + * of the chain of property sources. If the property source given is already the first + * this method has no effect. This operation does not change any ordinal values. + * + * @param propertySource the property source to be decresed regarding its significance. + * @return the builder for chaining. + * @throws IllegalArgumentException If no such property source exists in the current + * chain. + */ + ConfigurationBuilder decreasePriority(PropertySource propertySource); + + /** + * Increases the priority of the given property source to be maximal, by moving it to + * the tail of the of property source chain. If the property source given is + * already the last item this method has no effect. This operation does not change + * any ordinal values. + * + * @param propertySource the property source to be maximized regarding its significance. + * @return the builder for chaining. + * @throws IllegalArgumentException If no such property source exists in the current + * chain. + */ + ConfigurationBuilder highestPriority(PropertySource propertySource); + + /** + * Decreases the priority of the given property source to be minimal, by moving it to + * the start of the chain of property source chain. If the property source given is + * already the first item this method has no effect. This operation does not change + * any ordinal values. + * + * @param propertySource the property source to be minimized regarding its significance. + * @return the builder for chaining. + * @throws IllegalArgumentException If no such property source exists in the current + * chain. + */ + ConfigurationBuilder lowestPriority(PropertySource propertySource); + + /** + * Adds the given PropertyFilter instances, hereby the instances are added + * to the end of the list with highest priority. The ordering of existing + * property filters remains unchanged. To sort the property + * filters call {@link #sortPropertyFilter}. + * + * @param filters the filters to add + * @return this builder, for chaining, never null. + */ + ConfigurationBuilder addPropertyFilters(PropertyFilter... filters); + + /** + * Adds the given PropertyFilter instances, hereby the instances are added + * to the end of the list with highest priority. The ordering of existing + * property filters remains unchanged. To sort the property + * filters call {@link #sortPropertyFilter}. + * + * @param filters the filters to add + * @return this builder, for chaining, never null. + */ + ConfigurationBuilder addPropertyFilters(Collection<PropertyFilter> filters); + + /** + * Add all registered (default) property filters to the context built. + * @return this builder, for chaining, never null. + */ + ConfigurationBuilder addDefaultPropertyFilters(); + + + /** + * Removes the given PropertyFilter instances, if existing. The order of the remaining + * filters is preserved. + * + * @param filters the filter to remove + * @return this builder, for chaining, never null. + */ + ConfigurationBuilder removePropertyFilters(PropertyFilter... filters); + + /** + * Removes the given PropertyFilter instances, if existing. The order of the remaining + * filters is preserved. + * + * @param filters the filter to remove + * @return this builder, for chaining, never null. + */ + ConfigurationBuilder removePropertyFilters(Collection<PropertyFilter> filters); + + /** + * This method can be used for adding {@link PropertyConverter}s. + * Converters are added at the end after any existing converters. + * For converters already registered for the current target type the + * method has no effect. + * + * @param typeToConvert the type for which the converters is for + * @param propertyConverters the PropertyConverters to add for this type + * @param <T> the target type. + * @return this builder, for chaining, never null. + */ + <T> ConfigurationBuilder addPropertyConverters(TypeLiteral<T> typeToConvert, + PropertyConverter<T>... propertyConverters); + + /** + * This method can be used for adding {@link PropertyConverter}s. + * Converters are added at the end after any existing converters. + * For converters already registered for the current target type the + * method has no effect. + * + * @param typeToConvert the type for which the converters is for + * @param propertyConverters the PropertyConverters to add for this type + * @param <T> the target type. + * @return this builder, for chaining, never null. + */ + <T> ConfigurationBuilder addPropertyConverters(TypeLiteral<T> typeToConvert, + Collection<PropertyConverter<T>> propertyConverters); + + /** + * Add all registered (default) property converters to the context built. + * @return this builder, for chaining, never null. + */ + ConfigurationBuilder addDefaultPropertyConverters(); + + /** + * Removes the given PropertyConverter instances for the given type, + * if existing. + * + * @param typeToConvert the type which the converters is for + * @param propertyConverters the converters to remove + * @param <T> the target type. + * @return this builder, for chaining, never null. + */ + <T> ConfigurationBuilder removePropertyConverters(TypeLiteral<T> typeToConvert, + PropertyConverter<T>... propertyConverters); + + /** + * Removes the given PropertyConverter instances for the given type, + * if existing. + * + * @param typeToConvert the type which the converters is for + * @param propertyConverters the converters to remove + * @param <T> the target type. + * @return this builder, for chaining, never null. + */ + <T> ConfigurationBuilder removePropertyConverters(TypeLiteral<T> typeToConvert, + Collection<PropertyConverter<T>> propertyConverters); + + /** + * Removes all converters for the given type, which actually renders a given type + * unsupported for type conversion. + * + * @param typeToConvert the type which the converters is for + * @return this builder, for chaining, never null. + */ + ConfigurationBuilder removePropertyConverters(TypeLiteral<?> typeToConvert); + + /** + * Sorts the current registered property sources using the given comparator. + * + * NOTE: property sources at the beginning have minimal significance. + * + * @param comparator the comparator to be used, not {@code null}. + * @return this instance for chaining. + */ + ConfigurationBuilder sortPropertySources(Comparator<PropertySource> comparator); + + /** + * Sorts the current registered property filters using the given comparator. + * + * NOTE: property filters at the beginning have minimal significance. + * + * @param comparator the comparator to be used, not {@code null}. + * @return this instance for chaining. + */ + ConfigurationBuilder sortPropertyFilter(Comparator<PropertyFilter> comparator); + + /** + * Sets the {@link PropertyValueCombinationPolicy} used to evaluate the final + * property values. + * + * @param policy the {@link PropertyValueCombinationPolicy} used, not {@code null}. + * @return this builder, for chaining, never null. + */ + ConfigurationBuilder setPropertyValueCombinationPolicy(PropertyValueCombinationPolicy policy); + + /** + * Builds a new {@link Configuration} based on the data in this builder. The ordering of property + * sources and property filters is not changed, regardless of their ordinals. For ensure a certain + * ordering/significance call {@link #sortPropertyFilter(Comparator)} and/or {@link #sortPropertySources(Comparator)} + * before building the context. + * + * @return the final configuration. + */ + Configuration build(); + +} + http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/7917a9f3/code/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfigValueEvaluator.java ---------------------------------------------------------------------- diff --git a/code/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfigValueEvaluator.java b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfigValueEvaluator.java new file mode 100644 index 0000000..d50ed7d --- /dev/null +++ b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfigValueEvaluator.java @@ -0,0 +1,70 @@ +/* + * 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.spisupport; + +import org.apache.tamaya.spi.ConfigurationContext; +import org.apache.tamaya.spi.PropertyFilter; +import org.apache.tamaya.spi.PropertySource; +import org.apache.tamaya.spi.PropertyValue; + +import java.util.HashMap; +import java.util.Map; + + +/** + * Implementation of the Configuration API. This class uses the current {@link ConfigurationContext} to evaluate the + * chain of {@link PropertySource} and {@link PropertyFilter} + * instance to evaluate the current Configuration. + */ +public class DefaultConfigValueEvaluator implements ConfigValueEvaluator{ + + @Override + public PropertyValue evaluteRawValue(String key, ConfigurationContext context) { + PropertyValue unfilteredValue = null; + for (PropertySource propertySource : context.getPropertySources()) { + unfilteredValue = context.getPropertyValueCombinationPolicy(). + collect(unfilteredValue, key, propertySource); + } + if(unfilteredValue==null || unfilteredValue.getValue()==null){ + return null; + } + return unfilteredValue; + } + + @Override + public Map<String, PropertyValue> evaluateRawValues(ConfigurationContext context) { + Map<String, PropertyValue> result = new HashMap<>(); + for (PropertySource propertySource : context.getPropertySources()) { + for (Map.Entry<String,PropertyValue> propEntry: propertySource.getProperties().entrySet()) { + PropertyValue unfilteredValue = result.get(propEntry.getKey()); + unfilteredValue = context.getPropertyValueCombinationPolicy(). + collect(unfilteredValue, propEntry.getKey(), propertySource); + if(unfilteredValue!=null){ + result.put(unfilteredValue.getKey(), unfilteredValue); + } + } + } + return result; + } + + @Override + public String toString() { + return "DefaultConfigEvaluator{}"; + } +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/7917a9f3/code/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfiguration.java ---------------------------------------------------------------------- diff --git a/code/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfiguration.java b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfiguration.java new file mode 100644 index 0000000..227c9ab --- /dev/null +++ b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfiguration.java @@ -0,0 +1,268 @@ +/* + * 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.spisupport; + +import org.apache.tamaya.ConfigException; +import org.apache.tamaya.ConfigOperator; +import org.apache.tamaya.ConfigQuery; +import org.apache.tamaya.Configuration; +import org.apache.tamaya.TypeLiteral; +import org.apache.tamaya.spi.ConfigurationContext; +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.apache.tamaya.spi.PropertyValueCombinationPolicy; +import org.apache.tamaya.spi.ServiceContextManager; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Implementation of the Configuration API. This class uses the current {@link ConfigurationContext} to evaluate the + * chain of {@link PropertySource} and {@link org.apache.tamaya.spi.PropertyFilter} + * instance to evaluate the current Configuration. + */ +public class DefaultConfiguration implements Configuration { + /** + * The logger. + */ + private static final Logger LOG = Logger.getLogger(DefaultConfiguration.class.getName()); + + /** + * The current {@link ConfigurationContext} of the current instance. + */ + private final ConfigurationContext configurationContext; + + /** + * EvaluationStrategy + */ + private ConfigValueEvaluator configEvaluator = loadConfigValueEvaluator(); + + private ConfigValueEvaluator loadConfigValueEvaluator() { + ConfigValueEvaluator eval = null; + try{ + eval = ServiceContextManager.getServiceContext() + .getService(ConfigValueEvaluator.class); + }catch(Exception e){ + LOG.log(Level.WARNING, "Failed to load ConfigValueEvaluator from ServiceContext, using default.", e); + } + if(eval==null){ + eval = new DefaultConfigValueEvaluator(); + } + return eval; + } + + + /** + * Constructor. + * @param configurationContext The configuration Context to be used. + */ + public DefaultConfiguration(ConfigurationContext configurationContext){ + this.configurationContext = Objects.requireNonNull(configurationContext); + } + + /** + * Get a given value, filtered with the context's filters as needed. + * @param key the property's key, not null. + * @return the filtered value, or null. + */ + @Override + public String get(String key) { + Objects.requireNonNull(key, "Key must not be null."); + + PropertyValue value = configEvaluator.evaluteRawValue(key, configurationContext); + if(value==null || value.getValue()==null){ + return null; + } + value = PropertyFiltering.applyFilter(value, configurationContext); + if(value!=null){ + return value.getValue(); + } + return null; + } + + /** + * Evaluates the raw value using the context's PropertyValueCombinationPolicy. + * @param key the key, not null. + * @return the value, before filtering is applied. + */ + protected PropertyValue evaluteRawValue(String key) { + List<PropertySource> propertySources = configurationContext.getPropertySources(); + PropertyValue filteredValue = null; + PropertyValueCombinationPolicy combinationPolicy = this.configurationContext + .getPropertyValueCombinationPolicy(); + for (PropertySource propertySource : propertySources) { + filteredValue = combinationPolicy.collect(filteredValue, key, propertySource); + } + return filteredValue; + } + + + @Override + public String getOrDefault(String key, String defaultValue) { + Objects.requireNonNull(key, "Key must not be null."); + Objects.requireNonNull(defaultValue, "Default value must not be null"); + + String val = get(key); + if(val==null){ + return defaultValue; + } + return val; + } + + @Override + public <T> T getOrDefault(String key, Class<T> type, T defaultValue) { + Objects.requireNonNull(key, "Key must not be null."); + Objects.requireNonNull(type, "Target type must not be null"); + Objects.requireNonNull(defaultValue, "Default value must not be null"); + + T val = get(key, type); + if(val==null){ + return defaultValue; + } + return val; + } + + /** + * Get the current properties, composed by the loaded {@link PropertySource} and filtered + * by registered {@link org.apache.tamaya.spi.PropertyFilter}. + * + * @return the final properties. + */ + @Override + public Map<String, String> getProperties() { + Map<String, PropertyValue> filtered = PropertyFiltering.applyFilters( + configEvaluator.evaluateRawValues(configurationContext), + configurationContext); + Map<String,String> result = new HashMap<>(); + for(PropertyValue val:filtered.values()){ + if(val.getValue()!=null) { + result.put(val.getKey(), val.getValue()); + // TODO: Discuss metadata handling... + result.putAll(val.getMetaEntries()); + } + } + return result; + } + + + /** + * Accesses the current String value for the given key and tries to convert it + * using the {@link PropertyConverter} instances provided by the current + * {@link ConfigurationContext}. + * + * @param key the property's absolute, or relative path, e.g. @code + * a/b/c/d.myProperty}, never {@code null}. + * @param type The target type required, not {@code null}. + * @param <T> the value type + * @return the converted value, never {@code null}. + */ + @Override + public <T> T get(String key, Class<T> type) { + return get(key, (TypeLiteral<T>)TypeLiteral.of(type)); + } + + /** + * Accesses the current String value for the given key and tries to convert it + * using the {@link PropertyConverter} instances provided by the current + * {@link ConfigurationContext}. + * + * @param key the property's absolute, or relative path, e.g. @code + * a/b/c/d.myProperty}. + * @param type The target type required, not null. + * @param <T> the value type + * @return the converted value, never null. + */ + @Override + public <T> T get(String key, TypeLiteral<T> type) { + Objects.requireNonNull(key, "Key must not be null."); + Objects.requireNonNull(type, "Target type must not be null"); + + return convertValue(key, get(key), type); + } + + @SuppressWarnings("unchecked") + protected <T> T convertValue(String key, String value, TypeLiteral<T> type) { + if (value != null) { + List<PropertyConverter<T>> converters = configurationContext.getPropertyConverters(type); + ConversionContext context = new ConversionContext.Builder(this, this.configurationContext, key, type) + .build(); + for (PropertyConverter<T> converter : converters) { + try { + T t = converter.convert(value, context); + if (t != null) { + return t; + } + } catch (Exception e) { + LOG.log(Level.FINEST, "PropertyConverter: " + converter + " failed to convert value: " + value, e); + } + } + // if the target type is a String, we can return the value, no conversion required. + if(type.equals(TypeLiteral.of(String.class))){ + return (T)value; + } + // unsupported type, throw an exception + throw new ConfigException("Unparseable config value for type: " + type.getRawType().getName() + ": " + key + + ", supported formats: " + context.getSupportedFormats()); + } + return null; + } + + @Override + public <T> T getOrDefault(String key, TypeLiteral<T> type, T defaultValue) { + Objects.requireNonNull(key); + Objects.requireNonNull(type); + Objects.requireNonNull(defaultValue); + + T val = get(key, type); + if(val==null){ + return defaultValue; + } + return val; + } + + @Override + public Configuration with(ConfigOperator operator) { + return operator.operate(this); + } + + @Override + public <T> T query(ConfigQuery<T> query) { + return query.query(this); + } + + @Override + public ConfigurationContext getContext() { + return this.configurationContext; + } + + @Override + public String toString() { + return "Configuration{\n " + + configurationContext + + '}'; + } +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/7917a9f3/code/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfigurationBuilder.java ---------------------------------------------------------------------- diff --git a/code/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfigurationBuilder.java b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfigurationBuilder.java new file mode 100644 index 0000000..f1c0f46 --- /dev/null +++ b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfigurationBuilder.java @@ -0,0 +1,229 @@ +/* + * 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.spisupport; + +import org.apache.tamaya.Configuration; +import org.apache.tamaya.TypeLiteral; +import org.apache.tamaya.spi.*; + +import java.util.*; + +/** + * Default implementation of {@link ConfigurationContextBuilder}. + */ +public class DefaultConfigurationBuilder implements ConfigurationBuilder { + + private final ConfigurationContextBuilder contextBuilder; + + /** + * Creates a new builder instance. + */ + public DefaultConfigurationBuilder(ConfigurationContextBuilder contextBuilder) { + this.contextBuilder = Objects.requireNonNull(contextBuilder); + } + + /** + * Creates a new builder instance initializing it with the given context. + * @param configuration the configuration to be used, not null. + */ + public DefaultConfigurationBuilder(Configuration configuration) { + this.contextBuilder = configuration.getContext().toBuilder(); + } + + /** + * Allows to set configuration context during unit tests. + */ + ConfigurationBuilder setConfiguration(Configuration configuration) { + this.contextBuilder.setContext(configuration.getContext()); + return this; + } + + + @Override + public ConfigurationBuilder setContext(ConfigurationContext context) { + this.contextBuilder.setContext(context); + return this; + } + + @Override + public ConfigurationBuilder addPropertySources(PropertySource... sources){ + this.contextBuilder.addPropertySources(sources); + return this; + } + + @Override + public ConfigurationBuilder addPropertySources(Collection<PropertySource> sources){ + this.contextBuilder.addPropertySources(sources); + return this; + } + + public ConfigurationBuilder addDefaultPropertyFilters() { + this.contextBuilder.addDefaultPropertyFilters(); + return this; + } + + public ConfigurationBuilder addDefaultPropertySources() { + this.contextBuilder.addDefaultPropertySources(); + return this; + } + + public ConfigurationBuilder addDefaultPropertyConverters() { + this.contextBuilder.addDefaultPropertyConverters(); + return this; + } + + @Override + public ConfigurationBuilder removePropertySources(PropertySource... propertySources) { + this.contextBuilder.removePropertySources(propertySources); + return this; + } + + @Override + public ConfigurationBuilder removePropertySources(Collection<PropertySource> propertySources) { + this.contextBuilder.removePropertySources(propertySources); + return this; + } + + @Override + public List<PropertySource> getPropertySources() { + return this.contextBuilder.getPropertySources(); + } + + @Override + public ConfigurationBuilder increasePriority(PropertySource propertySource) { + this.contextBuilder.increasePriority(propertySource); + return this; + } + + @Override + public ConfigurationBuilder decreasePriority(PropertySource propertySource) { + this.contextBuilder.decreasePriority(propertySource); + return this; + } + + @Override + public ConfigurationBuilder highestPriority(PropertySource propertySource) { + this.contextBuilder.highestPriority(propertySource); + return this; + } + + @Override + public ConfigurationBuilder lowestPriority(PropertySource propertySource) { + this.contextBuilder.lowestPriority(propertySource); + return this; + } + + @Override + public ConfigurationBuilder addPropertyFilters(PropertyFilter... filters){ + this.contextBuilder.addPropertyFilters(filters); + return this; + } + + @Override + public ConfigurationBuilder addPropertyFilters(Collection<PropertyFilter> filters){ + this.contextBuilder.addPropertyFilters(filters); + return this; + } + + @Override + public ConfigurationBuilder removePropertyFilters(PropertyFilter... filters) { + this.contextBuilder.removePropertyFilters(filters); + return this; + } + + @Override + public ConfigurationBuilder removePropertyFilters(Collection<PropertyFilter> filters) { + this.contextBuilder.removePropertyFilters(filters); + return this; + } + + + @Override + public <T> ConfigurationBuilder removePropertyConverters(TypeLiteral<T> typeToConvert, + PropertyConverter<T>... converters) { + this.contextBuilder.removePropertyConverters(typeToConvert, converters); + return this; + } + + @Override + public <T> ConfigurationBuilder removePropertyConverters(TypeLiteral<T> typeToConvert, + Collection<PropertyConverter<T>> converters) { + this.contextBuilder.removePropertyConverters(typeToConvert, converters); + return this; + } + + @Override + public ConfigurationBuilder removePropertyConverters(TypeLiteral<?> typeToConvert) { + this.contextBuilder.removePropertyConverters(typeToConvert); + return this; + } + + + @Override + public ConfigurationBuilder setPropertyValueCombinationPolicy(PropertyValueCombinationPolicy combinationPolicy){ + this.contextBuilder.setPropertyValueCombinationPolicy(combinationPolicy); + return this; + } + + + @Override + public <T> ConfigurationBuilder addPropertyConverters(TypeLiteral<T> type, PropertyConverter<T>... propertyConverters){ + this.contextBuilder.addPropertyConverters(type, propertyConverters); + return this; + } + + @Override + public <T> ConfigurationBuilder addPropertyConverters(TypeLiteral<T> type, Collection<PropertyConverter<T>> propertyConverters){ + this.contextBuilder.addPropertyConverters(type, propertyConverters); + return this; + } + + /** + * Builds a new configuration based on the configuration of this builder instance. + * + * @return a new {@link org.apache.tamaya.Configuration configuration instance}, + * never {@code null}. + */ + @Override + public Configuration build() { + return new DefaultConfiguration(this.contextBuilder.build()); + } + + @Override + public ConfigurationBuilder sortPropertyFilter(Comparator<PropertyFilter> comparator) { + this.contextBuilder.sortPropertyFilter(comparator); + return this; + } + + @Override + public ConfigurationBuilder sortPropertySources(Comparator<PropertySource> comparator) { + this.contextBuilder.sortPropertySources(comparator); + return this; + } + + @Override + public List<PropertyFilter> getPropertyFilters() { + return this.contextBuilder.getPropertyFilters(); + } + + @Override + public Map<TypeLiteral<?>, Collection<PropertyConverter<?>>> getPropertyConverter() { + return this.contextBuilder.getPropertyConverter(); + } +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/7917a9f3/code/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultServiceContext.java ---------------------------------------------------------------------- diff --git a/code/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultServiceContext.java b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultServiceContext.java new file mode 100644 index 0000000..61819f9 --- /dev/null +++ b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultServiceContext.java @@ -0,0 +1,204 @@ +/* + * 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.spisupport; + +import org.apache.tamaya.ConfigException; +import org.apache.tamaya.spi.ServiceContext; + +import javax.annotation.Priority; +import java.io.IOException; +import java.net.URL; +import java.text.MessageFormat; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * This class implements the (default) {@link ServiceContext} interface and hereby uses the JDK + * {@link ServiceLoader} to load the services required. + */ +public final class DefaultServiceContext implements ServiceContext { + private static final Logger LOG = Logger.getLogger(DefaultServiceContext.class.getName()); + /** + * List current services loaded, per class. + */ + private final ConcurrentHashMap<Class<?>, List<Object>> servicesLoaded = new ConcurrentHashMap<>(); + /** + * Singletons. + */ + private final Map<Class<?>, Object> singletons = new ConcurrentHashMap<>(); + @SuppressWarnings("rawtypes") + private Map<Class, Class> factoryTypes = new ConcurrentHashMap<>(); + + @Override + public <T> T getService(Class<T> serviceType) { + Object cached = singletons.get(serviceType); + if (cached == null) { + cached = create(serviceType); + if(cached!=null) { + singletons.put(serviceType, cached); + } + } + return serviceType.cast(cached); + } + + @Override + public <T> T create(Class<T> serviceType) { + @SuppressWarnings("unchecked") + Class<? extends T> implType = factoryTypes.get(serviceType); + if(implType==null) { + Collection<T> services = getServices(serviceType); + if (services.isEmpty()) { + return null; + } else { + return getServiceWithHighestPriority(services, serviceType); + } + } + try { + return implType.newInstance(); + } catch (Exception e) { + LOG.log(Level.SEVERE, "Failed to create instance of " + implType.getName(), e); + return null; + } + } + + /** + * Loads and registers services. + * + * @param <T> the concrete type. + * @param serviceType The service type. + * @return the items found, never {@code null}. + */ + @Override + public <T> List<T> getServices(final Class<T> serviceType) { + @SuppressWarnings("unchecked") + List<T> found = (List<T>) servicesLoaded.get(serviceType); + if (found != null) { + return found; + } + List<T> services = new ArrayList<>(); + try { + for (T t : ServiceLoader.load(serviceType)) { + services.add(t); + } + if(services.isEmpty()) { + for (T t : ServiceLoader.load(serviceType, serviceType.getClassLoader())) { + services.add(t); + } + } + Collections.sort(services, PriorityServiceComparator.getInstance()); + services = Collections.unmodifiableList(services); + } catch (ServiceConfigurationError e) { + LOG.log(Level.WARNING, + "Error loading services current type " + serviceType, e); + if(services==null){ + services = Collections.emptyList(); + } + } + @SuppressWarnings("unchecked") + final List<T> previousServices = List.class.cast(servicesLoaded.putIfAbsent(serviceType, (List<Object>) services)); + return previousServices != null ? previousServices : services; + } + + /** + * Checks the given instance for a @Priority annotation. If present the annotation's value is evaluated. If no such + * annotation is present, a default priority of {@code 1} is returned. + * @param o the instance, not {@code null}. + * @return a priority, by default 1. + */ + public static int getPriority(Object o){ + int prio = 1; //X TODO discuss default priority + Priority priority = o.getClass().getAnnotation(Priority.class); + if (priority != null) { + prio = priority.value(); + } + return prio; + } + + /** + * @param services to scan + * @param <T> type of the service + * + * @return the service with the highest {@link Priority#value()} + * + * @throws ConfigException if there are multiple service implementations with the maximum priority + */ + private <T> T getServiceWithHighestPriority(Collection<T> services, Class<T> serviceType) { + T highestService = null; + // we do not need the priority stuff if the list contains only one element + if (services.size() == 1) { + highestService = services.iterator().next(); + this.factoryTypes.put(serviceType, highestService.getClass()); + return highestService; + } + + Integer highestPriority = null; + int highestPriorityServiceCount = 0; + + for (T service : services) { + int prio = getPriority(service); + if (highestPriority == null || highestPriority < prio) { + highestService = service; + highestPriorityServiceCount = 1; + highestPriority = prio; + } else if (highestPriority == prio) { + highestPriorityServiceCount++; + } + } + + if (highestPriorityServiceCount > 1) { + throw new ConfigException(MessageFormat.format("Found {0} implementations for Service {1} with Priority {2}: {3}", + highestPriorityServiceCount, + serviceType.getName(), + highestPriority, + services)); + } + this.factoryTypes.put(serviceType, highestService.getClass()); + return highestService; + } + + @Override + public int ordinal() { + return 1; + } + + @Override + public Enumeration<URL> getResources(String resource, ClassLoader cl) throws IOException { + if(cl==null){ + cl = Thread.currentThread().getContextClassLoader(); + } + if(cl==null){ + cl = getClass().getClassLoader(); + } + return cl.getResources(resource); + } + + @Override + public URL getResource(String resource, ClassLoader cl) { + if(cl==null){ + cl = Thread.currentThread().getContextClassLoader(); + } + if(cl==null){ + cl = getClass().getClassLoader(); + } + return cl.getResource(resource); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/7917a9f3/code/spi-support/src/main/java/org/apache/tamaya/spisupport/EnumConverter.java ---------------------------------------------------------------------- diff --git a/code/spi-support/src/main/java/org/apache/tamaya/spisupport/EnumConverter.java b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/EnumConverter.java new file mode 100644 index 0000000..ed5214a --- /dev/null +++ b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/EnumConverter.java @@ -0,0 +1,83 @@ +/* + * 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.spisupport; + +import org.apache.tamaya.ConfigException; +import org.apache.tamaya.spi.ConversionContext; +import org.apache.tamaya.spi.PropertyConverter; +import org.osgi.service.component.annotations.Component; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Locale; +import java.util.Objects; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Converter, converting from String to tge given enum type. + */ +@Component(service = PropertyConverter.class) +public class EnumConverter<T> implements PropertyConverter<T> { + private final Logger LOG = Logger.getLogger(EnumConverter.class.getName()); + private Class<T> enumType; + private Method factory; + + public EnumConverter(Class<T> enumType) { + if (!Enum.class.isAssignableFrom(enumType)) { + throw new IllegalArgumentException("Not an Enum: " + enumType.getName()); + } + this.enumType = Objects.requireNonNull(enumType); + try { + this.factory = enumType.getMethod("valueOf", String.class); + } catch (NoSuchMethodException e) { + throw new ConfigException("Uncovertible enum type without valueOf method found, please provide a custom " + + "PropertyConverter for: " + enumType.getName()); + } + } + + @Override + public T convert(String value, ConversionContext context) { + context.addSupportedFormats(getClass(),"<enumValue>"); + try { + return (T) factory.invoke(null, value); + } catch (InvocationTargetException | IllegalAccessException e) { + LOG.log(Level.FINEST, "Invalid enum value '" + value + "' for " + enumType.getName(), e); + } + try { + return (T) factory.invoke(null, value.toUpperCase(Locale.ENGLISH)); + } catch (InvocationTargetException | IllegalAccessException e) { + LOG.log(Level.FINEST, "Invalid enum value '" + value + "' for " + enumType.getName(), e); + } + return null; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof EnumConverter)) return false; + EnumConverter<?> that = (EnumConverter<?>) o; + return Objects.equals(enumType, that.enumType); + } + + @Override + public int hashCode() { + return Objects.hash(enumType); + } +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/7917a9f3/code/spi-support/src/main/java/org/apache/tamaya/spisupport/PriorityServiceComparator.java ---------------------------------------------------------------------- diff --git a/code/spi-support/src/main/java/org/apache/tamaya/spisupport/PriorityServiceComparator.java b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/PriorityServiceComparator.java new file mode 100644 index 0000000..dbef51f --- /dev/null +++ b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/PriorityServiceComparator.java @@ -0,0 +1,84 @@ +/* + * 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.spisupport; + +import javax.annotation.Priority; +import java.io.Serializable; +import java.util.Comparator; + +/** + * Comparator implementation for odering services loaded based on their increasing priority values. + */ +public class PriorityServiceComparator implements Comparator<Object>, Serializable { + + private static final long serialVersionUID = 1L; + + private static final PriorityServiceComparator INSTANCE = new PriorityServiceComparator(); + + /** Singleton constructor. */ + private PriorityServiceComparator(){} + + /** + * Get the shared instance of the comparator. + * @return the shared instance, never null. + */ + public static PriorityServiceComparator getInstance(){ + return INSTANCE; + } + + @Override + public int compare(Object o1, Object o2) { + int prio = getPriority(o1) - getPriority(o2); + if (prio < 0) { + return 1; + } else if (prio > 0) { + return -1; + } else { + return o1.getClass().getSimpleName().compareTo(o2.getClass().getSimpleName()); + } + } + + /** + * Checks the given instance for a @Priority annotation. If present the annotation's value is evaluated. If no such + * annotation is present, a default priority {@code 1} is returned. + * + * @param o the instance, not {@code null}. + * @return a priority, by default 1. + */ + public static int getPriority(Object o) { + return getPriority(o.getClass()); + } + + /** + * Checks the given type optionally annotated with a @Priority. If present the annotation's value is evaluated. + * If no such annotation is present, a default priority {@code 1} is returned. + * + * @param type the type, not {@code null}. + * @return a priority, by default 1. + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + public static int getPriority(Class type) { + int prio = 1; + Priority priority = (Priority)type.getAnnotation(Priority.class); + if (priority != null) { + prio = priority.value(); + } + return prio; + } +}
