Subversion Repositories mkgmap

Rev

Rev 3408 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 * Copyright (C) 2007 Steve Ratcliffe
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2 as
 *  published by the Free Software Foundation.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *
 * Author: Steve Ratcliffe
 * Create date: Feb 17, 2008
 */

package uk.me.parabola.mkgmap.osmstyle;

import java.io.Closeable;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.Reader;
import java.net.URL;

import uk.me.parabola.log.Logger;

/**
 * Open a style which can be on the classpath (mainly for the built-in styles)
 * or in a specified file or directory.
 *
 * @author Steve Ratcliffe
 */

public abstract class StyleFileLoader implements Closeable {
        private static final Logger log = Logger.getLogger(StyleFileLoader.class);

        /**
         * Open a style that is contained in a file.  This is expected to be a
         * directory or zip file containing the files that make up the style.
         *
         * @param loc The file or directory containing the style(s). If this is null then the location "classpath:styles"
         * is used.
         * @param name If the name is given then we look for a directory with the
         * given name.  If there is no name, then the style is assumed to be at
         * the top level and/or the only file.
         *
         * @return A style loader.
         */

        public static StyleFileLoader createStyleLoader(String loc, String name)
                        throws FileNotFoundException
        {
                if (loc == null)
                        return createStyleLoader("classpath:styles", name);
               
                StyleFileLoader loader;

                File file = new File(loc);
                if (file.isDirectory()) {
                        File dir = file;
                        if (name != null) {
                                dir = new File(file, name);
                                if (dir.exists() == false)
                                        throw new FileNotFoundException("style " + name + " not found in " + dir);
                                if (!dir.isDirectory())
                                        dir = file;
                        }

                        log.debug("style directory", dir);
                        loader = new DirectoryFileLoader(dir);
                } else if (file.isFile()) {
                        String loclc = loc.toLowerCase();
                        if (loclc.endsWith(".style")) {
                                if (name != null)
                                        throw new FileNotFoundException("no sub styles in a simple style file");
                                log.debug("a single file style");
                                loader = new CombinedStyleFileLoader(loc);
                        } else {
                                log.debug("jar file", file);
                                loader = new JarFileLoader(file.toURI().toString(), name);
                        }
                } else {
                        log.debug("style url location", loc);
                        String s = loc.toLowerCase();
                        if (s.startsWith("classpath:")) {
                                log.debug("load style off classpath");
                                loader = classpathLoader(loc.substring(10), name);
                                return loader;
                        } else if (s.startsWith("jar:")) {
                                loader = new JarFileLoader(loc, name);
                        } else if (s.indexOf(':') > 0) {
                                loader = new JarFileLoader(s, name);
                        } else {
                                throw new FileNotFoundException("no such file or path: " + loc);
                        }
                }

                return loader;
        }

        /**
         * Open the specified file in the style definition.
         * @param filename The name of the file in the style.
         * @return An open file reader for the file.
         * @throws FileNotFoundException When the file can't be opened.
         */

        public abstract Reader open(String filename) throws FileNotFoundException;

        /**
         * Close the FileLoader.  This is different from closing individual files
         * that were opened via {@link #open}.  After this call then you shouldn't
         * open any more files.
         */

        public abstract void close();

        /**
         * List the names of the styles that are contained in this loader.
         * @return An array of style names.
         */

        public abstract String[] list();

        /**
         * Find a style on the class path.  First we find out if the style is in
         * a jar or a directory and then use the appropriate Loader.
         *
         * @param loc The file or directory location.
         * @param name The style name.
         * @return A loader for the style.
         * @throws FileNotFoundException If it can't be found.
         */

        private static StyleFileLoader classpathLoader(String loc, String name) throws FileNotFoundException
        {
                String path = loc;
                if (name != null)
                        path = loc + '/' + name + '/';

                ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
                if (classLoader == null)
                        throw new FileNotFoundException("no classloader to find style");

                // all style files must be in the same directory or zip
                URL url = classLoader.getResource(path);
                if (url == null) {
                        classLoader = StyleFileLoader.class.getClassLoader();
                        url = classLoader.getResource(path);
                        if (url == null)
                                throw new FileNotFoundException("Could not find style " + path);
                }

                String proto = url.getProtocol().toLowerCase();
                if (proto.equals("jar")) {
                        log.debug("classpath loading from jar with url", url);
                        return new JarFileLoader(url);
                } else if (proto.equals("file")) {
                        log.debug("classpath loading from directory", url.getPath());
                        return new DirectoryFileLoader(new File(url.getPath()));
                }
                throw new FileNotFoundException("Could not load style from classpath");
        }
}