/*******************************************************************************
* Copyright (c) 2011 The Board of Trustees of the Leland Stanford Junior University
* as Operator of the SLAC National Accelerator Laboratory.
* Copyright (c) 2011 Brookhaven National Laboratory.
* EPICS archiver appliance is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*******************************************************************************/
package edu.stanford.slac.archiverappliance.PlainPB.utils;
import java.io.BufferedOutputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.sql.Timestamp;
import java.util.LinkedList;
import org.apache.log4j.Logger;
import org.epics.archiverappliance.ByteArray;
import org.epics.archiverappliance.Event;
import org.epics.archiverappliance.common.TimeUtils;
import org.epics.archiverappliance.utils.nio.ArchPaths;
import edu.stanford.slac.archiverappliance.PB.EPICSEvent.PayloadInfo;
import edu.stanford.slac.archiverappliance.PB.utils.LineEscaper;
import edu.stanford.slac.archiverappliance.PlainPB.FileBackedPBEventStream;
import edu.stanford.slac.archiverappliance.PlainPB.PBFileInfo;
/**
* Make a copy of the specified PB file only including the samples between the specified timestamps.
*
* @author mshankar
*/
public class SlicePBFile {
private static Logger logger = Logger.getLogger(SlicePBFile.class.getName());
private static boolean verboseMode = false;
/**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
if(args == null || args.length < 4) {
printHelpMsg();
return;
}
LinkedList<String> argsAfterOptions = new LinkedList<String>();
for(String arg : args) {
if(arg.equals("-v")) {
verboseMode = true;
} else if(arg.equals("-h")) {
printHelpMsg();
return;
} else {
argsAfterOptions.add(arg);
}
}
if(argsAfterOptions.size() < 4) {
printHelpMsg();
return;
}
String srcFileName = argsAfterOptions.get(0);
String startTime = argsAfterOptions.get(1);
String endTime = argsAfterOptions.get(2);
String destFileName = argsAfterOptions.get(3);
if(srcFileName.equals(destFileName)) {
logger.error("Source and dest files are the same");
printHelpMsg();
return;
}
Path srcPath = Paths.get(srcFileName);
if(!Files.exists(srcPath) || !Files.isRegularFile(srcPath)) {
logger.error("Source path " + srcPath.toString() + " does not seem to exist or is not a regular file.");
return;
}
Timestamp startTs = TimeUtils.convertFromISO8601String(startTime);
Timestamp endTs = TimeUtils.convertFromISO8601String(endTime);
if(!startTs.before(endTs)) {
logger.error("Start time " + startTime + " is not before " + endTime);
return;
}
Path destPath = Paths.get(destFileName);
if(Files.exists(destPath)) {
logger.error("Dest path " + destPath.toString() + " already seems to exist");
return;
}
slicePBFile(srcPath, startTs, endTs, destPath);
}
private static void printHelpMsg() {
System.out.println();
System.out.println("Usage: run.sh edu.stanford.slac.archiverappliance.PlainPB.utils.SlicePBFile <Absolute Path to Source PB File> <ISO 8601 start time> <ISO 8601 end time> <Absolute Path to Dest PB File>");
System.out.println();
System.out.println("This utility copies the source PV file into the dest PB file; only the samples >= start time and < end time are copied over.");
System.out.println("For example: run.sh edu.stanford.slac.archiverappliance.PlainPB.utils.SlicePBFile /arch/lts/ABC/DEF/XYZ\\:2015.pb 2013-01-01T00:00:00.000Z 2013-02-01T00:00:00.000Z Only_January_2013.pb");
System.out.println("\t-h Prints this help");
System.out.println("\t-v Turns on verbose logging.");
System.out.println();
System.out.println();
System.out.println();
}
public static void slicePBFile(Path srcPath, Timestamp startTs, Timestamp endTs, Path destPath) {
logger.info("Slicing " + srcPath.toString() + " from " + TimeUtils.convertToISO8601String(startTs) + " to " + TimeUtils.convertToISO8601String(endTs) + " into " + destPath);
try (ArchPaths contexts = new ArchPaths()) {
try {
PBFileInfo info = new PBFileInfo(srcPath);
try(FileBackedPBEventStream strm = new FileBackedPBEventStream(info.getPVName(), srcPath, info.getType());
OutputStream os = new BufferedOutputStream(Files.newOutputStream(destPath, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING))) {
byte[] headerBytes = LineEscaper.escapeNewLines(PayloadInfo.newBuilder()
.setPvname(info.getPVName())
.setType(strm.getDescription().getArchDBRType().getPBPayloadType())
.setYear(info.getDataYear())
.build().toByteArray());
os.write(headerBytes);
os.write(LineEscaper.NEWLINE_CHAR);
int eventNumber = 0;
for(Event ev : strm) {
try {
Timestamp eventTs = ev.getEventTimeStamp();
if((eventTs.equals(startTs) || eventTs.after(startTs)) && eventTs.before(endTs)) {
ByteArray val = ev.getRawForm();
os.write(val.data, val.off, val.len);
os.write(LineEscaper.NEWLINE_CHAR);
} else {
if(verboseMode) {
logger.debug("Skipping event at " + TimeUtils.convertToISO8601String(eventTs));
}
}
} catch(Throwable t) {
logger.error("Exception processing event " + eventNumber, t);
}
eventNumber++;
}
} catch(Throwable t) {
logger.error("Exception fixing PB file " + srcPath, t);
}
} catch(Exception ex) {
logger.error("Exception fixing PB file " + srcPath, ex);
}
} catch(Exception ex) {
logger.error("Exception fixing PB file " + srcPath, ex);
}
}
}