001: /*
002: * (c) Copyright 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
003: * [See end of file]
004: */
005:
006: package com.hp.hpl.jena.util;
007:
008: import java.io.*;
009: import java.util.*;
010:
011: import org.apache.commons.logging.*; //import javax.servlet.* ;
012:
013: import com.hp.hpl.jena.rdf.model.*;
014: import com.hp.hpl.jena.shared.*;
015:
016: /** FileManager
017: *
018: * A FileManager provides access to named file-like resources by opening
019: * InputStreams to things in the filing system, by URL (http: and file:) and
020: * found by the classloader. It can also load RDF data from such a system
021: * resource into an existing model or create a new (Memory-based) model.
022: * There is a global FileManager which provide uniform access to system
023: * resources: applications may also create specialised FileManagers.
024: *
025: * A FileManager contains a list of location functions to try: the global
026: * FileManger has one {@link LocatorFile}, one {@link LocatorClassLoader} and
027: * one {@link LocatorURL}
028: *
029: * Main operations:
030: * * <ul>
031: * <li>loadModel, readModel : URI to model</li>
032: * <li>open, openNoMap : URI to input stream</li>
033: * <li>mapURI : map URI to another by {@link LocationMapper}</li>
034: * </ul>
035: *
036: * Utilities:
037: * <ul>
038: * <li>readWholeFileAsUTF8</li>
039: * <li>optional caching of models<li>
040: * </ul>
041: *
042: * A FileManager works in conjunction with a LocationMapper.
043: * A {@link LocationMapper} is a set of alternative locations for system
044: * resources and a set of alternative prefix locations. For example, a local
045: * copy of a common RDF dataset may be used whenever the usual URL is used by
046: * the application.
047: *
048: * The {@link LocatorFile} also supports the idea of "current directory".
049: *
050: * @see LocationMapper
051: * @see FileUtils
052: *
053: *
054: * @author Andy Seaborne
055: * @version $Id: FileManager.java,v 1.41 2008/01/02 12:07:44 andy_seaborne Exp $
056: */
057:
058: public class FileManager {
059: /** Delimiter between path entries : because URI scheme names use : we only allow ; */
060: public static final String PATH_DELIMITER = ";";
061: public static final String filePathSeparator = java.io.File.separator;
062: private static Log log = LogFactory.getLog(FileManager.class);
063:
064: static FileManager instance = null;
065:
066: static boolean logAllLookups = true;
067: List handlers = new ArrayList();
068: LocationMapper mapper = null;
069: boolean cacheModelLoads = false;
070: ModelCache modelCache = null;
071:
072: /** Get the global file manager.
073: * @return the global file manager
074: */
075: public static FileManager get() {
076: // Singleton pattern adopted in case we later have several file managers.
077: if (instance == null)
078: instance = makeGlobal();
079: return instance;
080: }
081:
082: /** Set the global file manager (as returned by get())
083: * If called before any call to get(), then the usual default filemanager is not created
084: * @param globalFileManager
085: */
086: public static void setGlobalFileManager(
087: FileManager globalFileManager) {
088: instance = globalFileManager;
089: }
090:
091: /** Create an uninitialized FileManager */
092: public FileManager() {
093: }
094:
095: /** Create a new file manager that is a deep copy another.
096: * Location mapper and locators chain are copied (the locators are not cloned).
097: * The model cache is not copied and is initially set to not cache.
098: * @param filemanager
099: */
100: public FileManager(FileManager filemanager) {
101: handlers.addAll(filemanager.handlers);
102: mapper = null;
103: if (filemanager.getLocationMapper() != null)
104: mapper = new LocationMapper(filemanager.getLocationMapper());
105: cacheModelLoads = false;
106: modelCache = null;
107: }
108:
109: /** Create a "standard" FileManager. */
110: public static FileManager makeGlobal() {
111: FileManager fMgr = new FileManager(LocationMapper.get());
112: setStdLocators(fMgr);
113: return fMgr;
114: }
115:
116: /** Force a file handler to have the default configuration. */
117: public static void setStdLocators(FileManager fMgr) {
118: fMgr.handlers.clear();
119: fMgr.addLocatorFile();
120: fMgr.addLocatorURL();
121: fMgr.addLocatorClassLoader(fMgr.getClass().getClassLoader());
122: }
123:
124: /** Create with the given location mapper */
125: public FileManager(LocationMapper _mapper) {
126: setLocationMapper(_mapper);
127: }
128:
129: /** @deprecated Use setLocationMapper */
130: public void setMapper(LocationMapper _mapper) {
131: setLocationMapper(_mapper);
132: }
133:
134: /** Set the location mapping */
135: public void setLocationMapper(LocationMapper _mapper) {
136: mapper = _mapper;
137: }
138:
139: /** Get the location mapping */
140: public LocationMapper getLocationMapper() {
141: return mapper;
142: }
143:
144: /** Return an iterator over all the handlers */
145: public Iterator locators() {
146: return handlers.listIterator();
147: }
148:
149: /** Add a locator to the end of the locators list */
150: public void addLocator(Locator loc) {
151: log.debug("Add location: " + loc.getName());
152: handlers.add(loc);
153: }
154:
155: /** Add a file locator */
156: public void addLocatorFile() {
157: addLocatorFile(null);
158: }
159:
160: /** Add a file locator which uses dir as its working directory */
161: public void addLocatorFile(String dir) {
162: LocatorFile fLoc = new LocatorFile(dir);
163: addLocator(fLoc);
164: }
165:
166: /** Add a class loader locator */
167: public void addLocatorClassLoader(ClassLoader cLoad) {
168: LocatorClassLoader cLoc = new LocatorClassLoader(cLoad);
169: addLocator(cLoc);
170: }
171:
172: /** Add a URL locator */
173: public void addLocatorURL() {
174: Locator loc = new LocatorURL();
175: addLocator(loc);
176: }
177:
178: /** Add a zip file locator */
179: public void addLocatorZip(String zfn) {
180: Locator loc = new LocatorZip(zfn);
181: addLocator(loc);
182: }
183:
184: /** Remove a locator */
185: public void remove(Locator loc) {
186: handlers.remove(loc);
187: }
188:
189: // -------- Cache operations
190:
191: /** Reset the model cache */
192: public void resetCache() {
193: if (modelCache != null)
194: modelCache.reset();
195: }
196:
197: /** Change the state of model cache : does not clear the cache */
198:
199: public void setModelCaching(boolean state) {
200: cacheModelLoads = state;
201: if (cacheModelLoads && modelCache == null)
202: modelCache = new ModelCache();
203: }
204:
205: /** return whether caching is on of off */
206: public boolean getCachingModels() {
207: return cacheModelLoads;
208: }
209:
210: /** Read out of the cache - return null if not in the cache */
211: public Model getFromCache(String filenameOrURI) {
212: if (!getCachingModels())
213: return null;
214: return modelCache.get(filenameOrURI);
215: }
216:
217: public boolean hasCachedModel(String filenameOrURI) {
218: if (!getCachingModels())
219: return false;
220: return modelCache.contains(filenameOrURI);
221: }
222:
223: public void addCacheModel(String uri, Model m) {
224: if (getCachingModels())
225: modelCache.put(uri, m);
226: }
227:
228: public void removeCacheModel(String uri) {
229: if (getCachingModels())
230: modelCache.remove(uri);
231: }
232:
233: // -------- Cache operations (end)
234:
235: /** Load a model from a file (local or remote).
236: * Guesses the syntax of the file based on filename extension,
237: * defaulting to RDF/XML.
238: * @param filenameOrURI The filename or a URI (file:, http:)
239: * @return a new model
240: * @exception JenaException if there is syntax error in file.
241: */
242:
243: public Model loadModel(String filenameOrURI) {
244: if (log.isDebugEnabled())
245: log.debug("loadModel(" + filenameOrURI + ")");
246:
247: return loadModelWorker(filenameOrURI, null, null);
248: }
249:
250: /** Load a model from a file (local or remote).
251: * URI is the base for reading the model.
252: *
253: * @param filenameOrURI The filename or a URI (file:, http:)
254: * @param rdfSyntax RDF Serialization syntax.
255: * @return a new model
256: * @exception JenaException if there is syntax error in file.
257: */
258:
259: public Model loadModel(String filenameOrURI, String rdfSyntax) {
260: if (log.isDebugEnabled())
261: log.debug("loadModel(" + filenameOrURI + ", " + rdfSyntax
262: + ")");
263: return loadModelWorker(filenameOrURI, null, rdfSyntax);
264: }
265:
266: /** Load a model from a file (local or remote).
267: *
268: * @param filenameOrURI The filename or a URI (file:, http:)
269: * @param baseURI Base URI for loading the RDF model.
270: * @param rdfSyntax RDF Serialization syntax.
271: * @return a new model
272: * @exception JenaException if there is syntax error in file.
273: */
274:
275: public Model loadModel(String filenameOrURI, String baseURI,
276: String rdfSyntax) {
277: if (log.isDebugEnabled())
278: log.debug("loadModel(" + filenameOrURI + ", " + baseURI
279: + ", " + rdfSyntax + ")");
280:
281: return loadModelWorker(filenameOrURI, baseURI, rdfSyntax);
282: }
283:
284: private Model loadModelWorker(String filenameOrURI, String baseURI,
285: String rdfSyntax) {
286: // Better: if ( hasCachedModel(filenameOrURI) ) return getFromCache(filenameOrURI) ;
287: if (modelCache != null && modelCache.contains(filenameOrURI)) {
288: if (log.isDebugEnabled())
289: log.debug("Model cache hit: " + filenameOrURI);
290: return modelCache.get(filenameOrURI);
291: }
292:
293: Model m = ModelFactory.createDefaultModel();
294: readModelWorker(m, filenameOrURI, baseURI, rdfSyntax);
295:
296: if (this .cacheModelLoads)
297: modelCache.put(filenameOrURI, m);
298: return m;
299: }
300:
301: /**
302: * Read a file of RDF into a model.
303: * @param model
304: * @param filenameOrURI
305: * @return The model or null, if there was an error.
306: * @exception JenaException if there is syntax error in file.
307: */
308:
309: public Model readModel(Model model, String filenameOrURI) {
310: if (log.isDebugEnabled())
311: log.debug("readModel(model," + filenameOrURI + ")");
312: return readModel(model, filenameOrURI, null);
313: }
314:
315: /**
316: * Read a file of RDF into a model.
317: * @param model
318: * @param filenameOrURI
319: * @param rdfSyntax RDF Serialization syntax.
320: * @return The model or null, if there was an error.
321: * @exception JenaException if there is syntax error in file.
322: */
323:
324: public Model readModel(Model model, String filenameOrURI,
325: String rdfSyntax) {
326: if (log.isDebugEnabled())
327: log.debug("readModel(model," + filenameOrURI + ", "
328: + rdfSyntax + ")");
329: return readModelWorker(model, filenameOrURI, null, rdfSyntax);
330: }
331:
332: /**
333: * Read a file of RDF into a model.
334: * @param model
335: * @param filenameOrURI
336: * @param baseURI
337: * @param syntax
338: * @return The model
339: * @exception JenaException if there is syntax error in file.
340: */
341:
342: public Model readModel(Model model, String filenameOrURI,
343: String baseURI, String syntax) {
344:
345: if (log.isDebugEnabled())
346: log.debug("readModel(model," + filenameOrURI + ", "
347: + baseURI + ", " + syntax + ")");
348: return readModelWorker(model, filenameOrURI, baseURI, syntax);
349: }
350:
351: private Model readModelWorker(Model model, String filenameOrURI,
352: String baseURI, String syntax) {
353: if (baseURI == null)
354: baseURI = chooseBaseURI(filenameOrURI);
355:
356: // Doesn't call open() - we want to make the synatx guess based on the mapped URI.
357: String mappedURI = mapURI(filenameOrURI);
358:
359: if (log.isDebugEnabled() && !mappedURI.equals(filenameOrURI))
360: log.debug("Map: " + filenameOrURI + " => " + mappedURI);
361:
362: if (syntax == null) {
363: syntax = FileUtils.guessLang(mappedURI);
364: if (syntax == null || syntax.equals(""))
365: syntax = FileUtils.langXML;
366: if (log.isDebugEnabled())
367: log.debug("Syntax guess: " + syntax);
368: }
369:
370: TypedStream in = openNoMapOrNull(mappedURI);
371: if (in == null) {
372: if (log.isDebugEnabled())
373: log.debug("Failed to locate '" + mappedURI + "'");
374: throw new NotFoundException("Not found: " + filenameOrURI);
375: }
376: if (in.getMimeType() != null) {
377: // XXX
378: //syntax
379: }
380:
381: model.read(in.getInput(), baseURI, syntax);
382: try {
383: in.getInput().close();
384: } catch (IOException ex) {
385: }
386: return model;
387: }
388:
389: private static String chooseBaseURI(String baseURI) {
390: String scheme = FileUtils.getScheme(baseURI);
391:
392: if (scheme != null) {
393: if (scheme.equals("file")) {
394: if (!baseURI.startsWith("file:///")) {
395: try {
396: // Fix up file URIs. Yuk.
397: String tmp = baseURI
398: .substring("file:".length());
399: File f = new File(tmp);
400: baseURI = "file:///" + f.getCanonicalPath();
401: baseURI = baseURI.replace('\\', '/');
402:
403: // baseURI = baseURI.replace(" ","%20");
404: // baseURI = baseURI.replace("~","%7E");
405: // Convert to URI. Except that it removes ///
406: // Could do that and fix up (again)
407: //java.net.URL u = new java.net.URL(baseURI) ;
408: //baseURI = u.toExternalForm() ;
409: } catch (Exception ex) {
410: }
411: }
412: }
413: return baseURI;
414: }
415:
416: if (baseURI.startsWith("/"))
417: return "file://" + baseURI;
418: return "file:" + baseURI;
419: }
420:
421: /** Open a file using the locators of this FileManager */
422: public InputStream open(String filenameOrURI) {
423: if (log.isDebugEnabled())
424: log.debug("open(" + filenameOrURI + ")");
425:
426: String uri = mapURI(filenameOrURI);
427:
428: if (log.isDebugEnabled() && !uri.equals(filenameOrURI))
429: log.debug("open: mapped to " + uri);
430:
431: return openNoMap(uri);
432: }
433:
434: /** @deprecated Use mapURI */
435: public String remap(String filenameOrURI) {
436: return mapURI(filenameOrURI);
437: }
438:
439: /** Apply the mapping of a filename or URI */
440: public String mapURI(String filenameOrURI) {
441: if (mapper == null)
442: return filenameOrURI;
443:
444: String uri = mapper.altMapping(filenameOrURI, null);
445:
446: if (uri == null) {
447: if (FileManager.logAllLookups && log.isDebugEnabled())
448: log.debug("Not mapped: " + filenameOrURI);
449: uri = filenameOrURI;
450: } else {
451: if (log.isDebugEnabled())
452: log.debug("Mapped: " + filenameOrURI + " => " + uri);
453: }
454: return uri;
455: }
456:
457: /** Slurp up a whole file */
458: public String readWholeFileAsUTF8(InputStream in) {
459: try {
460: Reader r = FileUtils.asBufferedUTF8(in);
461: StringWriter sw = new StringWriter(1024);
462: char buff[] = new char[1024];
463: while (r.ready()) {
464: int l = r.read(buff);
465: if (l <= 0)
466: break;
467: sw.write(buff, 0, l);
468: }
469: r.close();
470: sw.close();
471: return sw.toString();
472: } catch (IOException ex) {
473: throw new WrappedIOException(ex);
474: }
475: }
476:
477: /** Slurp up a whole file: map filename as necessary */
478: public String readWholeFileAsUTF8(String filename) {
479: InputStream in = open(filename);
480: if (in == null)
481: throw new NotFoundException("File not found: " + filename);
482: return readWholeFileAsUTF8(in);
483: }
484:
485: /** Open a file using the locators of this FileManager
486: * but without location mapping */
487: public InputStream openNoMap(String filenameOrURI) {
488: TypedStream in = openNoMapOrNull(filenameOrURI);
489: if (in == null)
490: return null;
491: // if ( in == null )
492: // throw new NotFoundException(filenameOrURI) ;
493: return in.getInput();
494: }
495:
496: /** Open a file using the locators of this FileManager
497: * but without location mapping.
498: * Return null if not found
499: */
500:
501: public TypedStream openNoMapOrNull(String filenameOrURI) {
502: for (Iterator iter = handlers.iterator(); iter.hasNext();) {
503: Locator loc = (Locator) iter.next();
504: TypedStream in = loc.open(filenameOrURI);
505: if (in != null) {
506: if (log.isDebugEnabled())
507: log.debug("Found: " + filenameOrURI + " ("
508: + loc.getName() + ")");
509: return in;
510: }
511: }
512: return null;
513: }
514: }
515:
516: class ModelCache {
517: Map modelCache = new HashMap();
518:
519: ModelCache() {
520: }
521:
522: /** Reset the model cache */
523: public void reset() {
524: if (modelCache != null) {
525: // for ( Iterator iter = modelCache.keySet().iterator() ; iter.hasNext() ; )
526: // {
527: // String name = (String)iter.next() ;
528: // Model m = (Model)modelCache.get(name) ;
529: // if ( m != null )
530: // m.close() ;
531: // }
532: modelCache.clear();
533: }
534: }
535:
536: public Model get(String filenameOrURI) {
537: return (Model) modelCache.get(filenameOrURI);
538: }
539:
540: public boolean contains(String filenameOrURI) {
541: return modelCache.containsKey(filenameOrURI);
542: }
543:
544: public void put(String uri, Model m) {
545: modelCache.put(uri, m);
546: }
547:
548: public void remove(String uri) {
549: modelCache.remove(uri);
550: }
551: }
552:
553: /*
554: * (c) Copyright 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
555: * All rights reserved.
556: *
557: * Redistribution and use in source and binary forms, with or without
558: * modification, are permitted provided that the following conditions
559: * are met:
560: * 1. Redistributions of source code must retain the above copyright
561: * notice, this list of conditions and the following disclaimer.
562: * 2. Redistributions in binary form must reproduce the above copyright
563: * notice, this list of conditions and the following disclaimer in the
564: * documentation and/or other materials provided with the distribution.
565: * 3. The name of the author may not be used to endorse or promote products
566: * derived from this software without specific prior written permission.
567: *
568: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
569: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
570: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
571: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
572: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
573: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
574: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
575: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
576: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
577: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
578: */
|