//
// DataStore.java
// Thud
//
// Copyright (c) 2001-2007 Anthony Parker & the THUD team.
// All rights reserved. See LICENSE.TXT for more information.
//
package net.sourceforge.btthud.util;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.io.IOException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileNotFoundException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.BufferedReader;
import java.io.BufferedWriter;
/**
* Generic data storage facility for THUD. Provides a mechanism to load and
* store data from an application-specific namespace. (Generally, a directory
* in the user's home directory called "THUD", but the interface is meant to be
* fairly generic. In particular, we may want to support the case in the
* future where file system access is constrained because we're an untrusted
* Web Start application, and use the javax.jnlp APIs instead.)
*
* This implementation will also fall back, in the case of input, to retrieving
* resources from the original codebase.
*
* FIXME: The user should be able to set this path the first time, in case they
* want a different one. We need to think about moving one path to a new one,
* too, in case the user changes path. The latter feature, probably not.
*/
public class DataStore {
// TODO: It'd be nice to put these in the right place for various
// platforms, just as a convenience to the user. They'll always be
// able to change it in the preferences later.
public final File defaultDir = new File (System.getProperty("user.home"), "THUD");
private File backingDir = null;
/**
* Construct data store. Store location will be taken from the
* preferences.
*/
public DataStore () {
// TODO: We want to be able to change this in preferences.
try {
setDir(defaultDir);
} catch (IOException e) {
System.err.println("Couldn't initialize data store: " + e);
}
}
private void setDir (final File newDir) throws IOException {
// Initialize backing store.
if (newDir.exists()) {
// Check if there's a usable existing directory.
if (!newDir.isDirectory()) {
throw new IOException ("Not a directory: " + newDir);
}
if (!newDir.canWrite() || !newDir.canRead()) {
throw new IOException ("Access denied: " + newDir);
}
} else {
// Create new directory (and any needed ancestors).
if (!newDir.mkdirs()) {
throw new IOException ("Can't create directory: " + newDir);
}
}
// Update in-memory objects.
backingDir = newDir;
}
/**
* Open stream for input. Returns null if the InputStream couldn't be
* created, for whatever reason.
*/
public InputStream getInputStream (final String name) {
if (backingDir != null) {
try {
return new FileInputStream (new File (backingDir, name));
} catch (FileNotFoundException e) {
}
}
// Fall back to retrieving as a resource.
return getClass().getClassLoader().getResourceAsStream(name);
}
/**
* Open stream for output. Returns null if the OutputStream couldn't
* be created, for whatever reason.
*/
public OutputStream getOutputStream (final String name) {
if (backingDir != null) {
try {
return new FileOutputStream (new File (backingDir, name));
} catch (FileNotFoundException e) {
}
}
// No fall back mechanism.
return null;
}
/**
* Convenience method to get a (buffered) Reader instead of an
* InputStream.
*/
public Reader getReader (final String name) {
// TODO: Think about the buffering some more.
final InputStream input = getInputStream(name);
if (input == null) {
return null;
}
return new BufferedReader (new InputStreamReader (input));
}
/**
* Convenience method to get a (buffered) Writer instead of an
* OutputStream.
*/
public Writer getWriter (final String name) {
// TODO: Think about the buffering some more.
final OutputStream output = getOutputStream(name);
if (output == null) {
return null;
}
return new BufferedWriter (new OutputStreamWriter (output));
}
}