/*****************************************************************************
*
* Copyright (C) Zenoss, Inc. 2011, all rights reserved.
*
* This content is made available according to terms specified in
* License.zenoss under the directory where your Zenoss product is installed.
*
****************************************************************************/
package org.zenoss.zep.index.impl;
import org.zenoss.zep.ZepUtils;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;
/**
* Saves state of index rebuild process so it can be restarted if ZEP is shut down.
*/
class IndexRebuildState {
private final int indexVersion;
private final byte[] indexVersionHash;
private final long throughTime;
private Long startingLastSeen;
private String startingUuid;
public IndexRebuildState(int indexVersion, byte[] indexVersionhash, long throughTime, Long startingLastSeen, String startingUuid) {
this.indexVersion = indexVersion;
this.indexVersionHash = indexVersionhash;
this.throughTime = throughTime;
this.startingLastSeen = startingLastSeen;
this.startingUuid = startingUuid;
}
public int getIndexVersion() {
return indexVersion;
}
public byte[] getIndexVersionHash() {
return indexVersionHash;
}
public long getThroughTime() {
return throughTime;
}
public Long getStartingLastSeen() {
return startingLastSeen;
}
public String getStartingUuid() {
return startingUuid;
}
private static String toHex(byte[] bytes) {
StringBuilder sb = new StringBuilder(bytes.length * 2);
for (byte b : bytes) {
int i = b & 0xff;
String s = Integer.toHexString(i);
if (s.length() == 1) {
sb.append('0');
}
sb.append(s);
}
return sb.toString();
}
private static byte[] fromHex(String hexString) {
if (hexString.length() % 2 != 0) {
throw new IllegalArgumentException("Hex string should be an even number of characters");
}
byte[] bytes = new byte[hexString.length()/2];
for (int i = 0; i < bytes.length; i++) {
int strIndex = i * 2;
bytes[i] = (byte) Integer.parseInt(hexString.substring(strIndex, strIndex+2), 16);
}
return bytes;
}
public void setStartingLastSeen(Long startingLastSeen) {
this.startingLastSeen = startingLastSeen;
}
public void setStartingUuid(String startingUuid) {
this.startingUuid = startingUuid;
}
/**
* Saves the current state to a file (to be able to restart the index rebuilding process).
*
* @param file The file to save the current state to.
* @throws IOException If the current state cannot be saved.
*/
public void save(File file) throws IOException {
Properties properties = new Properties();
properties.setProperty("zep.index.version", String.valueOf(indexVersion));
if (indexVersionHash != null) {
properties.setProperty("zep.index.version_hash", toHex(indexVersionHash));
}
properties.setProperty("zep.index.through_time", Long.toString(throughTime));
if (startingLastSeen != null) {
properties.setProperty("zep.index.starting_last_seen", startingLastSeen.toString());
}
if (startingUuid != null) {
properties.setProperty("zep.index.starting_uuid", startingUuid);
}
FileOutputStream fos = null;
File tempFile = null;
try {
tempFile = File.createTempFile("tmp", ".properties", file.getParentFile());
fos = new FileOutputStream(tempFile);
properties.store(fos, "ZEP Internal Indexing State - Do Not Modify");
fos.close();
fos = null;
if (!tempFile.renameTo(file)) {
throw new IOException("Failed to rename " + tempFile.getAbsolutePath() + " to " +
file.getAbsolutePath());
}
} finally {
ZepUtils.close(fos);
if (tempFile != null && tempFile.isFile()) {
if (!tempFile.delete()) {
tempFile.deleteOnExit();
}
}
}
}
/**
* Loads the state of the index rebuilding process from the specified file.
*
* @param file The file to load the state from.
* @return The state loaded from the file, or null if the file doesn't exist or the state couldn't be read.
* @throws IOException If an error occurs reading from the file.
*/
public static IndexRebuildState loadState(File file) throws IOException {
IndexRebuildState state = null;
if (file.isFile()) {
BufferedInputStream bis = null;
try {
bis = new BufferedInputStream(new FileInputStream(file));
Properties properties = new Properties();
properties.load(bis);
int indexVersion = Integer.valueOf(properties.getProperty("zep.index.version"));
byte[] indexVersionHash = null;
String indexVersionHashStr = properties.getProperty("zep.index.version_hash");
if (indexVersionHashStr != null) {
indexVersionHash = fromHex(indexVersionHashStr);
}
long throughTime = Long.valueOf(properties.getProperty("zep.index.through_time"));
String startingUuid = properties.getProperty("zep.index.starting_uuid");
Long startingLastSeen = null;
String startingLastSeenStr = properties.getProperty("zep.index.starting_last_seen");
if (startingLastSeenStr != null) {
startingLastSeen = Long.valueOf(startingLastSeenStr);
}
state = new IndexRebuildState(indexVersion, indexVersionHash, throughTime, startingLastSeen, startingUuid);
} catch (Exception e) {
throw new IOException(e.getLocalizedMessage(), e);
} finally {
ZepUtils.close(bis);
}
}
return state;
}
}