org.rhq.common.drift.ChangeSetReaderImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of rhq-common-drift Show documentation
Show all versions of rhq-common-drift Show documentation
A library with the code common to the agent and server drift management code
/*
* RHQ Management Platform
* Copyright (C) 2011 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package org.rhq.common.drift;
import static org.rhq.common.drift.FileEntry.addedFileEntry;
import static org.rhq.common.drift.FileEntry.changedFileEntry;
import static org.rhq.common.drift.FileEntry.removedFileEntry;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.Iterator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.rhq.core.domain.drift.DriftChangeSetCategory;
/**
* Note that this implementation does not do any validation for the most part. It assumes
* that entries in the change set file contain valid, 64 character SHA-256 hashes. It
* assumes that all headers are present in the file and in the correct order. It assume
* that all paths are non-null.
*
* The one thing that the read does check is the drift category code for each file entry.
* If the code is not valid, an error message is logged and a {@link ChangeSetReaderException}
* is thrown.
*/
public class ChangeSetReaderImpl implements ChangeSetReader {
private Log log = LogFactory.getLog(ChangeSetReaderImpl.class);
private BufferedReader reader;
private File metaDataFile;
private Headers headers;
private boolean closeStream;
public ChangeSetReaderImpl(File metaDataFile) throws ChangeSetReaderException {
try {
this.metaDataFile = metaDataFile;
reader = new BufferedReader(new FileReader(this.metaDataFile));
readHeaders();
} catch (IOException e) {
log.error("Unable to read headers from " + metaDataFile.getAbsolutePath() + ": " + e.getMessage());
throw new ChangeSetReaderException("Unable to read headers from " + metaDataFile.getAbsolutePath(), e);
} catch (IllegalArgumentException e) {
log.error("Unable to read headers from " + metaDataFile.getAbsolutePath() + ": " + e.getMessage());
throw new ChangeSetReaderException("Unable to read headers from " + metaDataFile.getAbsolutePath(), e);
}
}
public ChangeSetReaderImpl(Reader metaDataFile) throws Exception {
this(metaDataFile, false);
}
/**
* Creates a new change set reader. This constructor takes a boolean argument that can
* be used to prevent the reader from closing the stream when using its iterator. Note
* that calling {@link #close()} will close the stream regardless of the value of
* closeStream.
*
* @param metaDataFile
* @param closeStream
* @throws Exception
*/
public ChangeSetReaderImpl(Reader metaDataFile, boolean closeStream) throws Exception {
reader = new BufferedReader(metaDataFile);
readHeaders();
this.closeStream = closeStream;
}
private void readHeaders() throws IOException {
headers = new Headers();
try {
headers.setResourceId(Integer.parseInt(reader.readLine()));
headers.setDriftDefinitionId(Integer.parseInt(reader.readLine()));
headers.setDriftDefinitionName(reader.readLine());
headers.setBasedir(reader.readLine());
headers.setType(DriftChangeSetCategory.fromCode(reader.readLine()));
headers.setVersion(Integer.parseInt(reader.readLine()));
} catch (IOException e) {
throw e;
} catch (Throwable t) {
throw new IllegalStateException("Invalid changeset headers, could not parse: ", t);
}
}
@Override
public Headers getHeaders() throws ChangeSetReaderException {
return headers;
}
@Override
public FileEntry read() throws ChangeSetReaderException {
try {
String line = reader.readLine();
if (line == null) {
return null;
}
if (line.charAt(0) == 'A') { // file added
int fileSizeEndIndex = line.indexOf(' ', 2);
long size = Long.parseLong(line.substring(2, fileSizeEndIndex));
int lastModifiedEndIndex = line.indexOf(' ', fileSizeEndIndex + 1);
long lastModified = Long.parseLong(line.substring(fileSizeEndIndex + 1, lastModifiedEndIndex));
int shaEndIndex = lastModifiedEndIndex + 65;
String sha = line.substring(lastModifiedEndIndex + 1, shaEndIndex);
String fileName = line.substring(shaEndIndex + 3);
return addedFileEntry(fileName, sha, lastModified, size);
}
if (line.charAt(0) == 'C') { // file modified
int fileSizeEndIndex = line.indexOf(' ', 2);
long size = Long.parseLong(line.substring(2, fileSizeEndIndex));
int lastModifiedEndIndex = line.indexOf(' ', fileSizeEndIndex + 1);
long lastModified = Long.parseLong(line.substring(fileSizeEndIndex + 1, lastModifiedEndIndex));
int newShaIndex = lastModifiedEndIndex + 65;
String newSha = line.substring(lastModifiedEndIndex + 1, newShaIndex);
int oldShaIndex = newShaIndex + 65;
String oldSha = line.substring(newShaIndex + 1, oldShaIndex);
String fileName = line.substring(oldShaIndex + 1);
return changedFileEntry(fileName, oldSha, newSha, lastModified, size);
}
if (line.charAt(0) == 'R') { // file deleted
String sha = line.substring(10, 74);
String fileName = line.substring(75);
return removedFileEntry(fileName, sha);
}
log.error("An error occurred while parsing " + metaDataFile.getAbsolutePath() + ": " + line.charAt(0)
+ " is not a recognized drift change set category code.");
throw new ChangeSetReaderException(line.charAt(0) + " is not a recognized drift change set category code.");
} catch (IOException e) {
log.error("An error ocurred while parsing " + metaDataFile.getAbsolutePath() + ": " + e.getMessage());
throw new ChangeSetReaderException("An error ocurred while parsing " + metaDataFile.getAbsolutePath(), e);
}
}
@Override
public void close() throws ChangeSetReaderException {
try {
reader.close();
} catch (IOException e) {
log
.warn("An error ocurred while trying to close " + metaDataFile.getAbsolutePath() + ": "
+ e.getMessage());
throw new ChangeSetReaderException("An error ocurred while trying to close "
+ metaDataFile.getAbsolutePath(), e);
}
}
@Override
public Iterator iterator() {
return new Iterator() {
private FileEntry next;
{
try {
next = read();
} catch (IOException e) {
throw new RuntimeException("Failed to create iterator: " + e);
}
}
@Override
public boolean hasNext() {
return next != null;
}
@Override
public FileEntry next() {
try {
FileEntry previous = next;
next = read();
if (next == null && closeStream) {
close();
}
return previous;
} catch (IOException e) {
throw new RuntimeException("Failed to get next " + FileEntry.class.getName() + ": " + e);
}
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
}