platform35/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/SafeFileOutputStream.java
changeset 40 eb3c938c7fef
equal deleted inserted replaced
39:2a03ec4dbf31 40:eb3c938c7fef
       
     1 /*******************************************************************************
       
     2  * Copyright (c) 2000, 2006 IBM Corporation and others.
       
     3  * All rights reserved. This program and the accompanying materials
       
     4  * are made available under the terms of the Eclipse Public License v1.0
       
     5  * which accompanies this distribution, and is available at
       
     6  * http://www.eclipse.org/legal/epl-v10.html
       
     7  *
       
     8  * Contributors:
       
     9  *     IBM Corporation - initial API and implementation
       
    10  *******************************************************************************/
       
    11 package org.eclipse.core.internal.localstore;
       
    12 
       
    13 import java.io.*;
       
    14 import org.eclipse.core.internal.utils.FileUtil;
       
    15 
       
    16 /**
       
    17  * This class should be used when there's a file already in the
       
    18  * destination and we don't want to lose its contents if a
       
    19  * failure writing this stream happens.
       
    20  * Basically, the new contents are written to a temporary location.
       
    21  * If everything goes OK, it is moved to the right place.
       
    22  * The user has the option to define the temporary location or 
       
    23  * it will be created in the default-temporary directory
       
    24  * (see java.io.File for details).
       
    25  */
       
    26 public class SafeFileOutputStream extends OutputStream {
       
    27 	protected File temp;
       
    28 	protected File target;
       
    29 	protected OutputStream output;
       
    30 	protected boolean failed;
       
    31 	protected static final String EXTENSION = ".bak"; //$NON-NLS-1$
       
    32 
       
    33 	public SafeFileOutputStream(File file) throws IOException {
       
    34 		this(file.getAbsolutePath(), null);
       
    35 	}
       
    36 
       
    37 	/**
       
    38 	 * If targetPath is null, the file will be created in the default-temporary directory.
       
    39 	 */
       
    40 	public SafeFileOutputStream(String targetPath, String tempPath) throws IOException {
       
    41 		failed = false;
       
    42 		target = new File(targetPath);
       
    43 		createTempFile(tempPath);
       
    44 		if (!target.exists()) {
       
    45 			if (!temp.exists()) {
       
    46 				output = new BufferedOutputStream(new FileOutputStream(target));
       
    47 				return;
       
    48 			}
       
    49 			// If we do not have a file at target location, but we do have at temp location,
       
    50 			// it probably means something wrong happened the last time we tried to write it.
       
    51 			// So, try to recover the backup file. And, if successful, write the new one.
       
    52 			copy(temp, target);
       
    53 		}
       
    54 		output = new BufferedOutputStream(new FileOutputStream(temp));
       
    55 	}
       
    56 
       
    57 	public void close() throws IOException {
       
    58 		try {
       
    59 			output.close();
       
    60 		} catch (IOException e) {
       
    61 			failed = true;
       
    62 			throw e; // rethrow
       
    63 		}
       
    64 		if (failed)
       
    65 			temp.delete();
       
    66 		else
       
    67 			commit();
       
    68 	}
       
    69 
       
    70 	protected void commit() throws IOException {
       
    71 		if (!temp.exists())
       
    72 			return;
       
    73 		target.delete();
       
    74 		copy(temp, target);
       
    75 		temp.delete();
       
    76 	}
       
    77 
       
    78 	protected void copy(File sourceFile, File destinationFile) throws IOException {
       
    79 		if (!sourceFile.exists())
       
    80 			return;
       
    81 		if (sourceFile.renameTo(destinationFile))
       
    82 			return;
       
    83 		InputStream source = null;
       
    84 		OutputStream destination = null;
       
    85 		try {
       
    86 			source = new BufferedInputStream(new FileInputStream(sourceFile));
       
    87 			destination = new BufferedOutputStream(new FileOutputStream(destinationFile));
       
    88 			transferStreams(source, destination);
       
    89 		} finally {
       
    90 			FileUtil.safeClose(source);
       
    91 			FileUtil.safeClose(destination);
       
    92 		}
       
    93 	}
       
    94 
       
    95 	protected void createTempFile(String tempPath) {
       
    96 		if (tempPath == null)
       
    97 			tempPath = target.getAbsolutePath() + EXTENSION;
       
    98 		temp = new File(tempPath);
       
    99 	}
       
   100 
       
   101 	public void flush() throws IOException {
       
   102 		try {
       
   103 			output.flush();
       
   104 		} catch (IOException e) {
       
   105 			failed = true;
       
   106 			throw e; // rethrow
       
   107 		}
       
   108 	}
       
   109 
       
   110 	public String getTempFilePath() {
       
   111 		return temp.getAbsolutePath();
       
   112 	}
       
   113 
       
   114 	protected void transferStreams(InputStream source, OutputStream destination) throws IOException {
       
   115 		byte[] buffer = new byte[8192];
       
   116 		while (true) {
       
   117 			int bytesRead = source.read(buffer);
       
   118 			if (bytesRead == -1)
       
   119 				break;
       
   120 			destination.write(buffer, 0, bytesRead);
       
   121 		}
       
   122 	}
       
   123 
       
   124 	public void write(int b) throws IOException {
       
   125 		try {
       
   126 			output.write(b);
       
   127 		} catch (IOException e) {
       
   128 			failed = true;
       
   129 			throw e; // rethrow
       
   130 		}
       
   131 	}
       
   132 }