001/*******************************************************************************
002 * (C) Copyright 2014 Nuxeo SA (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *******************************************************************************/
014package org.nuxeo.runtime.test;
015
016import java.io.IOException;
017import java.net.URI;
018import java.net.URISyntaxException;
019import java.net.URL;
020import java.nio.file.FileSystem;
021import java.nio.file.FileSystems;
022import java.nio.file.Path;
023import java.nio.file.Paths;
024import java.util.Enumeration;
025import java.util.HashMap;
026import java.util.Map;
027
028public class TargetResourceLocator {
029
030    protected final ClassLoader loader;
031
032    protected final Path basepath;
033
034    public TargetResourceLocator(Class<?> clazz) {
035        basepath = basepath(clazz);
036        loader = clazz.getClassLoader();
037    }
038
039    public Path getBasepath() {
040        return basepath;
041    }
042
043    protected int depthOfClass(String name) {
044        int depth = 0;
045        int index = name.indexOf('.');
046        while (index > 0) {
047            depth += 1;
048            index = name.indexOf('.', index + 1);
049        }
050        return depth;
051    }
052
053    protected Path basepath(Class<?> clazz) {
054        String name = clazz.getName();
055        int depth = depthOfClass(name) + 1;
056        Path path;
057        try {
058            path = toPath(clazz.getResource("/".concat(name).replace('.', '/').concat(".class")).toURI());
059            Path root = path.getRoot();
060            if (path.getNameCount() > depth) {
061                path = path.subpath(0, path.getNameCount() - depth);
062                path = root.resolve(path);
063            }
064            return path;
065        } catch (URISyntaxException | IOException cause) {
066            throw new AssertionError("Cannot convert " + name + " to base dir", cause);
067        }
068    }
069
070    public URL getTargetTestResource(String name) throws IOException {
071        try {
072            final Enumeration<URL> resources = loader.getResources(name);
073            while (resources.hasMoreElements()) {
074                URL resource = resources.nextElement();
075                if (!resources.hasMoreElements()) {
076                    return resource;
077                }
078                URI uri = resource.toURI();
079                Path path = toPath(uri);
080                if (path.getFileSystem().equals(basepath.getFileSystem()) && path.startsWith(basepath)) {
081                    return path.toUri().toURL();
082                }
083            }
084        } catch (URISyntaxException cause) {
085            throw new AssertionError("Cannot find location of " + name, cause);
086        }
087        return null;
088    }
089
090    protected Path toPath(URI uri) throws IOException {
091        final Map<String, String> env = new HashMap<>();
092        final String[] array = uri.toString().split("!");
093        if (array.length == 1) {
094            return Paths.get(uri);
095        }
096        // work-around for jar paths on JDK7
097        try (FileSystem fs = FileSystems.newFileSystem(URI.create(array[0]), env)) {
098            return fs.getPath(array[1]);
099        }
100    }
101}