# Apache Tamaya — Extension: Resources

## Tamaya Resources (Extension Module)

### Overview

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

Tamaya Resources defines some additional tools to locate resources in your classpath or file system based on descriptive ant-styled resource patterns. To use this module add the following dependency:

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

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.

### Valid Expression 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 = Resources.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.