package org.ifsoft.openlink.calllog; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import org.jivesoftware.database.DbConnectionManager; import org.jivesoftware.util.Log; /** * */ public class DatabaseAppender implements Appender { private static final String INSERT_CALL_LOG = "INSERT INTO ofcalllog(tscId, callId, profileId, interestId, state, direction, startTimestamp, duration, callerName, callerNumber, calledName, calledNumber) VALUES(?,?,?,?,?,?,?,?,?,?,?,?)"; private static final String INSERT_PARTICIPANT_LOG = "INSERT INTO ofparticipantlog(tscId, callId, jid, direction, type, startTimestamp, duration) VALUES(?,?,?,?,?,?,?)"; // private List<LogRecord> buffer = null; private Queue<LogRecord> buffer = null; private int bufferSize = 1; private ExecutorService executor = Executors.newCachedThreadPool(); public DatabaseAppender() { // buffer = Collections.synchronizedList(new ArrayList<LogRecord>()); buffer = new ConcurrentLinkedQueue<LogRecord>(); } public void finalize() { // Log.debug("finalize"); flushBuffer(); } public void append(LogRecord logRecord) { Log.debug("append " + logRecord); if (bufferSize <= 1) { executor.submit(new LogRecordWorker(logRecord)); } else { // buffer.add(logRecord); buffer.offer(logRecord); if (buffer.size() >= bufferSize) { flushBuffer(); } } } private void flushBuffer() { Log.debug("flushBuffer"); // move all the records from buffers to own list to be written List<LogRecord> logRecordList = null; synchronized (buffer) { logRecordList = new ArrayList<LogRecord>(); LogRecord logRecord = null; for (int i = 0; i < bufferSize; i++) { logRecord = buffer.poll(); if (logRecord == null) { break; } logRecordList.add(logRecord); } } // new Thread(new LogRecordWorker(logRecordList)).start(); executor.submit(new LogRecordWorker(logRecordList)); } private void insertLog(Connection conn, LogRecord logRecord) throws Exception { if (logRecord instanceof CallLogRecord) { insertCallLog(conn, (CallLogRecord)logRecord); } else if (logRecord instanceof ParticipantLogRecord) { insertParticipantLog(conn, (ParticipantLogRecord)logRecord); } else { // Invalid type of logRecord object. Log.error("Invalid type of logRecord"); } } private void insertCallLog(Connection conn, CallLogRecord callLogRecord) throws Exception { Log.debug("insertCallLog " + callLogRecord); PreparedStatement stmt = null; try { stmt = conn.prepareStatement(INSERT_CALL_LOG); stmt.setString(1, callLogRecord.getTscId()); stmt.setString(2, callLogRecord.getCallId()); stmt.setString(3, callLogRecord.getProfileId()); stmt.setString(4, callLogRecord.getInterestId()); stmt.setString(5, callLogRecord.getState()); stmt.setString(6, callLogRecord.getDirection()); stmt.setTimestamp(7, new Timestamp(callLogRecord.getStartTimestamp())); stmt.setLong(8, callLogRecord.getDuration()); stmt.setString(9, callLogRecord.getCaller().getName()); stmt.setString(10, callLogRecord.getCaller().getNumber()); stmt.setString(11, callLogRecord.getCalled().getName()); stmt.setString(12, callLogRecord.getCalled().getNumber()); stmt.executeUpdate(); } catch (Exception e) { throw e; } finally { DbConnectionManager.closeStatement(stmt); } } private void insertParticipantLog(Connection conn, ParticipantLogRecord participantLogRecord) throws Exception { Log.debug("insertParticipantLog " + participantLogRecord); PreparedStatement stmt = null; try { stmt = conn.prepareStatement(INSERT_PARTICIPANT_LOG); stmt.setString(1, participantLogRecord.getTscId()); stmt.setString(2, participantLogRecord.getCallId()); stmt.setString(3, participantLogRecord.getJid()); stmt.setString(4, participantLogRecord.getDirection()); stmt.setString(5, participantLogRecord.getType()); stmt.setTimestamp(6, new Timestamp(participantLogRecord.getStartTimestamp())); stmt.setLong(7, participantLogRecord.getDuration()); stmt.executeUpdate(); } catch (Exception e) { throw e; } finally { DbConnectionManager.closeStatement(stmt); } } class LogRecordWorker implements Runnable { private List<LogRecord> logRecordList = null; private LogRecord logRecord = null; LogRecordWorker(List<LogRecord> logRecordList) { this.logRecordList = logRecordList; } LogRecordWorker(LogRecord logRecord) { this.logRecord = logRecord; } public void run() { Log.debug("LogRecordWorker.run " + logRecordList + ", " + logRecord); // write records to database if (logRecordList != null) { Connection conn = null; Iterator<LogRecord> iterator = logRecordList.iterator(); LogRecord logRecord = null; try { conn = DbConnectionManager.getConnection(); while (iterator.hasNext()) { logRecord = iterator.next(); // insert log record to database insertLog(conn, logRecord); } } catch (Exception e) { Log.error("Failed to write logs", e); } finally { DbConnectionManager.closeConnection(conn); } } else if (logRecord != null) { Connection conn = null; try { conn = DbConnectionManager.getConnection(); // insert log record to database insertLog(conn, logRecord); } catch (Exception e) { Log.error("Failed to write logs", e); } finally { DbConnectionManager.closeConnection(conn); } } } } }