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")); > - } > - > -} > - >
