Repository: incubator-tamaya
Updated Branches:
  refs/heads/master 2dd0c13e5 -> c48c5794e


TAMAYA-43: Implemented ant pattern based resource lookup for files and 
classpath, about 20k compiled size overall.
TAMAYA-43: Removed Resource abstraction in favor of URL.


Project: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/commit/ae66299e
Tree: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/tree/ae66299e
Diff: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/diff/ae66299e

Branch: refs/heads/master
Commit: ae66299e25b41167008021ffe95cad236f6e2bd3
Parents: 2dd0c13
Author: anatole <anat...@apache.org>
Authored: Wed Jan 7 22:49:39 2015 +0100
Committer: anatole <anat...@apache.org>
Committed: Sun Jan 11 01:40:57 2015 +0100

----------------------------------------------------------------------
 .../tamaya/format/ConfigurationFormat.java      |  10 +-
 .../apache/tamaya/format/PropertiesFormat.java  |  15 +-
 .../tamaya/format/PropertiesXmlFormat.java      |  15 +-
 ...AbstractPathBasedPropertySourceProvider.java |   7 +-
 .../AbstractResourcePropertySourceProvider.java |  17 +-
 .../org/apache/tamaya/resource/Resource.java    | 115 --------
 .../tamaya/resource/ResourceResolver.java       |  25 +-
 .../resource/internal/ClassPathResource.java    | 187 -------------
 .../resource/internal/ClasspathCollector.java   | 264 +++++++++++++++++++
 .../internal/DefaultResourceResolver.java       |  61 ++++-
 .../tamaya/resource/internal/FileCollector.java | 157 +++++++++++
 .../tamaya/resource/internal/FileResource.java  | 172 ------------
 .../resource/internal/InputStreamResource.java  | 117 --------
 .../tamaya/resource/internal/Locator.java       | 150 +++++++++++
 .../tamaya/resource/internal/UrlResource.java   | 140 ----------
 15 files changed, 671 insertions(+), 781 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/ae66299e/modules/formats/src/main/java/org/apache/tamaya/format/ConfigurationFormat.java
----------------------------------------------------------------------
diff --git 
a/modules/formats/src/main/java/org/apache/tamaya/format/ConfigurationFormat.java
 
b/modules/formats/src/main/java/org/apache/tamaya/format/ConfigurationFormat.java
index 4a1e06f..924fa7c 100644
--- 
a/modules/formats/src/main/java/org/apache/tamaya/format/ConfigurationFormat.java
+++ 
b/modules/formats/src/main/java/org/apache/tamaya/format/ConfigurationFormat.java
@@ -21,9 +21,8 @@ package org.apache.tamaya.format;
 import org.apache.tamaya.spi.PropertySource;
 
 import java.io.IOException;
-import java.io.InputStream;
+import java.net.URL;
 import java.util.Collection;
-import java.util.function.Supplier;
 
 /**
  * Implementations current this class encapsulate the mechanism how to read a
@@ -44,12 +43,11 @@ public interface ConfigurationFormat {
      * ladder case multiple PropertySources can be returned, each one with its 
own ordinal and the corresponding
      * entries.
      *
-     * @param sourceName name to be used for constructing a useful name for 
the created
-     *                   {@link org.apache.tamaya.spi.PropertySource} 
instances.
-     * @param streamSupplier   the resource represented by a supplier of 
InputStream, not null
+     * @param url the url to read the configuration data from (could be a 
file, a remote location, a classpath
+     *            resource or something else.
      * @return the corresponding {@link org.apache.tamaya.spi.PropertySource} 
instances, never {@code null}.
      */
-    Collection<PropertySource> readConfiguration(String sourceName, 
Supplier<InputStream> streamSupplier)
+    Collection<PropertySource> readConfiguration(URL url)
             throws IOException;
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/ae66299e/modules/formats/src/main/java/org/apache/tamaya/format/PropertiesFormat.java
----------------------------------------------------------------------
diff --git 
a/modules/formats/src/main/java/org/apache/tamaya/format/PropertiesFormat.java 
b/modules/formats/src/main/java/org/apache/tamaya/format/PropertiesFormat.java
index 34c9e21..a49e492 100644
--- 
a/modules/formats/src/main/java/org/apache/tamaya/format/PropertiesFormat.java
+++ 
b/modules/formats/src/main/java/org/apache/tamaya/format/PropertiesFormat.java
@@ -21,6 +21,7 @@ package org.apache.tamaya.format;
 import org.apache.tamaya.spi.PropertySource;
 
 import java.io.InputStream;
+import java.net.URL;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -28,7 +29,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Properties;
-import java.util.function.Supplier;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -70,10 +70,15 @@ public class PropertiesFormat implements 
ConfigurationFormat {
 
     @SuppressWarnings("unchecked")
     @Override
-    public Collection<PropertySource> readConfiguration(String sourceName, 
Supplier<InputStream> streamSupplier) {
-        final String name = "Properties(" + Objects.requireNonNull(sourceName) 
+ ')';
+    public Collection<PropertySource> readConfiguration(URL url) {
+        final String name;
+        if (Objects.requireNonNull(url).getQuery() == null) {
+            name = "Properties(" + Objects.requireNonNull(url).toString() + 
')';
+        } else {
+            name = Objects.requireNonNull(url).getQuery();
+        }
         List<PropertySource> propertySources = new ArrayList<>();
-        try (InputStream is = streamSupplier.get()) {
+        try (InputStream is = url.openStream()) {
             if (is != null) {
                 final Properties p = new Properties();
                 p.load(is);
@@ -101,7 +106,7 @@ public class PropertiesFormat implements 
ConfigurationFormat {
                 return propertySources;
             }
         } catch (Exception e) {
-            LOG.log(Level.FINEST, e, () -> "Failed to read config from 
resource: " + sourceName);
+            LOG.log(Level.FINEST, e, () -> "Failed to read config from 
resource: " + url);
         }
         return Collections.emptyList();
     }

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/ae66299e/modules/formats/src/main/java/org/apache/tamaya/format/PropertiesXmlFormat.java
----------------------------------------------------------------------
diff --git 
a/modules/formats/src/main/java/org/apache/tamaya/format/PropertiesXmlFormat.java
 
b/modules/formats/src/main/java/org/apache/tamaya/format/PropertiesXmlFormat.java
index 8b3468b..ddfe723 100644
--- 
a/modules/formats/src/main/java/org/apache/tamaya/format/PropertiesXmlFormat.java
+++ 
b/modules/formats/src/main/java/org/apache/tamaya/format/PropertiesXmlFormat.java
@@ -21,6 +21,7 @@ package org.apache.tamaya.format;
 import org.apache.tamaya.spi.PropertySource;
 
 import java.io.InputStream;
+import java.net.URL;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -28,7 +29,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Properties;
-import java.util.function.Supplier;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -71,10 +71,15 @@ public class PropertiesXmlFormat implements 
ConfigurationFormat {
 
     @SuppressWarnings("unchecked")
     @Override
-    public Collection<PropertySource> readConfiguration(String source, 
Supplier<InputStream> streamSupplier) {
-        final String name = "XML-Properties:" + Objects.requireNonNull(source) 
+ ')';
+    public Collection<PropertySource> readConfiguration(URL url) {
+        final String name;
+        if (Objects.requireNonNull(url).getQuery() == null) {
+            name = "XML-Properties(" + Objects.requireNonNull(url).toString() 
+ ')';
+        } else {
+            name = Objects.requireNonNull(url).getQuery();
+        }
         List<PropertySource> propertySources = new ArrayList<>();
-        try (InputStream is = streamSupplier.get()) {
+        try (InputStream is = url.openStream()) {
             if (is != null) {
                 final Properties p = new Properties();
                 p.loadFromXML(is);
@@ -102,7 +107,7 @@ public class PropertiesXmlFormat implements 
ConfigurationFormat {
                 return propertySources;
             }
         } catch (Exception e) {
-            LOG.log(Level.FINEST, e, () -> "Failed to read config from 
resource: " + source);
+            LOG.log(Level.FINEST, e, () -> "Failed to read config from 
resource: " + url);
         }
         return Collections.emptyList();
     }

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/ae66299e/modules/resources/src/main/java/org/apache/tamaya/resource/AbstractPathBasedPropertySourceProvider.java
----------------------------------------------------------------------
diff --git 
a/modules/resources/src/main/java/org/apache/tamaya/resource/AbstractPathBasedPropertySourceProvider.java
 
b/modules/resources/src/main/java/org/apache/tamaya/resource/AbstractPathBasedPropertySourceProvider.java
index c4c5651..58acba3 100644
--- 
a/modules/resources/src/main/java/org/apache/tamaya/resource/AbstractPathBasedPropertySourceProvider.java
+++ 
b/modules/resources/src/main/java/org/apache/tamaya/resource/AbstractPathBasedPropertySourceProvider.java
@@ -23,6 +23,7 @@ import org.apache.tamaya.spi.PropertySource;
 import org.apache.tamaya.spi.PropertySourceProvider;
 import org.apache.tamaya.spi.ServiceContext;
 
+import java.net.URL;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -75,13 +76,13 @@ public abstract class 
AbstractPathBasedPropertySourceProvider implements Propert
     public Collection<PropertySource> getPropertySources() {
         List<PropertySource> propertySources = new ArrayList<>();
         paths.forEach((path) -> {
-            for (Resource res : 
ServiceContext.getInstance().getService(ResourceResolver.class).get().getResources(path))
 {
+            for (URL res : 
ServiceContext.getInstance().getService(ResourceResolver.class).get().getResources(path))
 {
                 try {
                     for (ConfigurationFormat format : configFormats) {
-                        
propertySources.addAll(format.readConfiguration(sourceName, res));
+                        propertySources.addAll(format.readConfiguration(res));
                     }
                 } catch (Exception e) {
-                    LOG.log(Level.WARNING, "Failed to add resource based 
config: " + res.getName(), e);
+                    LOG.log(Level.WARNING, "Failed to add resource based 
config: " + res, e);
                 }
             }
         });

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/ae66299e/modules/resources/src/main/java/org/apache/tamaya/resource/AbstractResourcePropertySourceProvider.java
----------------------------------------------------------------------
diff --git 
a/modules/resources/src/main/java/org/apache/tamaya/resource/AbstractResourcePropertySourceProvider.java
 
b/modules/resources/src/main/java/org/apache/tamaya/resource/AbstractResourcePropertySourceProvider.java
index 6edba5b..f1ec885 100644
--- 
a/modules/resources/src/main/java/org/apache/tamaya/resource/AbstractResourcePropertySourceProvider.java
+++ 
b/modules/resources/src/main/java/org/apache/tamaya/resource/AbstractResourcePropertySourceProvider.java
@@ -22,6 +22,7 @@ import org.apache.tamaya.format.ConfigurationFormat;
 import org.apache.tamaya.spi.PropertySource;
 import org.apache.tamaya.spi.PropertySourceProvider;
 
+import java.net.URL;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -39,25 +40,25 @@ public abstract class 
AbstractResourcePropertySourceProvider implements Property
     /** The supported formats. */
     private List<ConfigurationFormat> formats = new ArrayList<>();
     /** The resource. */
-    private Resource resource;
+    private URL resource;
     /** The source name used for creating the PropertySource names. */
     private String sourceName;
 
     /**
      * Creates a new instance.
-     * @param resource the {@link Resource}, not null.
+     * @param resource the {@link URL}, not null.
      * @param formats the supported formats, not empty.
      */
-    public AbstractResourcePropertySourceProvider(String sourceName, Resource 
resource, ConfigurationFormat... formats) {
+    public AbstractResourcePropertySourceProvider(String sourceName, URL 
resource, ConfigurationFormat... formats) {
         this(sourceName, resource, Arrays.asList(formats));
     }
 
     /**
      * Creates a new instance.
-     * @param resource the {@link Resource}, not null.
+     * @param resource the {@link URL}, not null.
      * @param formats the supported formats, not empty.
      */
-    public AbstractResourcePropertySourceProvider(String sourceName, Resource 
resource, List<ConfigurationFormat> formats) {
+    public AbstractResourcePropertySourceProvider(String sourceName, URL 
resource, List<ConfigurationFormat> formats) {
         this.resource = Objects.requireNonNull(resource);
         this.sourceName = Objects.requireNonNull(sourceName);
         if(formats.size()==0){
@@ -72,7 +73,7 @@ public abstract class AbstractResourcePropertySourceProvider 
implements Property
      *
      * @return the underlying resource, never null.
      */
-    public Resource getResource() {
+    public URL getResource() {
         return this.resource;
     }
 
@@ -90,9 +91,9 @@ public abstract class AbstractResourcePropertySourceProvider 
implements Property
         List<PropertySource> propertySources = new ArrayList<>();
         for (ConfigurationFormat format : formats) {
             try {
-                propertySources.addAll(format.readConfiguration(sourceName, 
resource));
+                propertySources.addAll(format.readConfiguration(resource));
             } catch (Exception e) {
-                LOG.info(() -> "Format was not matching: " + format + " for 
resource: " + resource.getName());
+                LOG.info(() -> "Format was not matching: " + format + " for 
resource: " + resource);
             }
         }
         return propertySources;

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/ae66299e/modules/resources/src/main/java/org/apache/tamaya/resource/Resource.java
----------------------------------------------------------------------
diff --git 
a/modules/resources/src/main/java/org/apache/tamaya/resource/Resource.java 
b/modules/resources/src/main/java/org/apache/tamaya/resource/Resource.java
deleted file mode 100644
index 39e34e9..0000000
--- a/modules/resources/src/main/java/org/apache/tamaya/resource/Resource.java
+++ /dev/null
@@ -1,115 +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.resource;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URI;
-import java.util.Objects;
-import java.util.function.Supplier;
-
-/**
- * Interface for an abstract resource. The effective resource implementation 
can be completely arbitrary.
- * By default files, classpath format and URLs are supported, but alternate 
implementations are possible.
- *
- * @see #get()
- * @see #toURI()
- */
-public interface Resource extends Supplier<InputStream> {
-
-    /**
-     * Return whether this resource actually exists. Depending on the resource 
this can delegate to
-     * {@link java.io.File#exists()} or whatever may be appropriate to check 
accessibility of the resource.
-     */
-    default boolean exists() {
-        // Try to open a file first, if that fails try to open the stream...
-        try {
-            return new File(toURI()).exists();
-        } catch (IOException ex) {
-            // Fallback
-            try {
-                InputStream is = get();
-                is.close();
-                return true;
-            } catch (Exception e) {
-                // ignore, just return false for non existing
-                return false;
-            }
-        }
-    }
-
-    /**
-     * Checks whether the resource is accessible, meaning {@link #get()} 
should return a InputStream for reading the
-     * resource's content.
-     *
-     * @see #get()
-     */
-    default boolean isAccessible() {
-        return true;
-    }
-
-    /**
-     * Returns the resource as an URI.
-     *
-     * @throws IOException if the resource cannot be resolved as URI.
-     */
-    URI toURI() throws IOException;
-
-    /**
-     * Determines the length for this resource.
-     *
-     * @throws IOException if the resource is not readable.
-     */
-    default long length() throws IOException {
-        try(InputStream is = this.get();) {
-            Objects.requireNonNull(is, "resource not available");
-            long length = 0;
-            byte[] buf = new byte[256];
-            int bytesRead;
-            while ((bytesRead = is.read(buf)) > 0) {
-                length += bytesRead;
-            }
-            return length;
-        }
-    }
-
-    /**
-     * Determine the last-modified timestamp for a resource, as UTC ms 
timestamp
-     *
-     * @throws IOException if the resource is not accessible.
-     */
-    default long lastModified() throws IOException{
-        return new File(toURI()).lastModified();
-    }
-
-    /**
-     * Get a name for the resource. The name should be identifying the 
resource and also
-     * never change, so it must be eligible for hashcode/equals 
implementations.
-     */
-    default String getName() {
-        try {
-            return toURI().toString();
-        } catch (Exception e) {
-            return toString();
-        }
-    }
-
-
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/ae66299e/modules/resources/src/main/java/org/apache/tamaya/resource/ResourceResolver.java
----------------------------------------------------------------------
diff --git 
a/modules/resources/src/main/java/org/apache/tamaya/resource/ResourceResolver.java
 
b/modules/resources/src/main/java/org/apache/tamaya/resource/ResourceResolver.java
index 7901ca6..31856cf 100644
--- 
a/modules/resources/src/main/java/org/apache/tamaya/resource/ResourceResolver.java
+++ 
b/modules/resources/src/main/java/org/apache/tamaya/resource/ResourceResolver.java
@@ -18,6 +18,7 @@
  */
 package org.apache.tamaya.resource;
 
+import java.net.URL;
 import java.util.Arrays;
 import java.util.Collection;
 
@@ -28,16 +29,16 @@ import java.util.Collection;
 public interface ResourceResolver {
 
     /**
-     * Resolves resource expressions to a list of {@link Resource}s. Hereby
+     * Resolves resource expressions to a list of {@link URL}s. Hereby
      * the ordering of format matches the input of the resolved expressions. 
Nevertheless be aware that
      * there is no determined ordering of format located within a classloader.
      *
      * @param expressions the expressions to be resolved, not empty.
-     * @return the corresponding collection of current {@link Resource}s 
found, never
+     * @return the corresponding collection of current {@link URL}s found, 
never
      * null.
      * .
      */
-    default Collection<Resource> getResources(Collection<String> expressions) {
+    default Collection<URL> getResources(Collection<String> expressions) {
         ClassLoader cl = Thread.currentThread().getContextClassLoader();
         if (cl == null) {
             cl = getClass().getClassLoader();
@@ -46,45 +47,45 @@ public interface ResourceResolver {
     }
 
     /**
-     * Resolves resource expressions to a list of {@link Resource}s. Hereby
+     * Resolves resource expressions to a list of {@link URL}s. Hereby
      * the ordering of format matches the input of the resolved expressions. 
Nevertheless be aware that
      * there is no determined ordering of format located within a classloader.
      *
      * @param expressions the expressions to be resolved, not empty.
-     * @return the corresponding collection of current {@link Resource}s 
found, never
+     * @return the corresponding collection of current {@link URL}s found, 
never
      * null.
      * .
      */
-    default Collection<Resource> getResources(String... expressions) {
+    default Collection<URL> getResources(String... expressions) {
         return getResources(Arrays.asList(expressions));
     }
 
     /**
-     * Resolves resource expressions to a list of {@link Resource}s, 
considerubg
+     * Resolves resource expressions to a list of {@link URL}s, considerubg
      * the given classloader for classloader dependent format. Hereby
      * the ordering of format matches the input of the resolved expressions. 
Nevertheless be aware that
      * there is no determined ordering of format located within a classloader.
      *
      * @param expressions the expressions to be resolved, not empty.
-     * @return the corresponding collection of current {@link Resource}s 
found, never
+     * @return the corresponding collection of current {@link URL}s found, 
never
      * null.
      * .
      */
-    default Collection<Resource> getResources(ClassLoader classLoader, 
String... expressions){
+    default Collection<URL> getResources(ClassLoader classLoader, String... 
expressions){
         return getResources(classLoader, Arrays.asList(expressions));
     }
 
     /**
-     * Resolves resource expressions to a list of {@link Resource}s, 
considerubg
+     * Resolves resource expressions to a list of {@link URL}s, considerubg
      * the given classloader for classloader dependent format. Hereby
      * the ordering of format matches the input of the resolved expressions. 
Nevertheless be aware that
      * there is no determined ordering of format located within a classloader.
      *
      * @param expressions the expressions to be resolved, not empty.
-     * @return the corresponding collection of current {@link Resource}s 
found, never
+     * @return the corresponding collection of current {@link URL}s found, 
never
      * null.
      * .
      */
-    Collection<Resource> getResources(ClassLoader classLoader, 
Collection<String> expressions);
+    Collection<URL> getResources(ClassLoader classLoader, Collection<String> 
expressions);
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/ae66299e/modules/resources/src/main/java/org/apache/tamaya/resource/internal/ClassPathResource.java
----------------------------------------------------------------------
diff --git 
a/modules/resources/src/main/java/org/apache/tamaya/resource/internal/ClassPathResource.java
 
b/modules/resources/src/main/java/org/apache/tamaya/resource/internal/ClassPathResource.java
deleted file mode 100644
index b901164..0000000
--- 
a/modules/resources/src/main/java/org/apache/tamaya/resource/internal/ClassPathResource.java
+++ /dev/null
@@ -1,187 +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.resource.internal;
-
-import org.apache.tamaya.resource.Resource;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.util.Objects;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-/**
- * Implementation of {@link Resource} to be loaded from the classpath.
- */
-public class ClassPathResource implements Resource {
-
-    private static final Logger LOG = 
Logger.getLogger(ClassPathResource.class.getName());
-
-    private final String path;
-
-    private ClassLoader classLoader;
-
-
-    /**
-     * Create a new resource using the current context class loader.
-     *
-     * @param path the resource path, not null
-     * @see java.lang.ClassLoader#getResourceAsStream(String)
-     */
-    public ClassPathResource(String path) {
-        this(path, (ClassLoader) null);
-    }
-
-    /**
-     * Create a new resource using the given class loader.
-     *
-     * @param path        the resource path, not null
-     * @param classLoader the class loader to load the resource with,
-     *                    or {@code null} for the current context class loader
-     * @see ClassLoader#getResourceAsStream(String)
-     */
-    public ClassPathResource(String path, ClassLoader classLoader) {
-        Objects.requireNonNull(path, "Path null");
-        if (path.startsWith("/")) {
-            path = path.substring(1);
-        }
-        this.path = path.trim();
-        if (classLoader == null) {
-            classLoader = Thread.currentThread().getContextClassLoader();
-        }
-        if (classLoader == null) {
-            classLoader = getClass().getClassLoader();
-        }
-        this.classLoader = classLoader;
-    }
-
-    /**
-     * @return the path for this resource.
-     */
-    public final String getPath() {
-        return this.path;
-    }
-
-    /**
-     * @return the ClassLoader that this resource will be accessed from.
-     */
-    public final ClassLoader getClassLoader() {
-        return this.classLoader;
-    }
-
-
-    /**
-     * Checks if the given resource is resolvable from the configured 
classloader.
-     *
-     * @see java.lang.ClassLoader#getResource(String)
-     */
-    @Override
-    public boolean exists() {
-        return (resolveURL() != null);
-    }
-
-    /**
-     * Resolves a URL for the underlying class path resource.
-     *
-     * @return the resolved URL, or {@code null}
-     */
-    protected URL resolveURL() {
-        return this.classLoader.getResource(this.path);
-    }
-
-    /**
-     * This implementation opens an InputStream for the given class path 
resource.
-     *
-     * @see java.lang.ClassLoader#getResourceAsStream(String)
-     * @see java.lang.Class#getResourceAsStream(String)
-     */
-    @Override
-    public InputStream get() {
-        try {
-            InputStream is = this.classLoader.getResourceAsStream(this.path);
-            if (is == null) {
-                throw new IOException(getName() + " does not exist");
-            }
-            return is;
-        } catch (IOException e) {
-            LOG.log(Level.INFO, "Failed to open classpath resource: " + path, 
e);
-            return null;
-        }
-    }
-
-    @Override
-    public URI toURI() throws IOException {
-        try {
-            return resolveURL().toURI();
-        } catch (URISyntaxException e) {
-            throw new IOException(e);
-        }
-    }
-
-    @Override
-    public long lastModified() throws IOException {
-        return 0;
-    }
-
-    /**
-     * This implementation returns the name current the file that this class 
path
-     * resource refers to.
-     */
-    @Override
-    public String getName() {
-        return "classpath:" + path;
-    }
-
-    /**
-     * This implementation returns a description that includes the class path 
location.
-     */
-    @Override
-    public String toString() {
-        return "ClassPathResource[" + path + ']';
-    }
-
-    /**
-     * This implementation compares the underlying class path locations.
-     */
-    @Override
-    public boolean equals(Object obj) {
-        if (obj == this) {
-            return true;
-        }
-        if (obj instanceof ClassPathResource) {
-            ClassPathResource otherRes = (ClassPathResource) obj;
-            return (this.path.equals(otherRes.path) &&
-                    Objects.equals(this.classLoader, otherRes.classLoader));
-        }
-        return false;
-    }
-
-    /**
-     * This implementation returns the hash code current the underlying
-     * class path location.
-     */
-    @Override
-    public int hashCode() {
-        return getName().hashCode();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/ae66299e/modules/resources/src/main/java/org/apache/tamaya/resource/internal/ClasspathCollector.java
----------------------------------------------------------------------
diff --git 
a/modules/resources/src/main/java/org/apache/tamaya/resource/internal/ClasspathCollector.java
 
b/modules/resources/src/main/java/org/apache/tamaya/resource/internal/ClasspathCollector.java
new file mode 100644
index 0000000..3f2093b
--- /dev/null
+++ 
b/modules/resources/src/main/java/org/apache/tamaya/resource/internal/ClasspathCollector.java
@@ -0,0 +1,264 @@
+/*
+ * 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.resource.internal;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.JarURLConnection;
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Objects;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Collector that searches files based on ant styled patterns. For example the 
following patterns would be matched:
+ * <pre>
+ *     classpath:javax/annotations/*
+ *     javax?/annotations&#47;**&#47;*.class
+ *     org/apache/tamaya&#47;**&#47;tamayaconfig.properties
+ * </pre>
+ */
+public class ClasspathCollector {
+
+    /**
+     * JAR protocol.
+     */
+    public static final String PROTOCOL_JAR = "jar";
+
+    /**
+     * Separator between JAR file URL and the internal jar file path.
+     */
+    public static final String JAR_URL_SEPARATOR = "!/";
+
+    /**
+     * ZIP protocol.
+     */
+    public static final String PROTOCOL_ZIP = "zip";
+
+    /**
+     * ZIP protocol for a JBoss jar file entry: "vfszip".
+     */
+    public static final String PROTOCOL_VFSZIP = "vfszip";
+
+    /**
+     * URL protocol for an WebSphere jar file: "wsjar".
+     */
+    public static final String PROTOCOL_WSJAR = "wsjar";
+
+    /**
+     * URL protocol for an entry from an OC4J jar.
+     */
+    public static final String PROTOCOL_CODE_SOURCE = "code-source";
+
+    /**
+     * The logger used.
+     */
+    private static final Logger LOG = 
Logger.getLogger(ClasspathCollector.class.getName());
+
+    /**
+     * The classloader used to load the resources.
+     */
+    private ClassLoader classLoader;
+
+    /**
+     * Creates a new instance.
+     *
+     * @param classLoader the class loader to be used, not null.
+     */
+    public ClasspathCollector(ClassLoader classLoader) {
+        this.classLoader = Objects.requireNonNull(classLoader);
+    }
+
+    /**
+     * Collect all classpath resources given the expression.
+     *
+     * @param expression the expression, not null.
+     * @return the resources found.
+     */
+    public Collection<URL> collectFiles(String expression) {
+        if (expression.startsWith("classpath:")) {
+            expression = expression.substring("classpath:".length());
+        }
+        if (expression.startsWith("/")) {
+            expression = expression.substring(1);
+        }
+        Locator locator = Locator.of(expression);
+        List<URL> result = new ArrayList<>();
+        String rootPath = locator.getRootPath();
+        try {
+            Enumeration<URL> rootResources = 
this.classLoader.getResources(rootPath);
+            while (rootResources.hasMoreElements()) {
+                URL resource = rootResources.nextElement();
+                try {
+                    if (isJarFile(resource)) {
+                        result.addAll(doFindPathMatchingJarResources(resource, 
locator.getSubPath()));
+                    } else {
+                        File file = getFile(resource);
+                        
result.addAll(FileCollector.traverseAndSelectFromChildren(file, 
locator.getSubPathTokens(), 0));
+                    }
+                } catch (Exception e) {
+                    LOG.log(Level.SEVERE, "Error locating resources for: " + 
expression, e);
+                }
+            }
+        } catch (IOException e) {
+            LOG.log(Level.SEVERE, "Error locating resources for: " + 
expression, e);
+        }
+        return result;
+    }
+
+
+    /**
+     * Find all resources in jar files that match the given location pattern
+     * via the Ant-style PathMatcher.
+     *
+     * @param rootDirResource the root directory as Resource
+     * @param subPattern      the sub pattern to match (below the root 
directory)
+     * @return the Set of matching Resource instances
+     * @throws java.io.IOException in case of I/O errors
+     * @see java.net.JarURLConnection
+     */
+    protected Collection<URL> doFindPathMatchingJarResources(URL 
rootDirResource, String subPattern)
+            throws IOException, URISyntaxException {
+        subPattern = subPattern.replace("*", ".*").replace("?", 
".?").replace(".*.*", ".*");
+        URLConnection con = rootDirResource.toURI().toURL().openConnection();
+        JarFile jarFile;
+        boolean newJarFile = false;
+        String jarFileUrl;
+        String rootEntryPath;
+
+        if (con instanceof JarURLConnection) {
+            // Should usually be the case for traditional JAR files.
+            JarURLConnection jarCon = (JarURLConnection) con;
+            jarCon.setUseCaches(false);
+            jarFile = jarCon.getJarFile();
+            jarFileUrl = jarCon.getJarFileURL().toExternalForm();
+            JarEntry jarEntry = jarCon.getJarEntry();
+            rootEntryPath = (jarEntry != null ? jarEntry.getName() : "");
+        } else {
+            // No JarURLConnection -> need to resort to URL file parsing.
+            // We'll assume URLs of the format "jar:path!/entry", with the 
protocol
+            // being arbitrary as long as following the entry format.
+            // We'll also handle paths with and without leading "file:" prefix.
+            String urlFile = rootDirResource.toURI().toURL().getFile();
+            int separatorIndex = urlFile.indexOf(JAR_URL_SEPARATOR);
+            jarFileUrl = urlFile.substring(0, separatorIndex);
+            if (jarFileUrl.startsWith("file:")) {
+                jarFileUrl = jarFileUrl.substring("file:".length());
+            }
+            jarFile = new JarFile(jarFileUrl);
+            newJarFile = true;
+            jarFileUrl = "file:" + jarFileUrl;
+            rootEntryPath = urlFile.substring(separatorIndex + 
JAR_URL_SEPARATOR.length());
+        }
+
+        try {
+            if (LOG.isLoggable(Level.FINEST)) {
+                LOG.finest("Looking for matching resources in jar file [" + 
jarFileUrl + "]");
+            }
+            if (!rootEntryPath.isEmpty() && !rootEntryPath.endsWith("/")) {
+                // Root entry path must end with slash for correct matching
+                rootEntryPath = rootEntryPath + '/';
+            }
+            Collection<URL> result = new ArrayList<>(10);
+            for (Enumeration entries = jarFile.entries(); 
entries.hasMoreElements(); ) {
+                JarEntry entry = (JarEntry) entries.nextElement();
+                String entryPath = entry.getName();
+                if (entryPath.startsWith(rootEntryPath)) {
+                    String relativePath = 
entryPath.substring(rootEntryPath.length());
+                    if (relativePath.matches(subPattern)) {
+                        result.add(createRelativeFrom(rootDirResource, 
relativePath));
+                    }
+                }
+            }
+            return result;
+        } finally {
+            // Close jar file, but only if freshly obtained -
+            // not from JarURLConnection, which might cache the file reference.
+            if (newJarFile) {
+                jarFile.close();
+            }
+        }
+    }
+
+    /**
+     * Creates a new URL based on the given root path and the relative path to 
be added.
+     *
+     * @param url          the root, not null
+     * @param relativePath the relative path to be added, not null
+     * @return the new URL instance
+     * @throws MalformedURLException
+     */
+    private URL createRelativeFrom(URL url, String relativePath)
+            throws MalformedURLException {
+        String rootDirResource = url.toExternalForm();
+        if (relativePath.startsWith("/")) {
+            relativePath = relativePath.substring(1);
+        }
+        if (!rootDirResource.endsWith("/")) {
+            rootDirResource = rootDirResource + '/';
+        }
+        return new URL(rootDirResource + relativePath);
+    }
+
+
+    /**
+     * Small check if a given URL is a jar file URL.
+     *
+     * @param url the URL to check, not null.
+     * @return true if the URL has one of the following protocols: jar, zip, 
vfszip, wsjar, code-source.
+     */
+    private boolean isJarFile(URL url) {
+        String protocol = Objects.requireNonNull(url).getProtocol();
+        return (PROTOCOL_JAR.equals(protocol) ||
+                PROTOCOL_ZIP.equals(protocol) ||
+                PROTOCOL_VFSZIP.equals(protocol) ||
+                PROTOCOL_WSJAR.equals(protocol) ||
+                (PROTOCOL_CODE_SOURCE.equals(protocol) && 
url.getPath().indexOf(JAR_URL_SEPARATOR) != -1));
+    }
+
+    /**
+     * Creates a file from an URL.
+     *
+     * @param resourceUrl the url, not null.
+     * @return a new file instance. The instance still may not exist. if the 
url's protocol is not 'file', {@code null}
+     * is returned.
+     */
+    private File getFile(URL resourceUrl) {
+        Objects.requireNonNull(resourceUrl, "Resource URL must not be null");
+        if (!"file".equals(resourceUrl.getProtocol())) {
+            return null;
+        }
+        try {
+            return new File(resourceUrl.toURI().getSchemeSpecificPart());
+        } catch (Exception ex) {
+            // Fallback for URLs that are not valid URIs (should hardly ever 
happen).
+            return new File(resourceUrl.getFile());
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/ae66299e/modules/resources/src/main/java/org/apache/tamaya/resource/internal/DefaultResourceResolver.java
----------------------------------------------------------------------
diff --git 
a/modules/resources/src/main/java/org/apache/tamaya/resource/internal/DefaultResourceResolver.java
 
b/modules/resources/src/main/java/org/apache/tamaya/resource/internal/DefaultResourceResolver.java
index 9fd6fc4..c90e53a 100644
--- 
a/modules/resources/src/main/java/org/apache/tamaya/resource/internal/DefaultResourceResolver.java
+++ 
b/modules/resources/src/main/java/org/apache/tamaya/resource/internal/DefaultResourceResolver.java
@@ -18,7 +18,6 @@
  */
 package org.apache.tamaya.resource.internal;
 
-import org.apache.tamaya.resource.Resource;
 import org.apache.tamaya.resource.ResourceResolver;
 
 import javax.annotation.Priority;
@@ -39,10 +38,10 @@ public class DefaultResourceResolver implements 
ResourceResolver {
     private static final Logger LOG = 
Logger.getLogger(DefaultResourceResolver.class.getName());
 
     @Override
-    public List<Resource> getResources(ClassLoader classLoader, 
Collection<String> expressions) {
-        List<Resource> resources = new ArrayList<>();
+    public List<URL> getResources(ClassLoader classLoader, Collection<String> 
expressions) {
+        List<URL> resources = new ArrayList<>();
         for (String expression : expressions) {
-            if (tryClassPath(classLoader, expression, resources) || 
tryFile(expression, resources) ||
+            if (tryPath(classLoader, expression, resources) || 
tryClassPath(classLoader, expression, resources) || tryFile(expression, 
resources) ||
                     tryURL(expression, resources)) {
                 continue;
             }
@@ -51,12 +50,41 @@ public class DefaultResourceResolver implements 
ResourceResolver {
         return resources;
     }
 
-    private boolean tryClassPath(ClassLoader classLoader, String expression, 
List<Resource> resources) {
+    /**
+     * Tries to evaluate the location passed by Ant path matching.
+     * @param classLoader the class loader to use
+     * @param expression the path expression
+     * @param resources the resources for adding the results
+     * @return true, if the expression could be resolved.
+     */
+    private boolean tryPath(ClassLoader classLoader, String expression, 
List<URL> resources) {
+        try {
+            // 1: try file path
+            Collection<URL> found = FileCollector.collectFiles(expression);
+            if (found.isEmpty()) {
+                found = new 
ClasspathCollector(classLoader).collectFiles(expression);
+            }
+            resources.addAll(found);
+            return !found.isEmpty();
+        } catch (Exception e) {
+            LOG.finest(() -> "Failed to load resource from CP: " + expression);
+        }
+        return false;
+    }
+
+    /**
+     * Tries to evaluate the location passed by loading from the classloader.
+     * @param classLoader the class loader to use
+     * @param expression the path expression
+     * @param resources the resources for adding the results
+     * @return true, if the expression could be resolved.
+     */
+    private boolean tryClassPath(ClassLoader classLoader, String expression, 
List<URL> resources) {
         try {
             Enumeration<URL> urls = classLoader.getResources(expression);
             while (urls.hasMoreElements()) {
                 URL url = urls.nextElement();
-                resources.add(new UrlResource(url));
+                resources.add(url);
             }
             return !resources.isEmpty();
         } catch (Exception e) {
@@ -65,11 +93,17 @@ public class DefaultResourceResolver implements 
ResourceResolver {
         return false;
     }
 
-    private boolean tryFile(String expression, List<Resource> resources) {
+    /**
+     * Tries to evaluate the location passed by lokking up a file.
+     * @param expression the path expression
+     * @param resources the resources for adding the results
+     * @return true, if the expression could be resolved.
+     */
+    private boolean tryFile(String expression, List<URL> resources) {
         try {
             File file = new File(expression);
             if (file.exists()) {
-                resources.add(new FileResource(file));
+                resources.add(file.toURI().toURL());
                 return true;
             }
         } catch (Exception e) {
@@ -78,16 +112,21 @@ public class DefaultResourceResolver implements 
ResourceResolver {
         return false;
     }
 
-    private boolean tryURL(String expression, List<Resource> resources) {
+    /**
+     * Tries to interpret the expression as URL.
+     * @param expression the path expression
+     * @param resources the resources for adding the results
+     * @return true, if the expression could be resolved.
+     */
+    private boolean tryURL(String expression, List<URL> resources) {
         try {
             URL url = new URL(expression);
-            resources.add(new UrlResource(url));
+            resources.add(url);
             return true;
         } catch (Exception e) {
             LOG.finest(() -> "Failed to load resource from file: " + 
expression);
         }
         return false;
-
     }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/ae66299e/modules/resources/src/main/java/org/apache/tamaya/resource/internal/FileCollector.java
----------------------------------------------------------------------
diff --git 
a/modules/resources/src/main/java/org/apache/tamaya/resource/internal/FileCollector.java
 
b/modules/resources/src/main/java/org/apache/tamaya/resource/internal/FileCollector.java
new file mode 100644
index 0000000..d506e11
--- /dev/null
+++ 
b/modules/resources/src/main/java/org/apache/tamaya/resource/internal/FileCollector.java
@@ -0,0 +1,157 @@
+/*
+ * 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.resource.internal;
+
+import java.io.File;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.logging.Logger;
+
+/**
+ * Collector that searches files based on ant styled patterns. For example the 
following patterns would be matched:
+ * <pre>
+ *     file:C:/temp/*.txt
+ *     file:C:\**\*.ini
+ *     C:\Programs\**&#47;*.ini
+ *     /user/home/A*b101_?.pid
+ *     /var/logs&#47;**&#47;*.log
+ * </pre>
+ */
+public class FileCollector {
+
+    public static final String FILE_PREFIX = "file:";
+
+    private FileCollector() {
+    }
+
+    private static final Logger LOG = 
Logger.getLogger(FileCollector.class.getName());
+
+    public static Collection<URL> collectFiles(String expression) {
+        expression = expression.replace("\\", "/");
+        Locator locator = Locator.of(expression);
+        List<URL> result = new ArrayList<>();
+        String rootPath = locator.getRootPath();
+        if (rootPath.startsWith(FILE_PREFIX)) {
+            rootPath = rootPath.substring(FILE_PREFIX.length());
+        }
+        File file = new File(rootPath);
+        if (file.exists()) {
+            List<String> subTokens = locator.getSubPathTokens();
+            result.addAll(traverseAndSelectFromChildren(file, subTokens, 0));
+        }
+        return result;
+    }
+
+    static Collection<URL> traverseAndSelectFromChildren(File dir, 
List<String> subTokens, int tokenIndex) {
+        if (tokenIndex >= subTokens.size() || dir.isFile()) {
+            return Collections.emptyList();
+        }
+        List<URL> result = new ArrayList<>();
+        String token = subTokens.get(tokenIndex);
+        if (token.equals("**")) {
+            result.addAll(traverseAndSelectFromChildren(dir, 
getSubExpression(subTokens, tokenIndex + 1)));
+        } else {
+            token = token.replace("*", ".*");
+            File[] files = dir.listFiles();
+            if (tokenIndex == subTokens.size() - 1) {
+                // select files!
+                for (File f : files) {
+                    if (f.isFile() && f.getName().matches(token)) {
+                        result.add(getURL(f));
+                    }
+                }
+            } else {
+                // check directory pattern
+                for (File f : files) {
+                    if (f.isDirectory() && f.getName().matches(token)) {
+                        result.addAll(traverseAndSelectFromChildren(f, 
subTokens, tokenIndex + 1));
+                    }
+                }
+            }
+        }
+        return result;
+    }
+
+    static Collection<URL> traverseAndSelectFromChildren(File file, String 
subExpression) {
+        List<URL> result = new ArrayList<>();
+        for (File childFile : file.listFiles()) {
+            if (childFile.isFile()) {
+                if (childFile.getName().matches(subExpression)) {
+                    try {
+                        result.add(getURL(childFile));
+                    } catch (Exception e) {
+                        LOG.warning(() -> "File not convertible to URL: " + 
childFile);
+                    }
+                }
+            } else if (childFile.isDirectory()) {
+                result.addAll(traverseAndSelectFromChildren(childFile, 
subExpression));
+            }
+        }
+        return result;
+    }
+
+    private static boolean matchesFile(File childFile, List<String> subTokens, 
int tokenIndex) {
+        if (tokenIndex < (subTokens.size() - 1)) {
+            // not all tokens consumed, so no match!
+            return false;
+        }
+        String tokenToMatch = subTokens.get(tokenIndex);
+        tokenToMatch = tokenToMatch.replace("*", ".*");
+        return childFile.getName().matches(tokenToMatch);
+    }
+
+    /**
+     * Get an URL from a file.
+     *
+     * @param file the file, not null.
+     * @return the URL, never null.
+     * @throws java.lang.IllegalStateException if it fails to create the URL
+     */
+    private static URL getURL(File file) {
+        Objects.requireNonNull(file);
+        try {
+            return file.toURI().toURL();
+        } catch (Exception e) {
+            throw new IllegalStateException("Failed to create URL from file: " 
+ file);
+        }
+    }
+
+    /**
+     * Constructs a sub expression, using the tokens from {@code subTokens} 
starting at index {@code startIndex}.
+     *
+     * @param subTokens  the token list, not null
+     * @param startIndex the start index from where tokens should be taken to 
produce the path.
+     * @return the constructed path, never null.
+     */
+    private static String getSubExpression(List<String> subTokens, int 
startIndex) {
+        StringBuilder b = new StringBuilder();
+        for (int i = startIndex; i < subTokens.size(); i++) {
+            b.append(subTokens.get(i));
+            b.append('/');
+        }
+        if (b.length() > 0) {
+            b.setLength(b.length() - 1);
+        }
+        return b.toString().replaceAll("\\*", ".*").replaceAll("\\?", ".?");
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/ae66299e/modules/resources/src/main/java/org/apache/tamaya/resource/internal/FileResource.java
----------------------------------------------------------------------
diff --git 
a/modules/resources/src/main/java/org/apache/tamaya/resource/internal/FileResource.java
 
b/modules/resources/src/main/java/org/apache/tamaya/resource/internal/FileResource.java
deleted file mode 100644
index c5f521a..0000000
--- 
a/modules/resources/src/main/java/org/apache/tamaya/resource/internal/FileResource.java
+++ /dev/null
@@ -1,172 +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.resource.internal;
-
-import org.apache.tamaya.resource.Resource;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URI;
-import java.util.Objects;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-/**
- * Implementation of {@link Resource} to be loaded from a file.
- *
- * @see java.io.File
- */
-public class FileResource implements Resource {
-
-    private static final Logger LOG = 
Logger.getLogger(FileResource.class.getName());
-
-    private final File file;
-
-    /**
-     * Creates a new instance.
-     *
-     * @param file a File, not null.
-     */
-    public FileResource(File file) {
-        this.file = Objects.requireNonNull(file, "File must not be null");
-    }
-
-    /**
-     * Crreates a new instance.
-     *
-     * @param filePath a file path
-     */
-    public FileResource(String filePath) {
-        Objects.requireNonNull(filePath, "Path must not be null");
-        this.file = new File(filePath);
-    }
-
-
-    /**
-     * Get the file path for this resource.
-     */
-    public final String getPath() {
-        return this.file.getPath();
-    }
-
-
-    /**
-     * This implementation returns whether the underlying file exists.
-     *
-     * @see java.io.File#exists()
-     */
-    @Override
-    public boolean exists() {
-        return this.file.exists();
-    }
-
-    /**
-     * This implementation checks whether the underlying file is marked as 
readable
-     * (and corresponds to an actual file with content, not to a directory).
-     *
-     * @see java.io.File#canRead()
-     * @see java.io.File#isDirectory()
-     */
-    @Override
-    public boolean isAccessible() {
-        return (this.file.canRead() && !this.file.isDirectory());
-    }
-
-    /**
-     * This implementation opens a FileInputStream for the underlying file.
-     *
-     * @see java.io.FileInputStream
-     */
-    @Override
-    public InputStream get() {
-        try {
-            return new FileInputStream(this.file);
-        } catch (Exception e) {
-            LOG.log(Level.INFO, "Failed to open file: " + 
file.getAbsolutePath(), e);
-            return null;
-        }
-    }
-
-    /**
-     * This implementation returns a URI for the underlying file.
-     *
-     * @see java.io.File#toURI()
-     */
-    @Override
-    public URI toURI() throws IOException {
-        return this.file.toURI();
-    }
-
-    /**
-     * Returns the underlying File's length.
-     */
-    @Override
-    public long length() throws IOException {
-        return this.file.length();
-    }
-
-    @Override
-    public long lastModified() throws IOException {
-        return file.lastModified();
-    }
-
-    /**
-     * Returns the name of the current file.
-     *
-     * @see java.io.File#getName()
-     */
-    @Override
-    public String getName() {
-        return this.file.getName();
-    }
-
-    /**
-     * Returns a description that includes the absolute
-     * path of the current file.
-     *
-     * @see java.io.File#getAbsolutePath()
-     */
-    @Override
-    public String toString() {
-        return "File [" + this.file.getAbsolutePath() + "]";
-    }
-
-
-    // implementation current WritableResource
-
-    /**
-     * Compares the underlying Files.
-     */
-    @Override
-    public boolean equals(Object obj) {
-        return (obj == this ||
-                (obj instanceof FileResource && 
this.file.equals(((FileResource) obj).file)));
-    }
-
-    /**
-     * Returns hash code current the underlying File reference.
-     */
-    @Override
-    public int hashCode() {
-        return this.file.hashCode();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/ae66299e/modules/resources/src/main/java/org/apache/tamaya/resource/internal/InputStreamResource.java
----------------------------------------------------------------------
diff --git 
a/modules/resources/src/main/java/org/apache/tamaya/resource/internal/InputStreamResource.java
 
b/modules/resources/src/main/java/org/apache/tamaya/resource/internal/InputStreamResource.java
deleted file mode 100644
index d4aa673..0000000
--- 
a/modules/resources/src/main/java/org/apache/tamaya/resource/internal/InputStreamResource.java
+++ /dev/null
@@ -1,117 +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.resource.internal;
-
-import org.apache.tamaya.resource.Resource;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URI;
-import java.util.Objects;
-
-/**
- * Simple Resource encapsulating an InputStream.
- */
-public class InputStreamResource implements Resource {
-
-    /** The InputStream. */
-    private final InputStream inputStream;
-    /** The read flag. */
-    private boolean read = false;
-    /** The name of the resource. */
-    private String name;
-
-
-    /**
-     * Create a new InputStreamResource.
-     *
-     * @param inputStream the InputStream to use
-     */
-    public InputStreamResource(InputStream inputStream) {
-        this(inputStream, "InputStream:");
-    }
-
-    /**
-     * Create a new InputStreamResource.
-     *
-     * @param inputStream the InputStream to use
-     * @param name where the InputStream comes from
-     */
-    public InputStreamResource(InputStream inputStream, String name) {
-        this.inputStream = Objects.requireNonNull(inputStream);
-        this.name = (name != null ? name : "InputStream");
-    }
-
-
-    /**
-     * This implementation always returns {@code true}.
-     */
-    @Override
-    public boolean exists() {
-        return true;
-    }
-
-    @Override
-    public URI toURI() throws IOException {
-        throw new IOException("URI not available.");
-    }
-
-    @Override
-    public long lastModified() throws IOException {
-        throw new IOException("lastModified not available.");
-    }
-
-    /**
-     * Accesses the input stream. Hereby the input stream can only accessed 
once.
-     */
-    @Override
-    public InputStream get() {
-        if (this.read) {
-            throw new IllegalStateException("InputStream can only be read 
once!");
-        }
-        this.read = true;
-        return this.inputStream;
-    }
-
-    /**
-     * This implementation returns the passed-in description, if any.
-     */
-    public String toString() {
-        return this.name != null ? this.name : super.toString();
-    }
-
-
-    /**
-     * Compares the underlying InputStream.
-     */
-    @Override
-    public boolean equals(Object obj) {
-        return (obj == this ||
-                (obj instanceof InputStreamResource && ((InputStreamResource) 
obj).inputStream.equals(this.inputStream)));
-    }
-
-    /**
-     * This implementation returns the hash code current the underlying 
InputStream.
-     */
-    @Override
-    public int hashCode() {
-        return this.inputStream.hashCode();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/ae66299e/modules/resources/src/main/java/org/apache/tamaya/resource/internal/Locator.java
----------------------------------------------------------------------
diff --git 
a/modules/resources/src/main/java/org/apache/tamaya/resource/internal/Locator.java
 
b/modules/resources/src/main/java/org/apache/tamaya/resource/internal/Locator.java
new file mode 100644
index 0000000..8d9e08a
--- /dev/null
+++ 
b/modules/resources/src/main/java/org/apache/tamaya/resource/internal/Locator.java
@@ -0,0 +1,150 @@
+/*
+ * 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.resource.internal;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Small helper class that manages the path parts of a location expression.
+ */
+final class Locator {
+    /**
+     * The tokenized location expression.
+     */
+    private List<String> tokens;
+
+    /**
+     * Creates a new instances based on the tokenized expression.
+     *
+     * @param tokens the tokenized expression, not null.
+     */
+    Locator(List<String> tokens) {
+        this.tokens = tokens;
+    }
+
+    /**
+     * Creates a new instance of the corresponding expression.
+     *
+     * @param expression the location expression, not null.
+     * @return the tokenized instance.
+     */
+    public static Locator of(String expression) {
+        return new 
Locator(Arrays.asList(expression.split("/")).stream().filter((s) -> 
!s.isEmpty()).collect(Collectors.toList()));
+    }
+
+    /**
+     * Access the root path, which is the location expression, before any 
wildcards or placeholders are used.
+     * It is used as the entry point into the file system or for accessing 
base classpath resources, before
+     * further analysis on the file or jar filesystem can be performed.
+     *
+     * @return the root path, never null.
+     */
+    public String getRootPath() {
+        StringBuilder builder = new StringBuilder();
+        for (String token : tokens) {
+            if (containsPlaceholder(token)) {
+                break;
+            } else {
+                builder.append(token);
+                builder.append('/');
+            }
+        }
+        if (builder.length() > 0) {
+            builder.setLength(builder.length() - 1);
+        }
+        return builder.toString();
+    }
+
+    /**
+     * Return the sub expression path, which contains the second part of the 
expression, starting with a placeholder
+     * or wildcard token.
+     *
+     * @return the sub expression part, never null.
+     */
+    public String getSubPath() {
+        StringBuilder builder = new StringBuilder();
+        for (String token : getSubPathTokens()) {
+            builder.append(token);
+            builder.append('/');
+        }
+        if (builder.length() > 0) {
+            builder.setLength(builder.length() - 1);
+        }
+        return builder.toString();
+    }
+
+    /**
+     * This method returns the single tokenized form of the sub expression.
+     *
+     * @return the tokenized version of the sub path.
+     * @see #getSubPath()
+     */
+    public List<String> getSubPathTokens() {
+        List<String> subTokens = new ArrayList<>();
+        for (String token : tokens) {
+            if (!containsPlaceholder(token)) {
+                continue;
+            } else {
+                subTokens.add(token);
+            }
+        }
+        return subTokens;
+    }
+
+    /**
+     * Access the full reconstructed path. In most cases this should match the 
original expression.
+     *
+     * @return the full expression path, never null.
+     */
+    public String getPath() {
+        StringBuilder builder = new StringBuilder();
+        for (String token : tokens) {
+            builder.append(token);
+            builder.append('/');
+        }
+        if (builder.length() > 0) {
+            builder.setLength(builder.length() - 1);
+        }
+        return builder.toString();
+    }
+
+    /**
+     * Short method that checks for '*' and '?' chars.
+     *
+     * @param token the token to check, not null
+     * @return true, if it contains wildcard characters.
+     */
+    private boolean containsPlaceholder(String token) {
+        return token.contains("*") || token.contains("?");
+    }
+
+    /**
+     * Return the expressions' path.
+     *
+     * @return the locator path.
+     */
+    @Override
+    public String toString() {
+        return "Locator: " + getPath();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/ae66299e/modules/resources/src/main/java/org/apache/tamaya/resource/internal/UrlResource.java
----------------------------------------------------------------------
diff --git 
a/modules/resources/src/main/java/org/apache/tamaya/resource/internal/UrlResource.java
 
b/modules/resources/src/main/java/org/apache/tamaya/resource/internal/UrlResource.java
deleted file mode 100644
index 6522cf5..0000000
--- 
a/modules/resources/src/main/java/org/apache/tamaya/resource/internal/UrlResource.java
+++ /dev/null
@@ -1,140 +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.resource.internal;
-
-import org.apache.tamaya.resource.Resource;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.HttpURLConnection;
-import java.net.MalformedURLException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.net.URLConnection;
-import java.util.Objects;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-/**
- * Implementation of a resource based on a {@code java.net.URL}.
- */
-public class UrlResource implements Resource {
-
-    private static final Logger LOG = 
Logger.getLogger(UrlResource.class.getName());
-
-    /**
-     * Original URL, used for actual access.
-     */
-    private final URL url;
-
-    /**
-     * Create a new instance based on the given URL.
-     *
-     * @param url a URL
-     */
-    public UrlResource(URL url) {
-        this.url = Objects.requireNonNull(url, "URL null");
-    }
-
-    /**
-     * Create a new URLResource based on a URL path.
-     *
-     * @param path a URL path
-     * @throws MalformedURLException if the given URL path is not valid
-     * @see java.net.URL#URL(String)
-     */
-    public UrlResource(String path) throws MalformedURLException {
-        Objects.requireNonNull(path, "Path must not be null");
-        this.url = new URL(path);
-    }
-
-
-    /**
-     * This implementation opens an InputStream for the given URL.
-     *
-     * @see java.net.URL#openConnection()
-     * @see java.net.URLConnection#setUseCaches(boolean)
-     * @see java.net.URLConnection#getInputStream()
-     */
-    @Override
-    public InputStream get() {
-        URLConnection con = null;
-        try {
-            con = this.url.openConnection();
-            useCachesIfNecessary(con);
-            return con.getInputStream();
-        } catch (IOException e) {
-            if (con instanceof HttpURLConnection) {
-                ((HttpURLConnection) con).disconnect();
-            }
-            LOG.log(Level.INFO, "Failed to open URL: " + url, e);
-            return null;
-        }
-    }
-
-    @Override
-    public URI toURI() throws IOException {
-        try {
-            return this.url.toURI();
-        } catch (URISyntaxException e) {
-            throw new IOException("Failed to create URI from " + url);
-        }
-    }
-
-    @Override
-    public String getName() {
-        return this.url.toString();
-    }
-
-    @Override
-    public String toString() {
-        return "URL [" + this.url + "]";
-    }
-
-    /**
-     * Compares the underlying URL references.
-     */
-    @Override
-    public boolean equals(Object obj) {
-        return (obj == this ||
-                (obj instanceof UrlResource && this.url.equals(((UrlResource) 
obj).url)));
-    }
-
-    /**
-     * This implementation returns the hash code current the underlying URL 
reference.
-     */
-    @Override
-    public int hashCode() {
-        return this.url.hashCode();
-    }
-
-    /**
-     * Set the {@link URLConnection#setUseCaches "useCaches"} flag on the
-     * given connection, preferring {@code false} but leaving the
-     * flag at {@code true} for JNLP based format.
-     *
-     * @param con the URLConnection to set the flag on
-     */
-    private void useCachesIfNecessary(URLConnection con) {
-        con.setUseCaches(con.getClass().getSimpleName().startsWith("JNLP"));
-    }
-
-}
-

Reply via email to