001: /* Copyright (c) 2001 - 2007 TOPP - www.openplans.org. All rights reserved.
002: * This code is licensed under the GPL 2.0 license, availible at the root
003: * application directory.
004: */
005: package org.vfny.geoserver.global;
006:
007: import org.geoserver.platform.GeoServerResourceLoader;
008: import org.geotools.feature.FeatureType;
009: import org.springframework.context.ApplicationContext;
010: import org.springframework.web.context.WebApplicationContext;
011: import org.springframework.web.context.support.WebApplicationContextUtils;
012:
013: /* Copyright (c) 2001 - 2007 TOPP - www.openplans.org. All rights reserved.
014: * This code is licensed under the GPL 2.0 license, availible at the root
015: * application directory.
016: */
017: import java.io.File;
018: import java.io.IOException;
019: import java.net.URI;
020: import java.net.URL;
021: import java.util.NoSuchElementException;
022: import java.util.logging.Logger;
023: import javax.servlet.ServletContext;
024:
025: /**
026: * This class allows for abstracting the location of the Geoserver Data directory. Some people call this "GEOSERVER_HOME".
027: *
028: * 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
029: * directories.
030: *
031: * For the exact content of these directories, see any existing geoserver install's server/geoserver directory.
032: *
033: * In order to find the geoserver data directory the following steps take place:
034: *
035: * 1. search for the "GEOSERVER_DATA_DIR" system property. this will most likely have come from "java -DGEOSERVER_DATA_DIR=..." or from you
036: * web container 2. search for a "GEOSERVER_DATA_DIR" in the web.xml document <context-param> <param-name>GEOSERVER_DATA_DIR</param-name>
037: * <param-value>...</param-value> </context-param> 3. It defaults to the old behavior - ie. the application root - usually
038: * "server/geoserver" in your .WAR.
039: *
040: *
041: * NOTE: a set method is currently undefined because you should either modify you web.xml or set the environment variable and re-start
042: * geoserver.
043: *
044: * @author dblasby
045: *
046: */
047: public class GeoserverDataDirectory {
048: // caches the dataDir
049: private static GeoServerResourceLoader loader;
050: private static Data catalog;
051: private static ApplicationContext appContext;
052: private static final Logger LOGGER = org.geotools.util.logging.Logging
053: .getLogger("org.vfny.geoserver.global");
054: private static boolean isTrueDataDir = false;
055:
056: /**
057: * See the class documentation for more details. 1. search for the "GEOSERVER_DATA_DIR" system property. 2. search for a
058: * "GEOSERVER_DATA_DIR" in the web.xml document 3. It defaults to the old behavior - ie. the application root - usually
059: * "server/geoserver" in your .WAR.
060: *
061: * @return location of the geoserver data dir
062: */
063: static public File getGeoserverDataDirectory() {
064: if (loader != null) {
065: return loader.getBaseDirectory();
066: } else {
067: return null;
068: }
069: }
070:
071: /**
072: * Locate feature type directory name using the FeatureType as a key into the catalog
073: * @see Data#getFeatureTypeInfo(String)
074: * @param name
075: * String The FeatureTypeInfo Name
076:
077: * @return the feature type dir name, or null if not found (either the feature type or the directory)
078: *
079: * @throws NoSuchElementException
080: */
081: static public String findFeatureTypeDirName(FeatureType featureType) {
082: String name = featureType.getTypeName();
083: URI namespace = featureType.getNamespace();
084: FeatureTypeInfo ftInfo = null;
085: Data data = getCatalog();
086: if (namespace != null) {
087: NameSpaceInfo nsInfo = data.getNameSpaceFromURI(namespace
088: .toString());
089: if (nsInfo != null)
090: ftInfo = data.getFeatureTypeInfo(nsInfo.getPrefix()
091: + ":" + name);
092: }
093: if (ftInfo == null)
094: ftInfo = data.getFeatureTypeInfo(name);
095: if (ftInfo == null)
096: return null;
097: return ftInfo.getDirName();
098: }
099:
100: /**
101: * Returns whether GeoServer is using a true data directory, loaded from outside the webapp, or if its defaulting to the webapp embedded
102: * dataDir. We're in the process of moving away from storing anything in the webapp but are keeping this to ease the transition.
103: *
104: * @return <tt>true</tt> if the directory being used for loading is not embedded in the webapp.
105: */
106: static public boolean isTrueDataDir() {
107: return isTrueDataDir;
108: }
109:
110: /**
111: * Utility method to find the approriate sub-data dir config. This is a helper for the fact that we're transitioning away from the
112: * WEB-INF type of hacky storage, but during the transition things can be in both places. So this method takes the root file, the
113: * 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
114: * the dir (the new way)
115: *
116: * @param root
117: * Generally the Data Directory, the directory to try to find the config file in.
118: * @param dirName
119: * The name of the directory to find in the data Dir.
120: * @return The proper config directory.
121: * @throws ConfigurationException
122: * if the directory could not be found at all.
123: */
124: public static File findConfigDir(File root, String dirName)
125: throws ConfigurationException {
126: File configDir;
127:
128: try {
129: configDir = loader.find(dirName);
130: } catch (IOException e) {
131: throw new ConfigurationException(e);
132: }
133:
134: return configDir;
135: }
136:
137: /**
138: * Same as {@link #findConfigDir(File, String), but it will create the configuration directory
139: * if missing (as a top level directory inside the Geoserver data directory)
140: * @param dirName
141: * @return
142: * @throws ConfigurationException
143: */
144: public static File findCreateConfigDir(String dirName)
145: throws ConfigurationException {
146: File configDir = findConfigDir(getGeoserverDataDirectory(),
147: dirName);
148:
149: if ((configDir == null) || !configDir.exists()) {
150: configDir = new File(getGeoserverDataDirectory(), dirName);
151: configDir.mkdir();
152:
153: if (configDir.exists()) {
154: return configDir;
155: }
156: }
157:
158: return configDir;
159: }
160:
161: /**
162: * Given a url, tries to interpret it as a file into the data directory, or as an absolute
163: * location, and returns the actual absolute location of the File
164: * @param path
165: * @return
166: */
167: public static File findDataFile(URL url) {
168: return findDataFile(url.getFile());
169: }
170:
171: /**
172: * Given a path, tries to interpret it as a file into the data directory, or as an absolute
173: * location, and returns the actual absolute location of the File
174: * @param path
175: * @return
176: */
177: public static File findDataFile(String path) {
178: File baseDir = GeoserverDataDirectory
179: .getGeoserverDataDirectory();
180:
181: // do we ever have something that is not a file system reference?
182: if (path.startsWith("file:")) {
183: path = path.substring(5); // remove 'file:' prefix
184:
185: File f = new File(path);
186:
187: // if it's an absolute path, use it as such,
188: // otherwise try to map it inside the data dir
189: if (f.isAbsolute() || f.exists()) {
190: return f;
191: } else {
192: return new File(baseDir, path);
193: }
194: } else {
195: return new File(path);
196: }
197: }
198:
199: /**
200: * Utility method fofinding a config file under the data directory.
201: *
202: * @param file
203: * Path to file, absolute or relative to data dir.
204: *
205: * @return The file handle, or null.
206: */
207: public static File findConfigFile(String file)
208: throws ConfigurationException {
209: try {
210: return loader.find(file);
211: } catch (IOException e) {
212: throw new ConfigurationException(e);
213: }
214: }
215:
216: /**
217: * Initializes the data directory lookup service.
218: * @param servContext
219: */
220: public static void init(WebApplicationContext context) {
221: ServletContext servContext = context.getServletContext();
222:
223: // Oh, this is really sad. We need a reference to Data in order to
224: // resolve feature type dirs, but gathering it here triggers the loading
225: // of Geoserver (on whose Catalog depends on), which depends on having
226: // DataDirectory and Config initialized, but this is not possible here...
227: // So we keep a reference to context in order to resolve Data later
228: appContext = context;
229:
230: // This was once in the GetGeoserverDataDirectory method, I've moved
231: // here so that servlet
232: // context is not needed as a parameter anymore.
233: // caching this, so we're not looking up everytime, and more
234: // importantly, so we can actually look up this stuff without
235: // having to pass in a ServletContext. This should be fine, since we
236: // don't allow a set method, as we recommend restarting GeoServer,
237: // so it should always get a ServletContext in the startup routine.
238: // If this assumption can't be made, then we can't allow data_dir
239: // _and_ webapp options with relative data/ links -ch
240: if (loader == null) {
241: //get the loader from the context
242: loader = (GeoServerResourceLoader) context
243: .getBean("resourceLoader");
244:
245: File dataDir = null;
246:
247: // see if there's a system property
248: try {
249: String prop = System.getProperty("GEOSERVER_DATA_DIR");
250:
251: if ((prop != null) && !prop.equals("")) {
252: // its defined!!
253: isTrueDataDir = true;
254: dataDir = new File(prop);
255: loader.setBaseDirectory(dataDir);
256: loader.addSearchLocation(new File(dataDir, "data"));
257: loader.addSearchLocation(new File(dataDir,
258: "WEB-INF"));
259:
260: LOGGER
261: .severe("\n----------------------------------\n- GEOSERVER_DATA_DIR: "
262: + dataDir.getAbsolutePath()
263: + "\n----------------------------------");
264:
265: return;
266: }
267: } catch (SecurityException e) {
268: // gobble exception
269: LOGGER
270: .fine("Security exception occurred. This is usually not a big deal.\n"
271: + e.getMessage());
272: }
273:
274: // try the webxml
275: String loc = servContext
276: .getInitParameter("GEOSERVER_DATA_DIR");
277:
278: if (loc != null) {
279: // its defined!!
280: isTrueDataDir = true;
281: dataDir = new File(loc);
282: loader.setBaseDirectory(dataDir);
283: loader.addSearchLocation(new File(dataDir, "data"));
284: loader.addSearchLocation(new File(dataDir, "WEB-INF"));
285: LOGGER
286: .severe("\n----------------------------------\n- GEOSERVER_DATA_DIR: "
287: + dataDir.getAbsolutePath()
288: + "\n----------------------------------");
289:
290: return;
291: }
292:
293: // return default
294: isTrueDataDir = false;
295:
296: String rootDir = servContext.getRealPath("/data");
297: dataDir = new File(rootDir);
298:
299: //set the base directory of hte loader
300: loader.setBaseDirectory(dataDir);
301: loader.addSearchLocation(new File(dataDir, "data"));
302: loader.addSearchLocation(new File(dataDir, "WEB-INF"));
303: LOGGER
304: .severe("\n----------------------------------\n- GEOSERVER_DATA_DIR: "
305: + dataDir.getAbsolutePath()
306: + "\n----------------------------------");
307: loader.addSearchLocation(new File(servContext
308: .getRealPath("WEB-INF")));
309: loader.addSearchLocation(new File(servContext
310: .getRealPath("data")));
311: }
312: }
313:
314: /**
315: * Signals the data directory to throw away all global state.
316: * <p>
317: * This code should *not* be called by any non-test GeoServer code.
318: * </p>
319: */
320: public static void destroy() {
321: loader = null;
322: isTrueDataDir = false;
323: }
324:
325: private static Data getCatalog() {
326: if (catalog == null) {
327: catalog = (Data) appContext.getBean("data");
328: }
329: return catalog;
330: }
331: }
|