2017-11-25

Tamaya Resources (Extension Module)

Tamaya Resources is an extension module. Refer to the extensions documentation for further details.

What functionality this module provides ?

Tamaya Resources defines some additional tools to locate resources in your classpath or file system based on descriptive ant-styled resource patterns.

Compatibility

The module is based on Java 7, so it can be used with Java 7 and beyond.

Installation

To use this module add the following dependency:

<dependency>
  <grooupId>org.apache.tamaya.ext</groupId>
  <artifactId>tamaya-resources</artifactId>
  <version>0.4-incubating-SNAPSHOT</version>
</dependency>

Usage

The module’s main entry point is the singleton class org.apache.tamaya.resource.ConfigResources. This class provides access to a ResourceResolver instance:

ResourceResolver resolver = ConfigResources.getResourceResolver();
public interface ResourceResolver {
    Collection<URL> getResources(Collection<String> expressions) {...}
    Collection<URL> getResources(String... expressions) {...}
    Collection<URL> getResources(ClassLoader classLoader, String... expressions){...}
    Collection<URL> getResources(ClassLoader classLoader, Collection<String> expressions);
}

Hereby the methods allow to resolve expressions to a collection of URLs. In case the expression is also targeting the current classpath the target ClassLoader to be used can be passed additionally.

The default implementation provides resource resolution mechanism similar to the functionality offered by Spring. So by default resources can be looked up

  • from files

  • from the classpath

  • optionally ant-styled expressions can be used.

Examples

There are numerous ways how a resource pattern can be defined. Following the most important variants are listed:

// explicitly searching the file system
file:myroot/aa?a/*.file
file:myroot/b*/b?/*.file
file:myroot/**/*.file

// explicitly searching the classpath
classpath:myroot/**/*.file
classpath:javax/annotation/*.class
classpath:javax/**/sql/*.class
classpath:javax/annotation/**/R*.class
classpath:javax/annotation/R?so*.class
classpath:META-INF/maven/org.apache.geronimo.specs/**/*

// search both classpath and files
javax/annotation/*.class
javax/**/sql/*.class
javax/annotation/**/R*.class
javax/annotation/R?so*.class
META-INF/maven/org.apache.geronimo.specs/**/*
myroot/**/*.file
myroot/aa?a/*.file
myroot/b*/b?/*.file

Summarizing the resources module provides useful functionality that helps to locate resources on the file system and in the classpath. This can be used to implement PropertySourceProvider implementations that are based on corresponding resource path patterns instead of concrete files.

Overall Usage Example

Given the functionality we can easily implement a PropertySourceProvider that reads all files from a classpath location, hereby traversing down all folders:

public class PathBasedPropertySourceProvider implements PropertySourceProvider {

    @Override
    public Collection<PropertySource> getPropertySources() {
        List<PropertySource> propertySources = new ArrayList<>();
        Collection<URL> resources = ConfigResources.getResourceResolver().getResources("META-INF/cfg/**/*.properties");
        for(URL url:resources){
            Properties props = new Properties();
            try(InputStream is = url.openStream()){
                props.load(is);
                propertySources.add(new PropertiesBasedPropertySource(url.toString(), props));
            }
            catch(Exception e){
                e.printStackTrace();
            }
        }

        return propertySources;
    }

    private final static class PropertiesBasedPropertySource implements PropertySource {
        private String name;
        private Map<String,String> properties = new HashMap<>();

        public PropertiesBasedPropertySource(String name, Properties props) {
            this.name = name;
            props.forEach((k,v) -> this.properties.put(k.toString(), v.toString()));
        }

        @Override
        public String getName() {
            return name;
        }

        @Override
        public String get(String key) {
            return properties.get(key);
        }

        @Override
        public Map<String, String> getProperties() {
            return properties;
        }
    }
}

SPI

The ResourceResolver that is returned by the ConfigResources singleton is determined by the current ServiceContext, by default you can replace the default implementation by registering an alternate implementation with an overriding @Priority annotation added using the ServiceLoader.

Additionally a BaseResourceResolver class can be used to reduce the amount of code to be written on your own.