package org.rhq.core.pc.drift;
import static java.io.File.separator;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.apache.commons.io.DirectoryWalker;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.rhq.core.util.MessageDigestGenerator;
public class SnapshotGenerator extends DirectoryWalker {
private final Log log = LogFactory.getLog(SnapshotGenerator.class);
private MessageDigestGenerator digestGenerator = new MessageDigestGenerator(MessageDigestGenerator.SHA_256);
private File snapshotDir;
/** @param dir The directory to which snapshot files will be written. */
public void setSnapshotDir(File dir) {
snapshotDir = dir;
}
/**
* Generates snapshot data and meta data files for the specified resource id starting at <code>basedir</code>. The
* files are written to the directory specified in {@link #setSnapshotDir(java.io.File)}. The files are currently
* stored as snapshot_dir/<resourceId>-snapshot.zip and snapshot_dir/<resourceId>_snapshot_metadata.txt.
*
* @param resourceId The id of the resource for which the snapshot is being created
* @param basedir The root directory from which the snapshot will be taken
* @return A {@link SnapshotHandle} that points the generated files on disk.
* @throws IOException If any errors occur
*/
public SnapshotHandle generateSnapshot(int resourceId, File basedir) throws IOException {
List<File> files = new ArrayList<File>();
walk(basedir, files);
File metadatFile = new File(snapshotDir, resourceId + "_snapshot_metadata.txt");
PrintWriter metadataWriter = new PrintWriter(new BufferedOutputStream(new FileOutputStream(metadatFile)));
File zipFile = new File(snapshotDir, resourceId + "-snapshot" + ".zip");
ZipOutputStream zos = null;
try {
zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipFile)));
for (File file : files) {
String relativePath = relativePath(basedir, file);
metadataWriter.println(relativePath + " " + sha256(file));
InputStream istream = null;
try {
istream = new BufferedInputStream(new FileInputStream(new File(basedir.getParent(), relativePath)));
ZipEntry entry = new ZipEntry(relativePath);
zos.putNextEntry(entry);
IOUtils.copy(istream, zos);
} catch (IOException e) {
log.error("Failed to add file " + file + " to zipfile " + zipFile + ".", e);
} finally {
if (istream != null) {
istream.close();
}
}
}
} finally {
if (metadataWriter != null) {
metadataWriter.close();
}
if (zos != null) {
zos.close();
}
}
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
IOUtils.copy(new FileInputStream(zipFile), byteStream);
return new SnapshotHandle(zipFile, metadatFile);
}
private String relativePath(File basedir, File file) {
return FilenameUtils.getName(basedir.getAbsolutePath()) + separator +
file.getAbsolutePath().substring(basedir.getAbsolutePath().length() + 1);
}
private String sha256(File file) throws IOException {
return digestGenerator.calcDigestString(file);
}
@Override
protected boolean handleDirectory(File directory, int depth, Collection results) throws IOException {
return true;
}
@Override
protected void handleFile(File file, int depth, Collection results) throws IOException {
results.add(file);
}
}