/*******************************************************************************
* Copyright (c) 2000, 2005 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.core.internal.localstore;
import org.eclipse.core.internal.utils.FileUtil;
import java.io.*;
/**
* Appends data, in chunks, to a file. Each chunk is defined by the moment
* the stream is opened (created) and a call to #succeed is made. It is
* necessary to use the <code>SafeChunkyInputStream</code> to read its
* contents back. The user of this class does not need to know explicitly about
* its chunk implementation.
* It is only an implementation detail. What really matters to the outside
* world is that it tries to keep the file data consistent.
* If some data becomes corrupted while writing or later, upon reading
* the file, the chunk that contains the corrupted data is skipped.
* <p>
* Because of this class purpose (keep data consistent), it is important that the
* user only calls <code>#succeed</code> when the chunk of data is successfully
* written. After this call, the user can continue writing data to the file and it
* will not be considered related to the previous chunk. So, if this data is
* corrupted, the previous one is still safe.
*
* @see SafeChunkyInputStream
*/
public class SafeChunkyOutputStream extends FilterOutputStream {
protected String filePath;
protected boolean isOpen;
public SafeChunkyOutputStream(File target) throws IOException {
this(target.getAbsolutePath());
}
public SafeChunkyOutputStream(String filePath) throws IOException {
super(new BufferedOutputStream(new FileOutputStream(filePath, true)));
this.filePath = filePath;
isOpen = true;
beginChunk();
}
protected void beginChunk() throws IOException {
write(ILocalStoreConstants.BEGIN_CHUNK);
}
protected void endChunk() throws IOException {
write(ILocalStoreConstants.END_CHUNK);
}
protected void open() throws IOException {
out = new BufferedOutputStream(new FileOutputStream(filePath, true));
isOpen = true;
beginChunk();
}
public void succeed() throws IOException {
try {
endChunk();
close();
} finally {
isOpen = false;
FileUtil.safeClose(this);
}
}
public void write(int b) throws IOException {
if (!isOpen)
open();
super.write(b);
}
}