001/*
002 * (C) Copyright 2014 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.nuxeo.runtime.test;
017
018import java.io.IOException;
019import java.net.URI;
020import java.net.URISyntaxException;
021import java.net.URL;
022import java.nio.file.FileSystem;
023import java.nio.file.FileSystems;
024import java.nio.file.Path;
025import java.nio.file.Paths;
026import java.util.Enumeration;
027import java.util.HashMap;
028import java.util.Map;
029
030public class TargetResourceLocator {
031
032    protected final ClassLoader loader;
033
034    protected final Path basepath;
035
036    public TargetResourceLocator(Class<?> clazz) {
037        basepath = basepath(clazz);
038        loader = clazz.getClassLoader();
039    }
040
041    public Path getBasepath() {
042        return basepath;
043    }
044
045    protected int depthOfClass(String name) {
046        int depth = 0;
047        int index = name.indexOf('.');
048        while (index > 0) {
049            depth += 1;
050            index = name.indexOf('.', index + 1);
051        }
052        return depth;
053    }
054
055    protected Path basepath(Class<?> clazz) {
056        String name = clazz.getName();
057        int depth = depthOfClass(name) + 1;
058        Path path;
059        try {
060            path = toPath(clazz.getResource("/".concat(name).replace('.', '/').concat(".class")).toURI());
061            Path root = path.getRoot();
062            if (path.getNameCount() > depth) {
063                path = path.subpath(0, path.getNameCount() - depth);
064                path = root.resolve(path);
065            }
066            return path;
067        } catch (URISyntaxException | IOException cause) {
068            throw new AssertionError("Cannot convert " + name + " to base dir", cause);
069        }
070    }
071
072    public URL getTargetTestResource(String name) throws IOException {
073        try {
074            final Enumeration<URL> resources = loader.getResources(name);
075            while (resources.hasMoreElements()) {
076                URL resource = resources.nextElement();
077                if (!resources.hasMoreElements()) {
078                    return resource;
079                }
080                URI uri = resource.toURI();
081                Path path = toPath(uri);
082                if (path.getFileSystem().equals(basepath.getFileSystem()) && path.startsWith(basepath)) {
083                    return path.toUri().toURL();
084                }
085            }
086        } catch (URISyntaxException cause) {
087            throw new AssertionError("Cannot find location of " + name, cause);
088        }
089        return null;
090    }
091
092    protected Path toPath(URI uri) throws IOException {
093        final Map<String, String> env = new HashMap<>();
094        final String[] array = uri.toString().split("!");
095        if (array.length == 1) {
096            return Paths.get(uri);
097        }
098        // work-around for jar paths on JDK7
099        try (FileSystem fs = FileSystems.newFileSystem(URI.create(array[0]), env)) {
100            return fs.getPath(array[1]);
101        }
102    }
103}