001: /**
002: * com.mckoi.store.IOStoreDataAccessor 10 Jun 2003
003: *
004: * Mckoi SQL Database ( http://www.mckoi.com/database )
005: * Copyright (C) 2000, 2001, 2002 Diehl and Associates, Inc.
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
009: * Version 2 as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU General Public License Version 2 for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * Version 2 along with this program; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
019: *
020: * Change Log:
021: *
022: *
023: */package com.mckoi.store;
024:
025: import java.io.File;
026: import java.io.SyncFailedException;
027: import java.io.RandomAccessFile;
028: import java.io.IOException;
029:
030: /**
031: * An implementation of StoreDataAccessor that uses the standard Java IO API to
032: * access data in some underlying file in the filesystem.
033: *
034: * @author Tobias Downer
035: */
036:
037: class IOStoreDataAccessor implements StoreDataAccessor {
038:
039: /**
040: * A lock because access to the data is stateful.
041: */
042: private Object lock = new Object();
043:
044: /**
045: * The File object representing the file in the file system.
046: */
047: private File file;
048:
049: /**
050: * The underlying RandomAccessFile containing the data.
051: */
052: private RandomAccessFile data;
053:
054: /**
055: * The size of the data area.
056: */
057: private long size;
058:
059: /**
060: * True if the file is open.
061: */
062: private boolean is_open;
063:
064: /**
065: * Constructor.
066: */
067: IOStoreDataAccessor(File file) {
068: this .file = file;
069: this .is_open = false;
070: }
071:
072: // ---------- Implemented from StoreDataAccessor ----------
073:
074: public void open(boolean is_read_only) throws IOException {
075: synchronized (lock) {
076: data = new RandomAccessFile(file, is_read_only ? "r" : "rw");
077: size = file.length();
078: is_open = true;
079: }
080: }
081:
082: public void close() throws IOException {
083: synchronized (lock) {
084: data.close();
085: data = null;
086: is_open = false;
087: }
088: }
089:
090: public boolean delete() {
091: if (!is_open) {
092: return file.delete();
093: }
094: return false;
095: }
096:
097: public boolean exists() {
098: return file.exists();
099: }
100:
101: public void read(long position, byte[] buf, int off, int len)
102: throws IOException {
103: // Make sure we don't read past the end
104: synchronized (lock) {
105: len = Math.max(0, Math.min(len, (int) (size - position)));
106: if (position < size) {
107: data.seek(position);
108: data.readFully(buf, off, len);
109: }
110: }
111: }
112:
113: public void write(long position, byte[] buf, int off, int len)
114: throws IOException {
115: // Make sure we don't write past the end
116: synchronized (lock) {
117: len = Math.max(0, Math.min(len, (int) (size - position)));
118: if (position < size) {
119: data.seek(position);
120: data.write(buf, off, len);
121: }
122: }
123: }
124:
125: public void setSize(long new_size) throws IOException {
126: synchronized (lock) {
127: // If expanding the size of the file,
128: if (new_size > this .size) {
129: // Seek to the new size - 1 and write a single byte to the end of the
130: // file.
131: long p = new_size - 1;
132: if (p > 0) {
133: data.seek(p);
134: data.write(0);
135: this .size = new_size;
136: }
137: } else if (new_size < this .size) {
138: // Otherwise the size of the file is shrinking, so setLength().
139: // Note that we don't use 'setLength' to grow the file because of a
140: // bug in the Linux 1.2, 1.3 and 1.4 JVM that generates an error when
141: // expanding the size of a file via 'setLength' on some file systems
142: // (specifically VFAT).
143: data.setLength(new_size);
144: this .size = new_size;
145: }
146: }
147: }
148:
149: public long getSize() throws IOException {
150: synchronized (lock) {
151: if (is_open) {
152: return size;
153: } else {
154: return file.length();
155: }
156: }
157: }
158:
159: public void synch() throws IOException {
160: synchronized (lock) {
161: try {
162: data.getFD().sync();
163: } catch (SyncFailedException e) {
164: // There isn't much we can do about this exception. By itself it
165: // doesn't indicate a terminating error so it's a good idea to ignore
166: // it. Should it be silently ignored?
167: }
168: }
169: }
170:
171: }
|