Why not starting to use vfs for this part? Le 11 janv. 2015 11:18, "Mark Struberg" <[email protected]> a écrit :
> Anatole, again: > > > > PROTOCOL_WSJAR > > > All this does NOT work portably! > Many people tried that many times and it simply does NOT work that easily! > The solution I know to work (xban-finder) explicitly has exit points to > extend archive handlers. And it is about 200kByte of size alltogether. > > > The problem with such a solution is that we must support it perfectly > well, or not at all... > > What we *could* support is a _very_ easy solution with a prefix > > classpath-config:mydir/myconfig.properties > vs a real URL e.g. file:// > > In the first case we would simply use ClassLoader.getResources and > register 0..n ConfigSources, in the second case we register exactly the one > URL we got handed over as parameter. > > Also note that any wildcard style in an URL or classpath resource is NOT > widely supported. Some ClassLoaders can handle it in SOME situations, but > most of them don't. > > LieGrue, > strub > > > > > > > On Sunday, 11 January 2015, 1:44, "[email protected]" < > [email protected]> wrote: > > > 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 <[email protected]> > > Authored: Wed Jan 7 22:49:39 2015 +0100 > > Committer: anatole <[email protected]> > > 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/**/*.class > > + * org/apache/tamaya/**/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\**/*.ini > > + * /user/home/A*b101_?.pid > > + * /var/logs/**/*.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")); > > - } > > - > > -} > > - > > >
