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