org.vfny.geoserver.global.GeoserverDataDirectory Maven / Gradle / Ivy
The newest version!
/* Copyright (c) 2001 - 2007 TOPP - www.openplans.org. All rights reserved.
* This code is licensed under the GPL 2.0 license, availible at the root
* application directory.
*/
package org.vfny.geoserver.global;
import org.geoserver.config.GeoServerLoader;
import org.geoserver.platform.GeoServerResourceLoader;
import org.opengis.feature.simple.SimpleFeatureType;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
/* Copyright (c) 2001 - 2007 TOPP - www.openplans.org. All rights reserved.
* This code is licensed under the GPL 2.0 license, availible at the root
* application directory.
*/
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.util.NoSuchElementException;
import java.util.logging.Logger;
import javax.servlet.ServletContext;
/**
* This class allows for abstracting the location of the Geoserver Data directory. Some people call this "GEOSERVER_HOME".
*
* Inside this directory should be two more directories: a. "WEB-INF/" Inside this is a catalog.xml b. "data/" Inside this is a set of other
* directories.
*
* For the exact content of these directories, see any existing geoserver install's server/geoserver directory.
*
* In order to find the geoserver data directory the following steps take place:
*
* 1. search for the "GEOSERVER_DATA_DIR" system property. this will most likely have come from "java -DGEOSERVER_DATA_DIR=..." or from you
* web container 2. search for a "GEOSERVER_DATA_DIR" in the web.xml document GEOSERVER_DATA_DIR
* ... 3. It defaults to the old behavior - ie. the application root - usually
* "server/geoserver" in your .WAR.
*
*
* NOTE: a set method is currently undefined because you should either modify you web.xml or set the environment variable and re-start
* geoserver.
*
* @author dblasby
*
*/
public class GeoserverDataDirectory {
// caches the dataDir
public static GeoServerResourceLoader loader;
private static Data catalog;
private static ApplicationContext appContext;
private static final Logger LOGGER = org.geotools.util.logging.Logging.getLogger("org.vfny.geoserver.global");
private static boolean isTrueDataDir = false;
/**
* See the class documentation for more details. 1. search for the "GEOSERVER_DATA_DIR" system property. 2. search for a
* "GEOSERVER_DATA_DIR" in the web.xml document 3. It defaults to the old behavior - ie. the application root - usually
* "server/geoserver" in your .WAR.
*
* @return location of the geoserver data dir
*/
static public File getGeoserverDataDirectory() {
if (loader != null) {
return loader.getBaseDirectory();
} else {
return null;
}
}
/**
* Locate feature type directory name using the FeatureType as a key into the catalog
* @see Data#getFeatureTypeInfo(String)
* @param name
* String The FeatureTypeInfo Name
* @return the feature type dir name, or null if not found (either the feature type or the directory)
*
* @throws NoSuchElementException
*/
static public String findFeatureTypeDirName(SimpleFeatureType featureType) {
String name = featureType.getTypeName();
String namespace = featureType.getName().getNamespaceURI();
FeatureTypeInfo ftInfo = null;
Data data = getCatalog();
if(namespace != null) {
NameSpaceInfo nsInfo = data.getNameSpaceFromURI(namespace);
if(nsInfo != null)
ftInfo = data.getFeatureTypeInfo(nsInfo.getPrefix() + ":" + name);
}
if(ftInfo == null)
ftInfo = data.getFeatureTypeInfo(name);
if(ftInfo == null)
return null;
String dirName = ftInfo.getDirName();
if ( dirName == null ) {
dirName = ftInfo.getPrefix() + "_" + ftInfo.getTypeName();
}
return dirName;
}
/**
* Locate coverage type directory name using the coverage name as a key into the catalog
* @see Data#getCoverageInfo(String)
* @param coverageName
* String The FeatureTypeInfo Name
* @return the feature type dir name, or null if not found (either the feature type or the directory)
*
* @throws NoSuchElementException
*/
public static String findCoverageDirName(String coverageName) {
Data data = getCatalog();
CoverageInfo coverageInfo = data.getCoverageInfo(coverageName);
String dirName = coverageInfo.getDirName();
return dirName;
}
/**
* Returns whether GeoServer is using a true data directory, loaded from outside the webapp, or if its defaulting to the webapp embedded
* dataDir. We're in the process of moving away from storing anything in the webapp but are keeping this to ease the transition.
*
* @return true if the directory being used for loading is not embedded in the webapp.
*/
static public boolean isTrueDataDir() {
return isTrueDataDir;
}
/**
* Utility method to find the approriate sub-data dir config. This is a helper for the fact that we're transitioning away from the
* WEB-INF type of hacky storage, but during the transition things can be in both places. So this method takes the root file, the
* dataDir, and a name of a directory that is stored in the data dir, and checks for it in the data/ dir (the old way), and directly in
* the dir (the new way)
*
* @param root
* Generally the Data Directory, the directory to try to find the config file in.
* @param dirName
* The name of the directory to find in the data Dir.
* @return The proper config directory.
* @throws ConfigurationException
* if the directory could not be found at all.
*/
public static File findConfigDir(File root, String dirName)
throws ConfigurationException {
File configDir;
try {
configDir = loader.find(dirName);
} catch (IOException e) {
throw new ConfigurationException(e);
}
return configDir;
}
/**
* Same as {@link #findConfigDir(File, String), but it will create the configuration directory
* if missing (as a top level directory inside the Geoserver data directory)
* @param dirName
* @return
* @throws ConfigurationException
*/
public static File findCreateConfigDir(String dirName)
throws ConfigurationException {
File configDir = findConfigDir(getGeoserverDataDirectory(), dirName);
if ((configDir == null) || !configDir.exists()) {
configDir = new File(getGeoserverDataDirectory(), dirName);
configDir.mkdir();
if (configDir.exists()) {
return configDir;
}
}
return configDir;
}
/**
* Given a url, tries to interpret it as a file into the data directory, or as an absolute
* location, and returns the actual absolute location of the File
* @param path
* @return
*/
public static File findDataFile(URL url) {
return findDataFile(url.getFile());
}
/**
* Looks up a file under the "styles" directory.
*
* @param fileName The name of the file.
*
* @return The style file, or null if it does not exist.
*/
public static File findStyleFile(String fileName) {
File baseDir = GeoserverDataDirectory.getGeoserverDataDirectory();
File styleFile = new File( new File( baseDir, "styles" ), fileName );
if (styleFile.exists() ) {
return styleFile;
}
return null;
}
/**
* Given a path, tries to interpret it as a file into the data directory, or as an absolute
* location, and returns the actual absolute location of the File
* @param path
* @return
*/
public static File findDataFile(String path) {
File baseDir = GeoserverDataDirectory.getGeoserverDataDirectory();
// do we ever have something that is not a file system reference?
if (path.startsWith("file:")) {
path = path.substring(5); // remove 'file:' prefix
File f = new File(path);
// if it's an absolute path, use it as such,
// otherwise try to map it inside the data dir
if (f.isAbsolute() || f.exists()) {
return f;
} else {
return new File(baseDir, path);
}
} else {
return new File(path);
}
}
/**
* Utility method fofinding a config file under the data directory.
*
* @param file
* Path to file, absolute or relative to data dir.
*
* @return The file handle, or null.
*/
public static File findConfigFile(String file) throws ConfigurationException {
try {
return loader.find(file);
} catch (IOException e) {
throw new ConfigurationException(e);
}
}
/**
* Initializes the data directory lookup service.
*
* @param servContext
*/
public static void init(WebApplicationContext context) {
ServletContext servContext = context.getServletContext();
// Oh, this is really sad. We need a reference to Data in order to
// resolve feature type dirs, but gathering it here triggers the loading
// of Geoserver (on whose Catalog depends on), which depends on having
// DataDirectory and Config initialized, but this is not possible
// here...
// So we keep a reference to context in order to resolve Data later
appContext = context;
// This was once in the GetGeoserverDataDirectory method, I've moved
// here so that servlet
// context is not needed as a parameter anymore.
// caching this, so we're not looking up everytime, and more
// importantly, so we can actually look up this stuff without
// having to pass in a ServletContext. This should be fine, since we
// don't allow a set method, as we recommend restarting GeoServer,
// so it should always get a ServletContext in the startup routine.
// If this assumption can't be made, then we can't allow data_dir
// _and_ webapp options with relative data/ links -ch
if (loader == null) {
// get the loader from the context
loader = (GeoServerResourceLoader) context
.getBean("resourceLoader");
File dataDir = null;
String dataDirStr = findGeoServerDataDir(servContext);
if (dataDirStr != null) {
// its defined!!
isTrueDataDir = true;
dataDir = new File(dataDirStr);
loader.setBaseDirectory(dataDir);
loader.addSearchLocation(new File(dataDir, "data"));
loader.addSearchLocation(new File(dataDir, "WEB-INF"));
LOGGER
.severe("\n----------------------------------\n- GEOSERVER_DATA_DIR: "
+ dataDir.getAbsolutePath()
+ "\n----------------------------------");
return;
} else {
// Return default
isTrueDataDir = false;
String rootDir = servContext.getRealPath("/data");
dataDir = new File(rootDir);
// set the base directory of the loader
loader.setBaseDirectory(dataDir);
loader.addSearchLocation(new File(dataDir, "data"));
loader.addSearchLocation(new File(dataDir, "WEB-INF"));
LOGGER
.severe("\n----------------------------------\n- GEOSERVER_DATA_DIR: "
+ dataDir.getAbsolutePath()
+ "\n----------------------------------");
// loader.addSearchLocation(new
// File(servContext.getRealPath("WEB-INF")));
//loader.addSearchLocation(new File(servContext.getRealPath("data")));
}
}
}
/**
* Loops over a list of variables that can represent the path to the
* GeoServer data directory and attempts to resolve the value by looking at
* 1) Java environment variable
* 2) Servlet context variable
* 3) System variable
*
* For each of these, the methods checks that
* 1) The path exists
* 2) Is a directory
* 3) Is writable
*
* @param servContext
* @return String representation of path, null otherwise
*/
private static String findGeoServerDataDir(ServletContext servContext) {
final String[] typeStrs = { "Java environment variable ",
"Servlet context parameter ", "System environment variable " };
String dataDirStr = null;
final String[] varStrs = { "GEOSERVER_DATA_DIR", "GEOSERVER_DATA_ROOT" };
String msgPrefix = null;
int iVar = 0;
// Loop over variable names
for (int i = 0; i < varStrs.length && dataDirStr == null; i++) {
// Loop over variable access methods
for (int j = 0; j < typeStrs.length && dataDirStr == null; j++) {
String value = null;
String varStr = new String(varStrs[i]);
String typeStr = typeStrs[j];
// Lookup section
switch (j) {
case 1:
value = System.getProperty(varStr);
break;
case 2:
value = servContext.getInitParameter(varStr);
break;
case 3:
value = System.getenv(varStr);
break;
}
if (value == null || value.equalsIgnoreCase("")) {
LOGGER.finer("Found " + typeStr + varStr + " to be unset");
continue;
}
// Verify section
File fh = new File(value);
// Being a bit pessimistic here
msgPrefix = "Found " + typeStr + varStr + " set to " + value;
if (!fh.exists()) {
LOGGER.fine(msgPrefix + " , but this path does not exist");
continue;
}
if (!fh.isDirectory()) {
LOGGER.fine(msgPrefix + " , which is not a directory");
continue;
}
if (!fh.canWrite()) {
LOGGER.fine(msgPrefix + " , which is not writeable");
continue;
}
// Sweet, we can work with this
dataDirStr = value;
iVar = i;
}
}
return dataDirStr;
}
/**
* Signals the data directory to throw away all global state.
*
* This code should *not* be called by any non-test GeoServer code.
*
*/
public static void destroy() {
loader = null;
isTrueDataDir = false;
catalog = null;
}
private static Data getCatalog() {
if(catalog == null) {
catalog = (Data) appContext.getBean("data");
}
return catalog;
}
}