package com.rayo.server.cdr; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.text.SimpleDateFormat; import java.util.Date; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import org.springframework.jmx.export.annotation.ManagedOperation; import org.springframework.jmx.export.annotation.ManagedResource; import com.rayo.core.cdr.Cdr; import com.rayo.core.cdr.CdrException; import com.rayo.server.jmx.FileCdrMXBean; import com.voxeo.logging.Loggerf; @ManagedResource(objectName = "com.rayo:Type=Admin,name=File CDR", description = "Filebased CDR storage") public class FileCdrStorageStrategy implements CdrStorageStrategy, FileCdrMXBean { private Loggerf logger = Loggerf.getLogger(FileCdrStorageStrategy.class); private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); // will keep this one for legacy reasons private String path; private String baseFolder = "/tmp/cdrs"; private boolean append = true; private String lastUsedPath; private OutputStream out; // Lock to enable File settings hot replacement private final ReadWriteLock lock = new ReentrantReadWriteLock(); public void init() throws IOException { logger.info("Initializing Filebased CDR storage"); if (baseFolder == null && path == null) { throw new IllegalStateException("Don't know where to write CDRs. You need to set the baseFolder variable."); } if (baseFolder != null) { File f = new File(baseFolder); if (!f.exists()) { boolean result = f.mkdirs(); if (!result) { throw new IllegalStateException(String.format("Could not create CDRs folder %s", f.getAbsolutePath())); } } // unset legacy stuff path = null; } else { File file = new File(path); if (!file.exists()) { File parent = file.getParentFile(); if (!parent.exists()) { parent.mkdirs(); } } out = new BufferedOutputStream(new FileOutputStream(file,append)); } lastUsedPath = null; } public void shutdown() { logger.info("Shutting down filebased CDR storage"); if (out != null) { try { out.close(); } catch (IOException e) { logger.error(e.getMessage(),e); } } } @Override public void store(Cdr cdr) throws CdrException { try { if (baseFolder != null) { out = getFileStream(cdr); } lock.readLock().lock(); out.write(cdr.toString().getBytes()); out.flush(); } catch (IOException e) { throw new CdrException(e); } finally { lock.readLock().unlock(); } } private synchronized OutputStream getFileStream(Cdr cdr) { OutputStream oldOut = out; path = sdf.format(new Date(cdr.getStartTime())); if (!path.equals(lastUsedPath)) { File f = new File(baseFolder + "/" + path + ".xml"); if (!f.exists()) { if (out != null) { try { out.close(); } catch (IOException ioe) { logger.error(ioe.getMessage(), ioe); } } logger.debug("Will store CDR at %s", f.getAbsolutePath()); try { out = new BufferedOutputStream(new FileOutputStream(f)); } catch (IOException ioe) { logger.error(ioe.getMessage(), ioe); out = oldOut; } } else { logger.debug("Will store CDR at %s", f.getAbsolutePath()); if (out == null) { try { out = new BufferedOutputStream(new FileOutputStream(f)); } catch (IOException ioe) { logger.error(ioe.getMessage(), ioe); out = oldOut; } } } } lastUsedPath = path; return out; } String getCurrentFilePath() { if (baseFolder != null) { String path = sdf.format(new Date()); return baseFolder + "/" + path + ".xml"; } else { return path; } } @Override @ManagedOperation(description = "Change CDRs audit file") public void changeFile(String filename) { logger.info("Changing CDRs audit file to %s", filename); String oldPath = this.path; try { // We do not let the system to do any logging while we are changing the config lock.writeLock().lock(); this.path = filename; init(); } catch (IOException ioe) { logger.error("Could not replace File storage configuration settings. Rolling back to previous setup"); this.path = oldPath; } finally { lock.writeLock().unlock(); } } public void setPath(String path) { this.path = path; } public String getPath() { return path; } public void setAppend(boolean append) { this.append = append; } public String getBaseFolder() { return baseFolder; } public void setBaseFolder(String baseFolder) { if (baseFolder.endsWith("/")) { baseFolder = baseFolder.substring(0, baseFolder.length()-1); } this.baseFolder = baseFolder; } }