001: package org.jvnet.mimepull;
002:
003: import java.io.*;
004:
005: /**
006: * Use {@link RandomAccessFile} for concurrent access of read
007: * and write partial part's content.
008: *
009: * @author Kohsuke Kawaguchi
010: * @author Jitendra Kotamraju
011: */
012: final class DataFile {
013: private File file;
014: private RandomAccessFile raf;
015: private long writePointer;
016:
017: DataFile(File file) {
018: this .file = file;
019: try {
020: raf = new RandomAccessFile(file, "rw");
021: } catch (IOException ioe) {
022: throw new MIMEParsingException(ioe);
023: }
024: writePointer = 0;
025: }
026:
027: /**
028: * there is no point in calling read(), write(). Directly can use
029: * {#getInputStream()}
030: */
031: void close() {
032: try {
033: raf.close();
034: } catch (IOException ioe) {
035: throw new MIMEParsingException(ioe);
036: }
037: }
038:
039: /**
040: *
041: * @return
042: */
043: InputStream getInputStream() {
044: try {
045: close();
046: return new DirectInputStream(this );
047: } catch (FileNotFoundException fe) {
048: throw new MIMEParsingException(fe);
049: }
050: }
051:
052: /**
053: * Read data from the given file pointer position.
054: *
055: * @param pointer read position
056: * @param buf that needs to be filled
057: * @param offset the start offset of the data.
058: * @param length of data that needs to be read
059: */
060: synchronized void read(long pointer, byte[] buf, int offset,
061: int length) {
062: try {
063: raf.seek(pointer);
064: raf.readFully(buf, offset, length);
065: } catch (IOException ioe) {
066: throw new MIMEParsingException(ioe);
067: }
068: }
069:
070: void renameTo(File f) {
071: try {
072: raf.close();
073: file.renameTo(f);
074: } catch (IOException ioe) {
075: throw new MIMEParsingException(ioe);
076: }
077: }
078:
079: /**
080: * Write data to the file
081: *
082: * @param data that needs to written to a file
083: * @param offset start offset in the data
084: * @param length no bytes to write
085: * @return file pointer before the write operation(or at which the
086: * data is written)
087: */
088: synchronized long writeTo(byte[] data, int offset, int length) {
089: try {
090: long temp = writePointer;
091: raf.seek(writePointer);
092: raf.write(data, offset, length);
093: writePointer = raf.getFilePointer(); // Update pointer for next write
094: return temp;
095: } catch (IOException ioe) {
096: throw new MIMEParsingException(ioe);
097: }
098: }
099:
100: /**
101: * Keeps {@link DataFile} from garbage collected when
102: * someone is reading it.
103: */
104: private static final class DirectInputStream extends
105: FilterInputStream {
106: private DataFile parent;
107:
108: public DirectInputStream(DataFile parent)
109: throws FileNotFoundException {
110: super (new FileInputStream(parent.file));
111: this .parent = parent;
112: }
113:
114: public void close() throws IOException {
115: super .close();
116: parent = null;
117: }
118: }
119:
120: @Override
121: protected void finalize() throws Throwable {
122: try {
123: raf.close();
124: file.delete();
125: } catch (Exception e) {
126: // Ignore all exceptions
127: } finally {
128: super.finalize();
129: }
130: }
131:
132: }
|