/******************************************************************************* * Copyright (c) 2000, 2011 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 * James Blackburn (Broadcom Corp.) - ongoing development *******************************************************************************/ package org.eclipse.core.internal.localstore; import java.io.*; import org.eclipse.core.internal.utils.FileUtil; /** * 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); } }