001: /*
002: (c) Copyright 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
003: [See end of file]
004: $Id: FileGraphMaker.java,v 1.28 2008/01/02 12:05:19 andy_seaborne Exp $
005: */
006:
007: package com.hp.hpl.jena.graph.impl;
008:
009: import com.hp.hpl.jena.graph.*;
010:
011: import java.io.*;
012: import java.util.*;
013:
014: import com.hp.hpl.jena.shared.*;
015: import com.hp.hpl.jena.util.CollectionFactory;
016: import com.hp.hpl.jena.util.iterator.*;
017: import com.hp.hpl.jena.vocabulary.*;
018:
019: /**
020: A FileGraph factory, making FileGraphs based round some supplied
021: directory. We have to keep track of created files ourselves, because a
022: FileGraph that has been created but not closed is not visible in the
023: filing system. (This might count as a bug at some point.)
024:
025: @author hedgehog
026: */
027: public class FileGraphMaker extends BaseGraphMaker implements
028: FileGraph.NotifyOnClose {
029: protected String fileBase;
030: protected boolean deleteOnClose;
031: protected Map created = CollectionFactory.createHashedMap();
032: protected Set toDelete = CollectionFactory.createHashedSet();
033:
034: /**
035: Construct a file graph factory whose files will appear in root. The reifier
036: style is Minimal and the files will be retained when the maker is closed.
037:
038: @param root the directory to keep the files in.
039: */
040: public FileGraphMaker(String root) {
041: this (root, ReificationStyle.Minimal);
042: }
043:
044: /**
045: Construct a file graph factory whose files will appear in root. The files
046: will be retained when the maker is closed.
047:
048: @param root the directory to keep the files in.
049: @param style the reification style of the resulting graph
050: */
051: public FileGraphMaker(String root, ReificationStyle style) {
052: this (root, style, false);
053: }
054:
055: /**
056: Construct a file graph factory whose files will appear in root.
057: If deleteOnClose is true, the files created by this factory will be deleted
058: when the factory is closed.
059:
060: @param root the directory to keep the files in
061: @param style the reification style of the graph
062: @param deleteOnClose iff true, delete created files on close
063: */
064: public FileGraphMaker(String root, ReificationStyle style,
065: boolean deleteOnClose) {
066: super (style);
067: this .fileBase = root;
068: this .deleteOnClose = deleteOnClose;
069: }
070:
071: /**
072: Answer the RDFS class of a FileGraphMaker
073: @return JenaModelSpec.FileMakerClass [node version]
074: */
075: public Node getMakerClass() {
076: return JenaModelSpec.FileMakerSpec.asNode();
077: }
078:
079: /**
080: Answer the fileBase of all the graphs created by this FileGraphMaker.
081: @return the fileBase of this Maker
082: */
083: public String getFileBase() {
084: return fileBase;
085: }
086:
087: protected void augmentDescription(Graph g, Node self) {
088: g.add(Triple.create(self, JenaModelSpec.fileBase.asNode(), Node
089: .createLiteral(fileBase, "", false)));
090: }
091:
092: /**
093: Answer a new, anonynous FileGraph. See FileGraph.create().
094: @return a new anonymous FileGraph
095: */
096: public Graph createGraph() {
097: return FileGraph.create();
098: }
099:
100: public Graph createGraph(String name, boolean strict) {
101: File f = withRoot(name);
102: FileGraph already = (FileGraph) created.get(f);
103: if (already == null)
104: return remember(f, new FileGraph(this , f, true, strict,
105: style));
106: else {
107: if (strict)
108: throw new AlreadyExistsException(name);
109: else
110: return already.openAgain();
111: }
112: }
113:
114: public Graph openGraph(String name, boolean strict) {
115: File f = withRoot(name);
116: return created.containsKey(f) ? ((FileGraph) created.get(f))
117: .openAgain() : remember(f, new FileGraph(this , f,
118: false, strict, style));
119: }
120:
121: public void notifyClosed(File f) {
122: toDelete.add(f);
123: created.remove(f);
124: }
125:
126: private File withRoot(String name) {
127: return new File(fileBase, toFilename(name));
128: }
129:
130: /**
131: Make <code>name</name> into a "safe" filename. "safe" is a bit weak
132: here; we want to allow URIs as graph names and assume that our filing
133: systems will be reasonably liberal. We'll see ...
134:
135: @param name
136: @return name with underbar, slash, and colon escaped as _U, _S, _C
137: */
138: public static String toFilename(String name) {
139: return name.replaceAll("_", "_U").replaceAll("/", "_S")
140: .replaceAll(":", "_C");
141: }
142:
143: /**
144: Answer the graphname corresponding to the given filename, undoing the
145: conversion done by toFilename.
146:
147: @param fileName a filename, possible containing _U, _C, and _S escapes
148: @return the unescaped name
149: */
150: public static String toGraphname(String fileName) {
151: return fileName.replaceAll("_C", ":").replaceAll("_S", "/")
152: .replaceAll("_U", "_");
153: }
154:
155: public void removeGraph(String name) {
156: forget(withRoot(name)).delete();
157: }
158:
159: private FileGraph remember(File f, FileGraph g) {
160: created.put(f, g);
161: return g;
162: }
163:
164: private File forget(File f) {
165: created.remove(f);
166: return f;
167: }
168:
169: public boolean hasGraph(String name) {
170: File f = withRoot(name);
171: return created.containsKey(f) || f.exists();
172: }
173:
174: public void close() {
175: if (deleteOnClose) {
176: deleteFiles(created.keySet().iterator());
177: deleteFiles(toDelete.iterator());
178: }
179: }
180:
181: protected void deleteFiles(Iterator it) {
182: while (it.hasNext())
183: ((File) it.next()).delete();
184: }
185:
186: /**
187: A Map1 that will convert filename strings to the corresponding graphname strings.
188: */
189: private static Map1 unconvert = new Map1() {
190: public Object map1(Object x) {
191: return toGraphname((String) x);
192: }
193: };
194:
195: /**
196: Answer a FilenameFilter which recognises plausibly RDF filenames; they're not
197: directories, and FileGraph likes them. Pass the buck, pass the buck ...
198:
199: @return a FilenameFilter that accepts plausible graph names
200: */
201: public static FilenameFilter graphName() {
202: return new FilenameFilter() {
203: public boolean accept(File file, String name) {
204: return !new File(file, name).isDirectory()
205: && FileGraph.isPlausibleGraphName(name);
206: }
207: };
208: }
209:
210: /**
211: Answer an iterator over the names of graphs in the FileGraphMaker. This is all the
212: names of freshly-created graphs, plus the names of any files in the fileBase that
213: might be RDF files. "Might" is weaker than we'd like for now.
214:
215: @see com.hp.hpl.jena.graph.GraphMaker#listGraphs()
216: */
217: public ExtendedIterator listGraphs() {
218: String[] fileNames = new File(fileBase).list(graphName());
219: Set allNames = CollectionFactory.createHashedSet(Arrays
220: .asList(fileNames));
221: Iterator it = created.keySet().iterator();
222: while (it.hasNext())
223: allNames.add(((File) it.next()).getName());
224: return WrappedIterator.create(allNames.iterator()).mapWith(
225: unconvert);
226: }
227: }
228:
229: /*
230: (c) Copyright 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
231: All rights reserved.
232:
233: Redistribution and use in source and binary forms, with or without
234: modification, are permitted provided that the following conditions
235: are met:
236:
237: 1. Redistributions of source code must retain the above copyright
238: notice, this list of conditions and the following disclaimer.
239:
240: 2. Redistributions in binary form must reproduce the above copyright
241: notice, this list of conditions and the following disclaimer in the
242: documentation and/or other materials provided with the distribution.
243:
244: 3. The name of the author may not be used to endorse or promote products
245: derived from this software without specific prior written permission.
246:
247: THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
248: IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
249: OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
250: IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
251: INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
252: NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
253: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
254: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
255: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
256: THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
257: */
|