TAMAYA-42,43,44: Added initial implementation of Configuration, ConfigurationContext, ResourceLoading and ConfigurationFormat.
Project: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/commit/8b2cc9b1 Tree: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/tree/8b2cc9b1 Diff: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/diff/8b2cc9b1 Branch: refs/heads/master Commit: 8b2cc9b15c95470ea430bea899ba5854d4ce434c Parents: b56817f Author: anatole <anat...@apache.org> Authored: Sat Jan 3 09:44:57 2015 +0100 Committer: anatole <anat...@apache.org> Committed: Sat Jan 3 09:44:57 2015 +0100 ---------------------------------------------------------------------- core/pom.xml | 36 +++++ .../core/PathBasedPropertySourceProvider.java | 76 +++++++++ .../core/ResourcePropertySourceProvider.java | 83 ++++++++++ .../core/formats/ConfigurationFormat.java | 46 ++++++ .../tamaya/core/formats/PropertiesFormat.java | 109 +++++++++++++ .../core/formats/PropertiesXmlFormat.java | 111 +++++++++++++ .../core/internal/DefaultConfiguration.java | 68 ++++++++ .../internal/DefaultConfigurationContext.java | 158 +++++++++++++++++++ .../core/internal/DefaultServiceContext.java | 89 +++++++++++ .../resource/DefaultResourceLoader.java | 94 +++++++++++ .../services/org.apache.tamaya.Configuration | 19 +++ ....apache.tamaya.core.resources.ResourceLoader | 19 +++ .../org.apache.tamaya.spi.ConfigurationContext | 19 +++ .../org.apache.tamaya.spi.ServiceContext | 19 +++ .../apache/tamaya/core/ConfigurationTest.java | 53 +++++++ .../TestPropertyDefaultSourceProvider.java | 32 ++++ ...org.apache.tamaya.spi.PropertySourceProvider | 20 +++ .../resources/cfg/defaults/test1.properties | 20 +++ .../cfg/final/anotherTestFile.properties | 22 +++ 19 files changed, 1093 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/8b2cc9b1/core/pom.xml ---------------------------------------------------------------------- diff --git a/core/pom.xml b/core/pom.xml index 26ccce0..64c868a 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -30,12 +30,48 @@ under the License. <artifactId>tamaya-core</artifactId> + <properties> + <slf4j.version>1.7.2</slf4j.version> + <log4j.version>1.2.17</log4j.version> + <log4j2.version>2.1</log4j2.version> + </properties> + <dependencies> <dependency> <groupId>org.apache.tamaya</groupId> <artifactId>tamaya-api</artifactId> <version>${project.version}</version> </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + <!-- Deps for logging backends --> + <dependency> + <groupId>log4j</groupId> + <artifactId>log4j</artifactId> + <version>${log4j.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.apache.logging.log4j</groupId> + <artifactId>log4j-api</artifactId> + <version>${log4j2.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>commons-logging</groupId> + <artifactId>commons-logging</artifactId> + <version>1.1.1</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + <version>${slf4j.version}</version> + <scope>provided</scope> + </dependency> </dependencies> </project> http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/8b2cc9b1/core/src/main/java/org/apache/tamaya/core/PathBasedPropertySourceProvider.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/tamaya/core/PathBasedPropertySourceProvider.java b/core/src/main/java/org/apache/tamaya/core/PathBasedPropertySourceProvider.java new file mode 100644 index 0000000..aba7a9f --- /dev/null +++ b/core/src/main/java/org/apache/tamaya/core/PathBasedPropertySourceProvider.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tamaya.core; + +import org.apache.tamaya.core.formats.ConfigurationFormat; +import org.apache.tamaya.core.resources.Resource; +import org.apache.tamaya.core.resources.ResourceLoader; +import org.apache.tamaya.spi.PropertySource; +import org.apache.tamaya.spi.PropertySourceProvider; +import org.apache.tamaya.spi.ServiceContext; + +import java.util.*; +import java.util.ArrayList; +import java.util.Objects; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Implementation of a PropertySourceProvider that reads configuration from some given resource paths + * and using the goven formats. + */ +public class PathBasedPropertySourceProvider implements PropertySourceProvider { + + private static final Logger LOG = Logger.getLogger(PathBasedPropertySourceProvider.class.getName()); + + private String baseName; + private List<ConfigurationFormat> configFormats = new ArrayList<>(); + private List<String> paths = new ArrayList<>(); + + public PathBasedPropertySourceProvider(String baseName, List<ConfigurationFormat> formats, String... paths) { + this.baseName = Objects.requireNonNull(baseName); + this.configFormats.addAll(Objects.requireNonNull(formats)); + this.paths.addAll(Arrays.asList(Objects.requireNonNull(paths))); + } + + public PathBasedPropertySourceProvider(String baseName, ConfigurationFormat format, String... paths) { + this.baseName = Objects.requireNonNull(baseName); + this.configFormats.add(Objects.requireNonNull(format)); + this.paths.addAll(Arrays.asList(Objects.requireNonNull(paths))); + } + + @Override + public Collection<PropertySource> getPropertySources(){ + List<PropertySource> propertySources = new ArrayList<>(); + paths.forEach((path) -> { + for (Resource res : ServiceContext.getInstance().getService(ResourceLoader.class).get().getResources(path)) { + try{ + for(ConfigurationFormat format:configFormats){ + propertySources.addAll(format.readConfiguration(res)); + } + } + catch(Exception e){ + LOG.log(Level.WARNING, "Failed to add resource based config: " + res.getDisplayName(), e); + } + } + }); + return propertySources; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/8b2cc9b1/core/src/main/java/org/apache/tamaya/core/ResourcePropertySourceProvider.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/tamaya/core/ResourcePropertySourceProvider.java b/core/src/main/java/org/apache/tamaya/core/ResourcePropertySourceProvider.java new file mode 100644 index 0000000..978ab9a --- /dev/null +++ b/core/src/main/java/org/apache/tamaya/core/ResourcePropertySourceProvider.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.core; + +import org.apache.tamaya.core.formats.ConfigurationFormat; +import org.apache.tamaya.core.resources.Resource; +import org.apache.tamaya.spi.PropertySource; +import org.apache.tamaya.spi.PropertySourceProvider; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.logging.Logger; + +public class ResourcePropertySourceProvider implements PropertySourceProvider { + + private static final Logger LOG = Logger.getLogger(ResourcePropertySourceProvider.class.getName()); + + private List<ConfigurationFormat> formats = new ArrayList<>(); + + private Resource resource; + + public ResourcePropertySourceProvider(Resource resource, ConfigurationFormat... formats) { + this.resource = Objects.requireNonNull(resource); + this.formats.addAll(Arrays.asList(formats)); + } + + public ResourcePropertySourceProvider(Resource resource, List<ConfigurationFormat> formats) { + this.resource = Objects.requireNonNull(resource); + this.formats.addAll(formats); + } + + + /** + * Get the underlying resource. + * + * @return + */ + public Resource getResource() { + return this.resource; + } + + + @Override + public String toString() { + return "ResourcePropertySourceProvider{" + + "resource=" + resource + + ", formats=+" + formats + + '}'; + } + + @Override + public Collection<PropertySource> getPropertySources() { + List<PropertySource> propertySources = new ArrayList<>(); + for (ConfigurationFormat format : formats) { + try { + propertySources.addAll(format.readConfiguration(resource)); + } catch (Exception e) { + LOG.info(() -> "Format was not matching: " + format + " for resource: " + resource.getDisplayName()); + } + } + return propertySources; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/8b2cc9b1/core/src/main/java/org/apache/tamaya/core/formats/ConfigurationFormat.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/tamaya/core/formats/ConfigurationFormat.java b/core/src/main/java/org/apache/tamaya/core/formats/ConfigurationFormat.java new file mode 100644 index 0000000..e9308c7 --- /dev/null +++ b/core/src/main/java/org/apache/tamaya/core/formats/ConfigurationFormat.java @@ -0,0 +1,46 @@ +/* + * 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.formats; + +import org.apache.tamaya.core.resources.Resource; +import org.apache.tamaya.spi.PropertySource; + +import java.io.IOException; +import java.util.Collection; + +/** + * Implementations current this class encapsulate the mechanism how to read a + * resource including interpreting the format correctly (e.g. xml vs. + * properties). In most cases file only contains entries of the same priority, which would then + * result in only one {@link PropertySource}. Complex file formats, hoiwever, may contain entries + * of different priorities. In this cases, each ordinal type found must be returned as a separate + * {@link PropertySource} instance. + */ +@FunctionalInterface +public interface ConfigurationFormat{ + + /** + * Reads a list {@link org.apache.tamaya.spi.PropertySource} instances from a resource, using this format. + * Hereby the ordinal given is used as a base ordinal + * @param resource the configuration resource, not null + * @return the corresponding {@link java.util.Map}, never {@code null}. + */ + Collection<PropertySource> readConfiguration(Resource resource)throws IOException; + +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/8b2cc9b1/core/src/main/java/org/apache/tamaya/core/formats/PropertiesFormat.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/tamaya/core/formats/PropertiesFormat.java b/core/src/main/java/org/apache/tamaya/core/formats/PropertiesFormat.java new file mode 100644 index 0000000..dc3d9bb --- /dev/null +++ b/core/src/main/java/org/apache/tamaya/core/formats/PropertiesFormat.java @@ -0,0 +1,109 @@ +/* + * 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.formats; + +import org.apache.tamaya.core.resources.Resource; +import org.apache.tamaya.spi.PropertySource; + +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Properties; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Implementation of a configuration format for -properties files. + */ +public class PropertiesFormat implements ConfigurationFormat{ + + private final static Logger LOG = Logger.getLogger(PropertiesFormat.class.getName()); + + /** The target ordinal. */ + private int ordinal; + + /** + * Creates a new ordinal. + * @param ordinal the target ordinal. + */ + private PropertiesFormat(int ordinal){ + this.ordinal = ordinal; + } + + public static PropertiesFormat of(int ordinal){ + // TODO caching... + return new PropertiesFormat(ordinal); + } + + /** + * Get the target ordinal, produced by this format. + * @return the target ordinal + */ + public int getOrdinal(){ + return ordinal; + } + + @SuppressWarnings("unchecked") + @Override + public Collection<PropertySource> readConfiguration(Resource resource) { + if (resource.exists()) { + List<PropertySource> propertySources = new ArrayList<>(); + try (InputStream is = resource.getInputStream()) { + final Properties p = new Properties(); + p.load(is); + propertySources.add(new PropertySource(){ + @Override + public int getOrdinal() { + return ordinal; + } + + @Override + public String getName() { + return resource.getDisplayName(); + } + + @Override + public Optional<String> get(String key) { + return Optional.ofNullable(p.getProperty(key)); + } + + @Override + public Map<String, String> getProperties() { + return Map.class.cast(p); + } + }); + return propertySources; + } catch (Exception e) { + LOG.log(Level.FINEST, e, () -> "Failed to read config from resource: " + resource); + } + } + return Collections.emptyList(); + } + + @Override + public String toString() { + return "PropertiesFormat{" + + "ordinal=" + ordinal + + '}'; + } +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/8b2cc9b1/core/src/main/java/org/apache/tamaya/core/formats/PropertiesXmlFormat.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/tamaya/core/formats/PropertiesXmlFormat.java b/core/src/main/java/org/apache/tamaya/core/formats/PropertiesXmlFormat.java new file mode 100644 index 0000000..625dd32 --- /dev/null +++ b/core/src/main/java/org/apache/tamaya/core/formats/PropertiesXmlFormat.java @@ -0,0 +1,111 @@ +/* + * 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.formats; + +import org.apache.tamaya.core.resources.Resource; +import org.apache.tamaya.spi.PropertySource; + +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Properties; +import java.util.logging.Level; +import java.util.logging.Logger; + + +public class PropertiesXmlFormat implements ConfigurationFormat { + + private final static Logger LOG = Logger.getLogger(PropertiesXmlFormat.class.getName()); + + /** + * The target ordinal. + */ + private int ordinal; + + /** + * Creates a new ordinal. + * + * @param ordinal the target ordinal. + */ + private PropertiesXmlFormat(int ordinal) { + this.ordinal = ordinal; + } + + public static PropertiesXmlFormat of(int ordinal){ + // TODO caching... + return new PropertiesXmlFormat(ordinal); + } + + /** + * Get the target ordinal, produced by this format. + * + * @return the target ordinal + */ + public int getOrdinal() { + return ordinal; + } + + @SuppressWarnings("unchecked") + @Override + public Collection<PropertySource> readConfiguration(Resource resource) { + if (resource.exists()) { + List<PropertySource> propertySources = new ArrayList<>(); + try (InputStream is = resource.getInputStream()) { + final Properties p = new Properties(); + p.loadFromXML(is); + propertySources.add(new PropertySource() { + @Override + public int getOrdinal() { + return ordinal; + } + + @Override + public String getName() { + return resource.getDisplayName(); + } + + @Override + public Optional<String> get(String key) { + return Optional.ofNullable(p.getProperty(key)); + } + + @Override + public Map<String, String> getProperties() { + return Map.class.cast(p); + } + }); + return propertySources; + } catch (Exception e) { + LOG.log(Level.FINEST, e, () -> "Failed to read config from resource: " + resource); + } + } + return Collections.emptyList(); + } + + @Override + public String toString() { + return "PropertiesXmlFormat{" + + "ordinal=" + ordinal + + '}'; + } +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/8b2cc9b1/core/src/main/java/org/apache/tamaya/core/internal/DefaultConfiguration.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/tamaya/core/internal/DefaultConfiguration.java b/core/src/main/java/org/apache/tamaya/core/internal/DefaultConfiguration.java new file mode 100644 index 0000000..ef27c87 --- /dev/null +++ b/core/src/main/java/org/apache/tamaya/core/internal/DefaultConfiguration.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tamaya.core.internal; + +import org.apache.tamaya.ConfigException; +import org.apache.tamaya.Configuration; +import org.apache.tamaya.spi.ConfigurationContext; +import org.apache.tamaya.spi.PropertyConverter; +import org.apache.tamaya.spi.PropertySource; +import org.apache.tamaya.spi.ServiceContext; + +import java.util.List; +import java.util.Optional; + +/** + * Implementation of the Configuration API. + */ +public class DefaultConfiguration implements Configuration{ + + @Override + public Optional<String> get(String key) { + List<PropertySource> propertySources = ServiceContext.getInstance().getService(ConfigurationContext.class).get().getPropertySources(); + for(PropertySource propertySource:propertySources){ + Optional<String> value = propertySource.get(key); + if(value.isPresent()){ + return value; + } + } + return Optional.empty(); + } + + @Override + public <T> Optional<T> get(String key, Class<T> type) { + Optional<String> value = get(key); + if(value.isPresent()){ + List<PropertyConverter<T>> converters = ServiceContext.getInstance().getService(ConfigurationContext.class).get().getPropertyConverters(type); + for(PropertyConverter<T> converter:converters){ + try{ + T t = converter.convert(value.get()); + if(t!=null){ + return Optional.of(t); + } + } + catch(Exception e){ + // TODO LOG + } + } + throw new ConfigException("Unparseable config value for type: " + type.getName() + ": " + key); + } + return Optional.empty(); + } +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/8b2cc9b1/core/src/main/java/org/apache/tamaya/core/internal/DefaultConfigurationContext.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/tamaya/core/internal/DefaultConfigurationContext.java b/core/src/main/java/org/apache/tamaya/core/internal/DefaultConfigurationContext.java new file mode 100644 index 0000000..90b1d16 --- /dev/null +++ b/core/src/main/java/org/apache/tamaya/core/internal/DefaultConfigurationContext.java @@ -0,0 +1,158 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tamaya.core.internal; + +import org.apache.tamaya.spi.ConfigurationContext; +import org.apache.tamaya.spi.PropertyConverter; +import org.apache.tamaya.spi.PropertyFilter; +import org.apache.tamaya.spi.PropertySource; +import org.apache.tamaya.spi.PropertySourceProvider; +import org.apache.tamaya.spi.ServiceContext; + +import javax.annotation.Priority; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.StampedLock; +import java.util.stream.Stream; + +/** + * Default Implementation of a simple ConfigurationContext. + */ +public class DefaultConfigurationContext implements ConfigurationContext{ + + private PropertyConverterManager propertyConverterManager = new PropertyConverterManager(); + + private List<PropertySource> propertySources = new ArrayList<>(); + private List<PropertySourceProvider> propertySourceProviders = new ArrayList<>(); + private List<PropertyFilter> propertyFilters = new ArrayList<>(); + private boolean loaded = false; + + private StampedLock propertySourceLock = new StampedLock(); + + + @Override + public void addPropertySources(PropertySource... propertySourcesToAdd) { + Lock writeLock = propertySourceLock.asWriteLock(); + try{ + writeLock.lock(); + List<PropertySource> newPropertySources = new ArrayList<>(this.propertySources); + newPropertySources.addAll(Arrays.asList(propertySourcesToAdd)); + Collections.sort(newPropertySources, this::comparePropertySources); + this.propertySources = newPropertySources; + } + finally{ + writeLock.unlock(); + } + } + + /** + * Order property source reversely, the most important come first. + * @param source1 + * @param source2 + * @return + */ + private int comparePropertySources(PropertySource source1, PropertySource source2){ + if(source1.getOrdinal() < source2.getOrdinal()){ + return 1; + } + else if(source1.getOrdinal()>source2.getOrdinal()){ + return -1; + } + else{ + return source2.getClass().getName().compareTo(source1.getClass().getName()); + } + } + + private int comparePropertyFilters(PropertyFilter filter1, PropertyFilter filter2){ + Priority prio1 = filter1.getClass().getAnnotation(Priority.class); + Priority prio2 = filter2.getClass().getAnnotation(Priority.class); + int ord1 = prio1!=null?prio1.value():0; + int ord2 = prio2!=null?prio2.value():0; + if(ord1 < ord2){ + return -1; + } + else if(ord1>ord2){ + return 1; + } + else{ + return filter1.getClass().getName().compareTo(filter2.getClass().getName()); + } + } + + @Override + public List<PropertySource> getPropertySources() { + if(!loaded){ + Lock writeLock = propertySourceLock.asWriteLock(); + try{ + writeLock.lock(); + if(!loaded) { + this.propertySources.addAll(ServiceContext.getInstance().getServices(PropertySource.class)); + this.propertySourceProviders.addAll(ServiceContext.getInstance().getServices(PropertySourceProvider.class)); + for (PropertySourceProvider prov : this.propertySourceProviders) { + try { + this.propertySources.addAll(prov.getPropertySources()); + } catch (Exception e) { + //X TODO Log! + } + } + Collections.sort(this.propertySources, this::comparePropertySources); + this.propertyFilters.addAll(ServiceContext.getInstance().getServices(PropertyFilter.class)); + Collections.sort(this.propertyFilters, this::comparePropertyFilters); + loaded = true; + } + } + finally{ + writeLock.unlock(); + } + } + Lock readLock = propertySourceLock.asReadLock(); + try{ + readLock.lock(); + return Collections.unmodifiableList(propertySources); + } + finally{ + readLock.unlock(); + } + } + + @Override + public <T> void addPropertyConverter(Class<T> typeToConvert, PropertyConverter<T> propertyConverter) { + propertyConverterManager.register(typeToConvert, propertyConverter); + } + + @Override + public Map<Class<?>, List<PropertyConverter<?>>> getPropertyConverters() { + return propertyConverterManager.getPropertyConverters(); + } + + @Override + public <T> List<PropertyConverter<T>> getPropertyConverters(Class<T> targetType) { + return propertyConverterManager.getPropertyConverters(targetType); + } + + @Override + public List<PropertyFilter> getPropertyFilters() { + return Collections.unmodifiableList(this.propertyFilters); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/8b2cc9b1/core/src/main/java/org/apache/tamaya/core/internal/DefaultServiceContext.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/tamaya/core/internal/DefaultServiceContext.java b/core/src/main/java/org/apache/tamaya/core/internal/DefaultServiceContext.java new file mode 100644 index 0000000..e86ca17 --- /dev/null +++ b/core/src/main/java/org/apache/tamaya/core/internal/DefaultServiceContext.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tamaya.core.internal; + +import org.apache.tamaya.spi.ServiceContext; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.ServiceLoader; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Supplier; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * This class implements the (default) {@link org.apache.tamaya.spi.ServiceContext} interface and hereby uses the JDK + * {@link java.util.ServiceLoader} to load the services required. + */ +public final class DefaultServiceContext implements ServiceContext { + /** List current services loaded, per class. */ + private final ConcurrentHashMap<Class, List<Object>> servicesLoaded = new ConcurrentHashMap<>(); + /** Singletons. */ + private final Map<Class, Optional<?>> singletons = new ConcurrentHashMap<>(); + + @Override + public <T> Optional<T> getService(Class<T> serviceType) { + Optional<T> cached = Optional.class.cast(singletons.get(serviceType)); + if(cached==null) { + List<? extends T> services = getServices(serviceType); + if (services.isEmpty()) { + cached = Optional.empty(); + } + else{ + cached = Optional.of(services.get(0)); + } + singletons.put(serviceType, cached); + } + return cached; + } + + /** + * Loads and registers services. + * + * @param serviceType + * The service type. + * @param <T> + * the concrete type. + * @return the items found, never {@code null}. + */ + @Override + public <T> List<T> getServices(final Class<T> serviceType) { + List<T> found = List.class.cast(servicesLoaded.get(serviceType)); + if (found != null) { + return found; + } + List<T> services = new ArrayList<>(); + try { + for (T t : ServiceLoader.load(serviceType)) { + services.add(t); + } + services = Collections.unmodifiableList(services); + } catch (Exception e) { + Logger.getLogger(DefaultServiceContext.class.getName()).log(Level.WARNING, + "Error loading services current type " + serviceType, e); + } + final List<T> previousServices = List.class.cast(servicesLoaded.putIfAbsent(serviceType, (List<Object>)services)); + return previousServices != null ? previousServices : services; + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/8b2cc9b1/core/src/main/java/org/apache/tamaya/core/internal/resource/DefaultResourceLoader.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/tamaya/core/internal/resource/DefaultResourceLoader.java b/core/src/main/java/org/apache/tamaya/core/internal/resource/DefaultResourceLoader.java new file mode 100644 index 0000000..c65be65 --- /dev/null +++ b/core/src/main/java/org/apache/tamaya/core/internal/resource/DefaultResourceLoader.java @@ -0,0 +1,94 @@ +package org.apache.tamaya.core.internal.resource; + +import org.apache.tamaya.core.resources.Resource; +import org.apache.tamaya.core.resources.ResourceLoader; + +import javax.annotation.Priority; +import java.io.File; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Enumeration; +import java.util.List; +import java.util.WeakHashMap; +import java.util.logging.Logger; + +/** + * Simple default implementation of the resource loader. + */ +@Priority(0) +public class DefaultResourceLoader implements ResourceLoader{ + + private static final Logger LOG = Logger.getLogger(DefaultResourceLoader.class.getName()); + + private WeakHashMap<ClassLoader, PathMatchingResourcePatternResolver> resourceLoaders = new WeakHashMap<>(); + + @Override + public List<Resource> getResources(ClassLoader classLoader, Collection<String> expressions) { + List<Resource> resources = new ArrayList<>(); + for(String expression:expressions){ + if(tryClassPath(classLoader, expression, resources) || tryFile(expression, resources) || tryURL(expression, resources) + || tryAntPath(classLoader, expression, resources)){ + continue; + } + LOG.warning("Failed to resolve resource: " + expression); + } + return resources; + } + + private boolean tryClassPath(ClassLoader classLoader, String expression, List<Resource> resources) { + try{ + Enumeration<URL> urls = classLoader.getResources(expression); + while(urls.hasMoreElements()){ + URL url = urls.nextElement(); + resources.add(new UrlResource(url)); + } + return !resources.isEmpty(); + } + catch(Exception e){ + LOG.finest(() -> "Failed to load resource from CP: " + expression); + } + return false; + } + + private boolean tryFile(String expression, List<Resource> resources) { + try{ + File file = new File(expression); + if(file.exists()) { + resources.add(new FileSystemResource(file)); + return true; + } + } + catch(Exception e){ + LOG.finest(() -> "Failed to load resource from file: " + expression); + } + return false; + } + + private boolean tryURL(String expression, List<Resource> resources) { + try{ + URL url = new URL(expression); + resources.add(new UrlResource(url)); + return true; + } + catch(Exception e){ + LOG.finest(() -> "Failed to load resource from file: " + expression); + } + return false; + + } + + private boolean tryAntPath(ClassLoader classLoader, String expression, List<Resource> resources) { + PathMatchingResourcePatternResolver loader = resourceLoaders.computeIfAbsent(classLoader, cl -> new PathMatchingResourcePatternResolver(cl)); + try{ + resources.addAll(Arrays.asList(loader.getResources(expression))); + return !resources.isEmpty(); + } + catch(Exception e){ + LOG.finest(() -> "Failed to load resources from pattern: " + expression); + } + return false; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/8b2cc9b1/core/src/main/resources/META-INF/services/org.apache.tamaya.Configuration ---------------------------------------------------------------------- diff --git a/core/src/main/resources/META-INF/services/org.apache.tamaya.Configuration b/core/src/main/resources/META-INF/services/org.apache.tamaya.Configuration new file mode 100644 index 0000000..0db8402 --- /dev/null +++ b/core/src/main/resources/META-INF/services/org.apache.tamaya.Configuration @@ -0,0 +1,19 @@ +# +# 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.core.internal.DefaultConfiguration \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/8b2cc9b1/core/src/main/resources/META-INF/services/org.apache.tamaya.core.resources.ResourceLoader ---------------------------------------------------------------------- diff --git a/core/src/main/resources/META-INF/services/org.apache.tamaya.core.resources.ResourceLoader b/core/src/main/resources/META-INF/services/org.apache.tamaya.core.resources.ResourceLoader new file mode 100644 index 0000000..08c9577 --- /dev/null +++ b/core/src/main/resources/META-INF/services/org.apache.tamaya.core.resources.ResourceLoader @@ -0,0 +1,19 @@ +# +# 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.core.internal.resource.DefaultResourceLoader \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/8b2cc9b1/core/src/main/resources/META-INF/services/org.apache.tamaya.spi.ConfigurationContext ---------------------------------------------------------------------- diff --git a/core/src/main/resources/META-INF/services/org.apache.tamaya.spi.ConfigurationContext b/core/src/main/resources/META-INF/services/org.apache.tamaya.spi.ConfigurationContext new file mode 100644 index 0000000..32b4302 --- /dev/null +++ b/core/src/main/resources/META-INF/services/org.apache.tamaya.spi.ConfigurationContext @@ -0,0 +1,19 @@ +# +# 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.core.internal.DefaultConfigurationContext \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/8b2cc9b1/core/src/main/resources/META-INF/services/org.apache.tamaya.spi.ServiceContext ---------------------------------------------------------------------- diff --git a/core/src/main/resources/META-INF/services/org.apache.tamaya.spi.ServiceContext b/core/src/main/resources/META-INF/services/org.apache.tamaya.spi.ServiceContext new file mode 100644 index 0000000..2721eff --- /dev/null +++ b/core/src/main/resources/META-INF/services/org.apache.tamaya.spi.ServiceContext @@ -0,0 +1,19 @@ +# +# 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.core.internal.DefaultServiceContext \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/8b2cc9b1/core/src/test/java/org/apache/tamaya/core/ConfigurationTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/tamaya/core/ConfigurationTest.java b/core/src/test/java/org/apache/tamaya/core/ConfigurationTest.java new file mode 100644 index 0000000..9c7b894 --- /dev/null +++ b/core/src/test/java/org/apache/tamaya/core/ConfigurationTest.java @@ -0,0 +1,53 @@ +/* + * 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; + +import org.apache.tamaya.Configuration; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +/** + * This tests checks if the combination of 2 prioritized PropertySource return valid results on the final Configuration. + */ +public class ConfigurationTest { + + @Test + public void testAccess(){ + assertNotNull(Configuration.current()); + } + + @Test + public void testContent(){ + assertEquals("Robin", Configuration.current().get("name").get()); + assertEquals("Sabine", Configuration.current().get("name2").get()); // from default + assertEquals("Lukas", Configuration.current().get("name3").get()); // oderridden default + assertEquals("Sereina", Configuration.current().get("name4").get()); // final only + assertEquals("Benjamin", Configuration.current().get("name5").get()); // final only + + System.out.println("name : " + Configuration.current().get("name").get()); + System.out.println("name2: " + Configuration.current().get("name2").get()); + System.out.println("name3: " + Configuration.current().get("name3").get()); + System.out.println("name4: " + Configuration.current().get("name4").get()); + System.out.println("name5: " + Configuration.current().get("name5").get()); + } + + +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/8b2cc9b1/core/src/test/java/org/apache/tamaya/core/testdata/TestPropertyDefaultSourceProvider.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/tamaya/core/testdata/TestPropertyDefaultSourceProvider.java b/core/src/test/java/org/apache/tamaya/core/testdata/TestPropertyDefaultSourceProvider.java new file mode 100644 index 0000000..ebd28f7 --- /dev/null +++ b/core/src/test/java/org/apache/tamaya/core/testdata/TestPropertyDefaultSourceProvider.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tamaya.core.testdata; + +import org.apache.tamaya.core.PathBasedPropertySourceProvider; +import org.apache.tamaya.core.formats.PropertiesFormat; + +/** + * Test provider reading properties from classpath:cfg/defaults/**.properties. + */ +public class TestPropertyDefaultSourceProvider extends PathBasedPropertySourceProvider{ + + public TestPropertyDefaultSourceProvider() { + super("default-testdata-properties", PropertiesFormat.of(100), "classpath:cfg/defaults/**/*.properties"); + } +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/8b2cc9b1/core/src/test/resources/META-INF/services/org.apache.tamaya.spi.PropertySourceProvider ---------------------------------------------------------------------- diff --git a/core/src/test/resources/META-INF/services/org.apache.tamaya.spi.PropertySourceProvider b/core/src/test/resources/META-INF/services/org.apache.tamaya.spi.PropertySourceProvider new file mode 100644 index 0000000..e61641c --- /dev/null +++ b/core/src/test/resources/META-INF/services/org.apache.tamaya.spi.PropertySourceProvider @@ -0,0 +1,20 @@ +# +# 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. +# +testdata.TestPropertyDefaultSourceProvider +testdata.TestPropertySourceProvider \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/8b2cc9b1/core/src/test/resources/cfg/defaults/test1.properties ---------------------------------------------------------------------- diff --git a/core/src/test/resources/cfg/defaults/test1.properties b/core/src/test/resources/cfg/defaults/test1.properties new file mode 100644 index 0000000..17a854d --- /dev/null +++ b/core/src/test/resources/cfg/defaults/test1.properties @@ -0,0 +1,20 @@ +# +# 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. +# +name=Anatole +name2=Sabine \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/8b2cc9b1/core/src/test/resources/cfg/final/anotherTestFile.properties ---------------------------------------------------------------------- diff --git a/core/src/test/resources/cfg/final/anotherTestFile.properties b/core/src/test/resources/cfg/final/anotherTestFile.properties new file mode 100644 index 0000000..9e405f6 --- /dev/null +++ b/core/src/test/resources/cfg/final/anotherTestFile.properties @@ -0,0 +1,22 @@ +# +# 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. +# +name=Robin +name3=Lukas +name4=Sereina +name5=Benjamin \ No newline at end of file