001: /*
002: * %W% %E%
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026:
027: package com.sun.jumpimpl.module.contentstore;
028:
029: import java.io.File;
030: import java.io.IOException;
031: import java.io.ObjectOutputStream;
032: import java.io.ObjectInputStream;
033: import java.io.FileOutputStream;
034: import java.io.FileInputStream;
035:
036: import java.util.ArrayList;
037: import java.util.Iterator;
038: import java.util.HashMap;
039: import java.util.Map;
040: import java.util.Properties;
041:
042: import com.sun.jump.module.contentstore.*;
043:
044: public class FileStoreImpl extends JUMPStore {
045:
046: //HashMap jumpNodeLists = new HashMap(); // uri, JUMPNode.List
047:
048: boolean verbose = false;
049:
050: public void load(Map map) {
051:
052: Object basedir;
053: if ((basedir = System.getProperty("contentstore.root")) != null) {
054: setStoreRoot((String) basedir);
055: } else if (map != null
056: && (basedir = map.get("contentstore.root")) != null) {
057: setStoreRoot((String) basedir);
058: } else {
059: setStoreRoot(".");
060: }
061: }
062:
063: public void unload() {
064: }
065:
066: public void createDataNode(String uri, JUMPData jumpData)
067: throws IOException {
068: File file = uriToDataFile(uri);
069: File parentFile = file.getParentFile();
070:
071: writeToFile(file, jumpData);
072: }
073:
074: public void createNode(String uri) throws IOException {
075: File file = uriToListFile(uri);
076: file.mkdirs();
077: if (!file.exists())
078: throw new IOException("Could not create: " + file);
079: }
080:
081: public JUMPNode getNode(String uri) throws IOException {
082: // getNode(String) needs to return what the createDataNode() above store
083: // if the uri parameter represents a data node.
084:
085: //System.out.println("getNode uri:" + uri);
086: if (!isDataUri(uri)) {
087: // This URI represents non-leaf node.
088: // No caching for now - might want to optimize in the future.
089: //JUMPNode node = (JUMPNode) jumpNodeLists.get(uri);
090: //if (node == null) {
091: // synchronized(jumpNodeLists) {
092: // node = new JUMPNodeListImpl("list", uri);
093: // jumpNodeLists.put(uri, node);
094: // }
095: //}
096: return new JUMPNodeListImpl(uri);
097: } else {
098:
099: try {
100: File file = uriToDataFile(uri);
101: String name = getNodeName(uri);
102:
103: if (!file.isHidden()) { // Don't make a node for hidden system files
104: JUMPData dataObject = readFromFile(file, name);
105: JUMPNode node = new JUMPNodeDataImpl(uri,
106: dataObject);
107: return node;
108: }
109:
110: } catch (IOException e) {
111: if (verbose)
112: System.err.println(e); // need to do something about exceptions
113: }
114: }
115:
116: return null;
117: }
118:
119: protected void updateDataNode(String uri, JUMPData data)
120: throws IOException {
121: createDataNode(uri, data);
122: }
123:
124: public void deleteNode(String uri) {
125: File file = uriToListFile(uri);
126: deleteFile(file, true);
127: }
128:
129: // deletes everything under this file
130: private boolean deleteFile(File file, boolean success) {
131:
132: if (file.isDirectory()) {
133: File[] list = file.listFiles();
134: for (int i = 0; i < list.length; i++) {
135: deleteFile(list[i], success);
136: }
137: }
138:
139: success = file.delete() & success;
140:
141: return success;
142: }
143:
144: String root; // The real path to the store root.
145:
146: protected void setStoreRoot(String root) {
147: File file = new File(root);
148: if (file.exists()) {
149: this .root = file.getAbsolutePath();
150: return;
151: }
152: // What to do about error checking?
153: throw new RuntimeException("Cannot set persistent store, "
154: + "repositoryDir=" + root + " does not exist");
155:
156: }
157:
158: protected File uriToDataFile(String uri) {
159: String absolutePath = convertToAbsolutePath(uri, true);
160: return new File(absolutePath + File.separatorChar
161: + getNodeName(uri));
162: }
163:
164: protected File uriToListFile(String uri) {
165: String absolutePath = convertToAbsolutePath(uri, false);
166: return new File(absolutePath);
167: }
168:
169: private String getNodeName(String uri) {
170: return uri.substring(uri.lastIndexOf(File.separatorChar) + 1);
171: }
172:
173: private void writeToFile(File file, JUMPData data)
174: throws IOException {
175:
176: int dataFormat = data.getFormat();
177: Object rawDataValue = data.getValue();
178:
179: // Special processing for the java.util.Properties format
180: if (file.getPath().endsWith(".properties")) {
181:
182: Properties prop = (Properties) rawDataValue;
183: prop.store(new FileOutputStream(file), "Generated by "
184: + this .getClass().getName());
185:
186: } else {
187:
188: // All other cases, simply write out the format, then serialized data.
189: ObjectOutputStream oout = new ObjectOutputStream(
190: new FileOutputStream(file));
191: oout.writeInt(dataFormat);
192: oout.writeObject(rawDataValue);
193: oout.close();
194:
195: }
196: }
197:
198: private JUMPData readFromFile(File file, String fileName)
199: throws IOException {
200:
201: int format;
202: Object value;
203:
204: // Special processing for the java.util.Properties format
205: if (fileName.endsWith(".properties")) {
206: format = JUMPData.FORMAT_SERIALIZABLE;
207: Properties prop = new Properties();
208: prop.load(new FileInputStream(file));
209: value = prop;
210: } else {
211:
212: // All other cases, simply read in the format, then deserialized data.
213: try {
214: ObjectInputStream oin = new ObjectInputStream(
215: new FileInputStream(file));
216: format = oin.readInt();
217: value = oin.readObject();
218: } catch (java.io.StreamCorruptedException e) {
219: // this means we ran into a file format that's not JUMPNode.Data.
220: throw new IOException(
221: "Failed to create JUMPNode.Data from "
222: + file.getName());
223: } catch (ClassNotFoundException e) { // can't happen!
224: e.printStackTrace();
225: return null;
226: }
227: }
228:
229: return new JUMPData(value, format);
230: }
231:
232: /*
233: * URI string need to start with ".". Any other restrictions?
234: * If isDataUri boolean param is true, then the uri represents a leaf node
235: * and the absolute uri returns the value with the last item trimmed down
236: * ex. convertToAbsolutePath("./apps/App1", false) and
237: * convertToAbsolutePath("./apps/App1/title", true) will both yield
238: * "<root dir>/apps/App1" as a return value.
239: **/
240: private String convertToAbsolutePath(String uri, boolean isData) {
241:
242: if (!uri.startsWith("."))
243: throw new IllegalArgumentException("Malformed uri, " + uri);
244:
245: String pathUri;
246:
247: if (isData) {
248: pathUri = root.concat(uri.substring(1, uri
249: .lastIndexOf(File.separatorChar)));
250: } else {
251: pathUri = root.concat(uri.substring(1));
252: }
253:
254: return pathUri;
255: }
256:
257: private boolean isDataUri(String uri) {
258:
259: if (!uri.startsWith("."))
260: return false;
261:
262: String absolutePath = convertToAbsolutePath(uri, false);
263:
264: File file = new File(absolutePath);
265:
266: if (file.exists() && file.isDirectory())
267: return false;
268:
269: // need a check on data file exists here.
270:
271: return true;
272: }
273:
274: class JUMPNodeDataImpl implements JUMPNode.Data {
275: JUMPData data;
276: String uri;
277:
278: JUMPNodeDataImpl(String uri, JUMPData data) {
279: this .uri = uri;
280: this .data = data;
281: }
282:
283: public boolean containsData() {
284: return true;
285: }
286:
287: public String getName() {
288: return getNodeName(uri);
289: }
290:
291: public String getURI() {
292: return uri;
293: }
294:
295: public JUMPData getData() {
296: return data;
297: }
298:
299: public String toString() {
300: return "JUMPNode.Data (" + uri + "," + data + ")";
301: }
302:
303: public boolean equals(Object obj) {
304: if (!(obj instanceof JUMPNode.Data))
305: return false;
306: JUMPNode.Data other = (JUMPNode.Data) obj;
307: return (uri.equals(other.getURI()) && data.equals(other
308: .getData()));
309: }
310: }
311:
312: class JUMPNodeListImpl implements JUMPNode.List {
313: String uri;
314: ArrayList children;
315:
316: JUMPNodeListImpl(String uri) {
317: this .uri = uri;
318: }
319:
320: public boolean containsData() {
321: return false;
322: }
323:
324: public String getName() {
325: return getNodeName(uri);
326: }
327:
328: public String getURI() {
329: return uri;
330: }
331:
332: public Iterator getChildren() {
333: //if (children == null) { // should we cache? What if dir content changes?
334: children = new ArrayList();
335: File file = uriToListFile(uri);
336: String[] names = file.list();
337: for (int i = 0; names != null && i < names.length; i++) {
338: try {
339: JUMPNode node = getNode(uri + File.separatorChar
340: + names[i]);
341: if (node != null)
342: children.add(node);
343: } catch (IOException e) {
344: }
345: }
346: //}
347: return children.iterator();
348: }
349:
350: public String toString() {
351: return "JUMPNode.List (" + uri + ")";
352: }
353:
354: public boolean equals(Object obj) {
355: if (!(obj instanceof JUMPNode.List))
356: return false;
357: JUMPNode.List other = (JUMPNode.List) obj;
358: return (uri.equals(other.getURI()));
359: }
360: }
361: }
|