|
What this is
Other links
The source code
/*****************************************************************************
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License Version
* 1.0 (the "License"). You may not use this file except in compliance with
* the License. A copy of the License is available at http://www.sun.com/
*
* The Original Code is the CVS Client Library.
* The Initial Developer of the Original Code is Robert Greig.
* Portions created by Robert Greig are Copyright (C) 2000.
* All Rights Reserved.
*
* Contributor(s): Robert Greig.
*****************************************************************************/
package org.netbeans.lib.cvsclient.file;
import java.io.*;
import java.util.*;
import org.netbeans.lib.cvsclient.command.*;
import org.netbeans.lib.cvsclient.request.*;
import org.netbeans.lib.cvsclient.util.*;
/**
* Provides a basic implementation of FileHandler, and does much of the
* handling of reading and writing files and performing CRLF conversions.
* @author Robert Greig
*/
public class DefaultFileHandler
implements FileHandler {
/**
* Whether to emit debug information.
*/
private static final boolean DEBUG = false;
/**
* The size of chunks read from disk.
*/
private static final int CHUNK_SIZE = 32768;
/**
* The date the next file written should be marked as being modified on.
*/
private Date modifiedDate;
private TransmitTextFilePreprocessor transmitTextFilePreprocessor;
private WriteTextFilePreprocessor writeTextFilePreprocessor;
private WriteTextFilePreprocessor writeRcsDiffFilePreprocessor;
private GlobalOptions globalOptions;
/**
* Creates a DefaultFileHandler.
*/
public DefaultFileHandler() {
setTransmitTextFilePreprocessor(new DefaultTransmitTextFilePreprocessor());
setWriteTextFilePreprocessor(new DefaultWriteTextFilePreprocessor());
setWriteRcsDiffFilePreprocessor(new WriteRcsDiffFilePreprocessor());
}
/**
* Returns the preprocessor for transmitting text files.
*/
public TransmitTextFilePreprocessor getTransmitTextFilePreprocessor() {
return transmitTextFilePreprocessor;
}
/**
* Sets the preprocessor for transmitting text files.
* The default one changes all line endings to Unix-lineendings (cvs default).
*/
public void setTransmitTextFilePreprocessor(TransmitTextFilePreprocessor transmitTextFilePreprocessor) {
this.transmitTextFilePreprocessor = transmitTextFilePreprocessor;
}
/**
* Gets the preprocessor for writing text files after getting (and un-gzipping) from server.
*/
public WriteTextFilePreprocessor getWriteTextFilePreprocessor() {
return writeTextFilePreprocessor;
}
/**
* Sets the preprocessor for writing text files after getting (and un-gzipping) from server.
*/
public void setWriteTextFilePreprocessor(WriteTextFilePreprocessor writeTextFilePreprocessor) {
this.writeTextFilePreprocessor = writeTextFilePreprocessor;
}
/**
* Gets the preprocessor for merging text files after getting
* (and un-gzipping) the diff received from server.
*/
public WriteTextFilePreprocessor getWriteRcsDiffFilePreprocessor() {
return writeRcsDiffFilePreprocessor;
}
/**
* Sets the preprocessor for merging text files after getting
* (and un-gzipping) the diff received from server.
*/
public void setWriteRcsDiffFilePreprocessor(WriteTextFilePreprocessor writeRcsDiffFilePreprocessor) {
this.writeRcsDiffFilePreprocessor = writeRcsDiffFilePreprocessor;
}
/**
* Get the string to transmit containing the file transmission length.
*
* @return a String to transmit to the server (including carriage return)
* @param length the amount of data that will be sent
*/
protected String getLengthString(long length) {
return String.valueOf(length) + "\n"; //NOI18N
}
protected Reader getProcessedReader(File f)
throws IOException {
return new FileReader(f);
}
protected InputStream getProcessedInputStream(File file) throws IOException {
return new FileInputStream(file);
}
/**
* Get any requests that must be sent before commands are sent, to init
* this file handler.
*
* @return an array of Requests that must be sent
*/
public Request[] getInitialisationRequests() {
return null;
}
/**
* Transmit a text file to the server, using the standard CVS protocol
* conventions. CR/LFs are converted to the Unix format.
*
* @param file the file to transmit
* @param dos the data outputstream on which to transmit the file
*/
public void transmitTextFile(File file, LoggedDataOutputStream dos)
throws IOException {
if (file == null || !file.exists()) {
throw new IllegalArgumentException("File is either null or " +
"does not exist. Cannot transmit.");
}
File fileToSend = file;
final TransmitTextFilePreprocessor transmitTextFilePreprocessor =
getTransmitTextFilePreprocessor();
if (transmitTextFilePreprocessor != null) {
fileToSend = transmitTextFilePreprocessor.getPreprocessedTextFile(file);
}
BufferedInputStream bis = null;
try {
// first write the length of the file
long length = fileToSend.length();
dos.writeBytes(getLengthString(length));
bis = new BufferedInputStream(new FileInputStream(fileToSend));
// now transmit the file itself
byte[] chunk = new byte[CHUNK_SIZE];
while (length > 0) {
int bytesToRead = (length >= CHUNK_SIZE) ? CHUNK_SIZE
: (int)length;
int count = bis.read(chunk, 0, bytesToRead);
length -= count;
dos.write(chunk, 0, count);
}
dos.flush();
}
finally {
if (bis != null) {
try {
bis.close();
}
catch (IOException ex) {
// ignore
}
}
if (transmitTextFilePreprocessor != null) {
transmitTextFilePreprocessor.cleanup(fileToSend);
}
}
}
/**
* Transmit a binary file to the server, using the standard CVS protocol
* conventions.
* @param file the file to transmit
* @param dos the data outputstream on which to transmit the file
*/
public void transmitBinaryFile(File file, LoggedDataOutputStream dos)
throws IOException {
if (file == null || !file.exists()) {
throw new IllegalArgumentException("File is either null or " +
"does not exist. Cannot transmit.");
}
BufferedInputStream bis = null;
try {
bis = new BufferedInputStream(new FileInputStream(file));
// first write the length of the file
long length = file.length();
dos.writeBytes(getLengthString(length));
// now transmit the file itself
byte[] chunk = new byte[CHUNK_SIZE];
while (length > 0) {
int bytesToRead = (length >= CHUNK_SIZE) ? CHUNK_SIZE
: (int)length;
int count = bis.read(chunk, 0, bytesToRead);
length -= count;
dos.write(chunk, 0, count);
}
dos.flush();
}
finally {
if (bis != null) {
try {
bis.close();
}
catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
/**
* Write (either create or replace) a file on the local machine with
* one read from the server.
* @param path the absolute path of the file, (including the file name).
* @param mode the mode of the file
* @param dis the stream to read the file from, as bytes
* @param length the number of bytes to read
*/
public void writeTextFile(String path, String mode,
LoggedDataInputStream dis, int length)
throws IOException {
writeAndPostProcessTextFile(path, mode, dis, length,
getWriteTextFilePreprocessor());
}
/**
* Merge a text file on the local machine with
* the diff from the server. (it uses the RcsDiff response format
* - see cvsclient.ps for details)
* @param path the absolute path of the file, (including the file name).
* @param mode the mode of the file
* @param dis the stream to read the file from, as bytes
* @param length the number of bytes to read
*/
public void writeRcsDiffFile(String path, String mode, LoggedDataInputStream dis,
int length) throws IOException {
writeAndPostProcessTextFile(path, mode, dis, length,
getWriteRcsDiffFilePreprocessor());
}
/**
* Common code for writeTextFile() and writeRcsDiffFile() methods.
* Differs only in the passed file processor.
*/
private void writeAndPostProcessTextFile(String path, String mode, LoggedDataInputStream dis,
int length, WriteTextFilePreprocessor processor) throws IOException {
if (DEBUG) {
System.err.println("[writeTextFile] writing: " + path); //NOI18N
System.err.println("[writeTextFile] length: " + length); //NOI18N
System.err.println("Reader object is: " + dis.hashCode()); //NOI18N
}
File file = new File(path);
boolean readOnly = resetReadOnly(file);
file.getParentFile().mkdirs();
file.createNewFile();
// For CRLF conversion, we have to read the file
// into a temp file, then do the conversion. This is because we cannot
// perform a sequence of readLines() until we've read the file from
// the server - the file transmission is not followed by a newline.
// Bah.
File cvsDir = new File(file.getParentFile(), "CVS");
cvsDir.mkdir();
File tempFile = File.createTempFile("cvsCRLF", "tmp", cvsDir); //NOI18N
try {
OutputStream os = null;
try {
os = new BufferedOutputStream(new FileOutputStream(tempFile));
byte[] chunk = new byte[CHUNK_SIZE];
while (length > 0) {
int count = (length >= CHUNK_SIZE) ? CHUNK_SIZE
:length;
count = dis.read(chunk, 0, count);
length -= count;
if (DEBUG) {
System.err.println("Still got: " + length + " to read"); //NOI18N
}
os.write(chunk, 0, count);
}
}
finally {
if (os != null) {
try {
os.close();
}
catch (IOException ex) {
// ignore
}
}
}
// Here we read the temp file in again, doing any processing required
// (for example, unzipping). We must not convert bytes to characters
// because it would break characters that are not in the current encoding
InputStream tempInput = getProcessedInputStream(tempFile);
try {
//BUGLOG - assert the processor is not null..
processor.copyTextFileToLocation(tempInput, file);
} finally {
tempInput.close();
}
if (modifiedDate != null) {
file.setLastModified(modifiedDate.getTime());
modifiedDate = null;
}
}
finally {
tempFile.delete();
}
if (readOnly) {
FileUtils.setFileReadOnly(file, true);
}
}
/**
* Write (either create or replace) a binary file on the local machine with
* one read from the server.
* @param path the absolute path of the file, (including the file name).
* @param mode the mode of the file
* @param dis the stream to read the file from, as bytes
* @param length the number of bytes to read
*/
public void writeBinaryFile(String path, String mode,
LoggedDataInputStream dis, int length)
throws IOException {
if (DEBUG) {
System.err.println("[writeBinaryFile] writing: " + path); //NOI18N
System.err.println("[writeBinaryFile] length: " + length); //NOI18N
System.err.println("Reader object is: " + dis.hashCode()); //NOI18N
}
File file = new File(path);
boolean readOnly = resetReadOnly(file);
file.getParentFile().mkdirs();
file.createNewFile();
// FUTURE: optimisation possible - no need to use a temp file if there
// is no post processing required (e.g. unzipping). So perhaps enhance
// the interface to allow this stage to be optional
File cvsDir = new File(file.getParentFile(), "CVS");
cvsDir.mkdir();
File tempFile = File.createTempFile("cvsPostConversion", "tmp", cvsDir); //NOI18N
try {
BufferedOutputStream bos =
new BufferedOutputStream(new FileOutputStream(tempFile));
byte[] chunk = new byte[CHUNK_SIZE];
try {
while (length > 0) {
int bytesToRead = (length >= CHUNK_SIZE) ? CHUNK_SIZE
: (int)length;
int count = dis.read(chunk, 0, bytesToRead);
if (count < 0) {
break;
}
length -= count;
if (DEBUG) {
System.err.println("Still got: " + length + " to read"); //NOI18N
}
bos.write(chunk, 0, count);
}
} finally {
bos.close();
}
// Here we read the temp file in, taking the opportunity to process
// the file, e.g. unzip the data
BufferedInputStream tempIS =
new BufferedInputStream(getProcessedInputStream(tempFile));
bos = new BufferedOutputStream(new FileOutputStream(file));
try {
for (int count = tempIS.read(chunk, 0, CHUNK_SIZE);
count > 0;
count = tempIS.read(chunk, 0, CHUNK_SIZE)) {
bos.write(chunk, 0, count);
}
} finally {
bos.close();
tempIS.close();
}
// now we need to modifiy the timestamp on the file, if specified
if (modifiedDate != null) {
file.setLastModified(modifiedDate.getTime());
modifiedDate = null;
}
}
finally {
tempFile.delete();
}
if (readOnly) {
FileUtils.setFileReadOnly(file, true);
}
}
private boolean resetReadOnly(File file) throws java.io.IOException {
boolean readOnly = globalOptions != null && globalOptions.isCheckedOutFilesReadOnly();
if (file.exists() && readOnly) {
readOnly = !file.canWrite();
if (readOnly) {
FileUtils.setFileReadOnly(file, false);
}
}
return readOnly;
}
/**
* Remove the specified file from the local disk.
*
* @param pathname the full path to the file to remove
* @throws IOException if an IO error occurs while removing the file
*/
public void removeLocalFile(String pathname)
throws IOException {
File fileToDelete = new File(pathname);
if (!fileToDelete.delete()) {
System.err.println("Could not delete file " +
fileToDelete.getAbsolutePath());
}
}
/**
* Rename the local file.
*
* @param pathname the full path to the file to rename
* @param newName the new name of the file (not the full path)
* @throws IOException if an IO error occurs while renaming the file
*/
public void renameLocalFile(String pathname, String newName)
throws IOException {
File sourceFile = new File(pathname);
File destinationFile = new File(sourceFile.getParentFile(), newName);
sourceFile.renameTo(destinationFile);
}
/**
* Set the modified date of the next file to be written.
* The next call to writeFile will use this date.
*
* @param modifiedDate the date the file should be marked as modified
*/
public void setNextFileDate(Date modifiedDate) {
this.modifiedDate = modifiedDate;
}
/**
* Sets the global options.
* This can be useful to detect, whether local files should be made read-only.
*/
public void setGlobalOptions(GlobalOptions globalOptions) {
BugLog.getInstance().assertNotNull(globalOptions);
this.globalOptions = globalOptions;
transmitTextFilePreprocessor.setTempDir(globalOptions.getTempDir());
}
}
|
| ... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.