/** * */ package com.trendrr.oss.appender; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.OutputStream; import java.util.Date; import java.util.UUID; import java.util.zip.GZIPOutputStream; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import com.trendrr.oss.FileHelper; import com.trendrr.oss.StringHelper; import com.trendrr.oss.TimeAmount; import com.trendrr.oss.Timeframe; import com.trendrr.oss.TypeCast; import com.trendrr.oss.appender.exceptions.FileClosedException; import com.trendrr.oss.exceptions.TrendrrIOException; /** * @author Dustin Norlander * @created Jun 17, 2013 * */ public class TimeAmountFile { protected static Log log = LogFactory.getLog(TimeAmountFile.class); private File file; private long epoch; private TimeAmount timeAmount; private boolean stale = false; private boolean callbackreturn = false; private long maxBytes; private long curBytes = 0; private boolean gzip = false; private OutputStream os = null; // private FileWriter writer = null; private Date lastWrite = new Date(); @Override public synchronized String toString() { return "TAF: filename:" + file.getName() + " stale: " + stale; } public TimeAmountFile(TimeAmount ta, long epoch, String dir, long maxBytes, boolean gzip) throws Exception { if (!dir.endsWith(File.separator)) { dir = dir + File.separator; } this.epoch = epoch; this.timeAmount = ta; this.maxBytes = maxBytes; this.gzip = gzip; boolean exists = true; while(exists) { //guarentee uniqueness. //we use current millisecond in the hour + a 5 character random string //this should be sufficiently unique in most cases. Date start = ta.fromTrendrrEpoch(ta.toTrendrrEpoch(new Date())); long millis = new Date().getTime()-start.getTime(); String filename = dir + epoch +"_" + ta.abbreviation() + "__" + millis + StringHelper.getRandomString(5); if (this.gzip) { filename += ".gz"; } filename = FileHelper.toSystemDependantFilename(filename); FileHelper.createDirectories(filename); this.file = new File(filename); exists = !file.createNewFile(); } this.os = new BufferedOutputStream(new FileOutputStream(file, true)); if (this.gzip) { this.os = new GZIPOutputStream(this.os); } log.warn("Created new TimeAmountFile: "+file.getAbsolutePath()); } /** * Creates from previously created file. * @param file * @throws Exception */ public TimeAmountFile(File file, long maxBytes) throws Exception { String filename = file.getName(); String tmp[] = filename.split("_"); if (tmp.length < 3) { throw new TrendrrIOException("File : " + filename + " is not a TimeAmountFile"); } if (filename.endsWith(".gz")) { this.gzip = true; } this.epoch = TypeCast.cast(Long.class, tmp[0]); this.timeAmount = TimeAmount.instance(tmp[1]); this.file = file; this.os = new BufferedOutputStream(new FileOutputStream(file, true)); if (this.gzip) { this.os = new GZIPOutputStream(this.os); } // this.writer = new FileWriter(this.file, true); this.maxBytes = maxBytes; } /** * stales the file. * @param callback * @return */ // Moved The delete code to callback level for deleting after the uploading protected synchronized void stale(TimeAmountFileCallback callback) { if (this.callbackreturn) return; //do nothing.. this.callbackreturn = true; this.setStale(); callback.staleFile(this); } /** * Append to this file. The string will be utf8 encoded. * @param str * @throws FileClosedException * @throws IOException */ public synchronized void append(String str) throws FileClosedException, IOException { this.append(str.getBytes("utf8")); } /** * Append to this file. * @param str * @throws FileClosedException * @throws IOException */ public synchronized void append(byte[] bytes) throws FileClosedException, IOException { if (stale) { throw new FileClosedException(); } //check that we havent gone over the max bytes if (maxBytes > 0 && curBytes >= maxBytes) { this.setStale(); throw new FileClosedException(); } this.curBytes += bytes.length; // System.out.println(this.curBytes + " " + maxBytes); this.lastWrite = new Date(); this.os.write(bytes); this.os.flush(); } public synchronized void setStale() { if (stale) { return; } stale = true; try { this.os.flush(); this.os.close(); // // this.writer.flush(); // this.writer.close(); } catch (Exception x) { log.error("Caught", x); } } public synchronized File getFile() { return file; } public synchronized long getEpoch() { return epoch; } public synchronized TimeAmount getTimeAmount() { return timeAmount; } public synchronized long getMaxBytes() { return maxBytes; } public synchronized long getCurBytes() { return curBytes; } public synchronized Date getLastWrite() { return lastWrite; } }