409 lines
14 KiB
Java
409 lines
14 KiB
Java
/**
|
|
* This software was developed and / or modified by Raytheon Company,
|
|
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
|
*
|
|
* U.S. EXPORT CONTROLLED TECHNICAL DATA
|
|
* This software product contains export-restricted data whose
|
|
* export/transfer/disclosure is restricted by U.S. law. Dissemination
|
|
* to non-U.S. persons whether in the United States or abroad requires
|
|
* an export license or other authorization.
|
|
*
|
|
* Contractor Name: Raytheon Company
|
|
* Contractor Address: 6825 Pine Street, Suite 340
|
|
* Mail Stop B8
|
|
* Omaha, NE 68106
|
|
* 402.291.0100
|
|
*
|
|
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
|
* further licensing information.
|
|
**/
|
|
package com.raytheon.openfire.plugin.detailedfeedlog;
|
|
|
|
import java.io.BufferedReader;
|
|
import java.io.File;
|
|
import java.io.FileNotFoundException;
|
|
import java.io.FileReader;
|
|
import java.io.FileWriter;
|
|
import java.io.IOException;
|
|
import java.text.ParseException;
|
|
import java.text.SimpleDateFormat;
|
|
import java.util.Date;
|
|
import java.util.HashMap;
|
|
import java.util.Map;
|
|
import java.util.Queue;
|
|
import java.util.TimerTask;
|
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
|
|
|
import org.dom4j.Element;
|
|
import org.jivesoftware.openfire.MessageRouter;
|
|
import org.jivesoftware.openfire.XMPPServer;
|
|
import org.jivesoftware.openfire.container.Plugin;
|
|
import org.jivesoftware.openfire.container.PluginManager;
|
|
import org.jivesoftware.openfire.muc.MUCEventDispatcher;
|
|
import org.jivesoftware.openfire.user.User;
|
|
import org.jivesoftware.openfire.user.UserManager;
|
|
import org.jivesoftware.openfire.user.UserNotFoundException;
|
|
import org.jivesoftware.util.JiveGlobals;
|
|
import org.jivesoftware.util.Log;
|
|
import org.jivesoftware.util.PropertyEventDispatcher;
|
|
import org.jivesoftware.util.PropertyEventListener;
|
|
import org.jivesoftware.util.TaskEngine;
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
import org.xmpp.packet.Message;
|
|
import org.xmpp.packet.Presence;
|
|
|
|
import com.raytheon.openfire.plugin.detailedfeedlog.listener.DetailedFeedLogEventListener;
|
|
|
|
/**
|
|
* Plugin that logs and purges qualifying packets in Openfire
|
|
*
|
|
* <pre>
|
|
*
|
|
* SOFTWARE HISTORY
|
|
*
|
|
* Date Ticket# Engineer Description
|
|
* ------------ ---------- ----------- --------------------------
|
|
* Jul 23, 2012 mnash Initial creation
|
|
*
|
|
* </pre>
|
|
*
|
|
* @author mnash
|
|
* @version 1.0
|
|
*/
|
|
|
|
public class DetailedFeedLogPlugin implements Plugin, PropertyEventListener {
|
|
|
|
// TODO, need to implement a read from the log file for if the server goes
|
|
// down
|
|
|
|
private static Logger logger = LoggerFactory
|
|
.getLogger(DetailedFeedLogPlugin.class);
|
|
|
|
private static Map<String, Queue<LogEntry>> entries;
|
|
|
|
private static final int defaultPurgeLogTime = 21600;
|
|
|
|
private static final int defaultRunInterval = 60;
|
|
|
|
// how long ago to purge, anything older than this many seconds will be
|
|
// purged
|
|
private int purgeLogTime = JiveGlobals.getIntProperty(LOG_TIME_TO_KEEP,
|
|
defaultPurgeLogTime);
|
|
|
|
// how often to run the purge
|
|
private int runInterval = JiveGlobals.getIntProperty(LOG_PURGE_INTERVAL,
|
|
defaultRunInterval);
|
|
|
|
private static final int SECONDS_TO_MILLIS = 1000;
|
|
|
|
// the constant for the global value for how long to keep in the logs
|
|
private static final String LOG_TIME_TO_KEEP = "detailedlogttl";
|
|
|
|
// the constant for the global value for how often to purge
|
|
private static final String LOG_PURGE_INTERVAL = "detailedlogfreq";
|
|
|
|
// the task that will run the purge
|
|
private TimerTask task;
|
|
|
|
private DetailedFeedLogEventListener feedListener;
|
|
|
|
public static final String SITE_INFO = "Site";
|
|
|
|
private SimpleDateFormat dateFormat = new SimpleDateFormat(
|
|
"MM/dd/yyyy h:mm a");
|
|
|
|
/*
|
|
* (non-Javadoc)
|
|
*
|
|
* @see
|
|
* org.jivesoftware.openfire.container.Plugin#initializePlugin(org.jivesoftware
|
|
* .openfire.container.PluginManager, java.io.File)
|
|
*/
|
|
@Override
|
|
public void initializePlugin(PluginManager arg0, File arg1) {
|
|
// register a listener for updates to the openfire configurations page
|
|
PropertyEventDispatcher.addListener(this);
|
|
|
|
entries = new HashMap<String, Queue<LogEntry>>();
|
|
|
|
// read the log in from the file
|
|
readLogInfo();
|
|
|
|
// start the timer that inits the purging capability
|
|
initPurge();
|
|
|
|
feedListener = new DetailedFeedLogEventListener();
|
|
MessageRouter router = XMPPServer.getInstance().getMessageRouter();
|
|
feedListener.setRouter(router);
|
|
|
|
// Make it possible for the listener to receive events.
|
|
MUCEventDispatcher.addListener(feedListener);
|
|
}
|
|
|
|
/*
|
|
* (non-Javadoc)
|
|
*
|
|
* @see org.jivesoftware.openfire.container.Plugin#destroyPlugin()
|
|
*/
|
|
@Override
|
|
public void destroyPlugin() {
|
|
// want to clean up nicely, so remove the chat listener
|
|
MUCEventDispatcher.removeListener(feedListener);
|
|
|
|
// flush all the current information out of log and write it to the feed
|
|
// log file
|
|
writeToFile();
|
|
entries.clear();
|
|
|
|
// cancel the task so we aren't trying to purge when there is no plugin
|
|
// running
|
|
TaskEngine.getInstance().cancelScheduledTask(task);
|
|
PropertyEventDispatcher.removeListener(this);
|
|
}
|
|
|
|
private void readLogInfo() {
|
|
Log.getLogDirectory();
|
|
File logDir = new File(Log.getLogDirectory());
|
|
File[] files = logDir.listFiles();
|
|
|
|
for (File file : files) {
|
|
try {
|
|
logger.info("Reading " + file.getName());
|
|
FileReader reader = new FileReader(file);
|
|
BufferedReader bReader = new BufferedReader(reader);
|
|
while (bReader.ready()) {
|
|
String line = bReader.readLine();
|
|
String[] splitLine = line.split("\\|");
|
|
String dateString = splitLine[0];
|
|
// replace the first parentheses and the second one with
|
|
// nothing, so the date can be formatted
|
|
dateString = dateString.replaceAll("\\(|\\)", "");
|
|
Date date = dateFormat.parse(dateString);
|
|
String user = splitLine[1];
|
|
String message = splitLine[3];
|
|
addToMemoryLog(date, user, message, file.getName()
|
|
.replaceAll(".log", ""));
|
|
}
|
|
} catch (FileNotFoundException e) {
|
|
logger.error("Unable to find " + file.getName(), e);
|
|
} catch (IOException e) {
|
|
logger.error("Unable to read from " + file.getName(), e);
|
|
} catch (ParseException e) {
|
|
logger.error("Unable to parse date", e);
|
|
} catch (ArrayIndexOutOfBoundsException e) {
|
|
logger.info("Unable to read " + file.getName(), e);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Log a message
|
|
*
|
|
* @param message
|
|
*/
|
|
public static void log(Message message, String room) {
|
|
User user = null;
|
|
try {
|
|
user = UserManager.getInstance().getUser(
|
|
message.getFrom().getResource());
|
|
} catch (UserNotFoundException e) {
|
|
logger.error("Unable to get user", e);
|
|
}
|
|
|
|
String site = getSiteFromPresence(user);
|
|
|
|
// format it with the site so the site can be sent with the packet later
|
|
log(user.getUsername() + "|" + site, message.getBody(), room);
|
|
}
|
|
|
|
/**
|
|
* To log in openfire
|
|
*
|
|
* @param user
|
|
* - fqname
|
|
* @param message
|
|
*/
|
|
private static void log(String user, String message, String room) {
|
|
logger.info("Logging : " + user + message);
|
|
Date date = new Date();
|
|
addToMemoryLog(date, user, message, room);
|
|
}
|
|
|
|
/**
|
|
* Add the log message to memory
|
|
*
|
|
* @param date
|
|
* @param user
|
|
* @param message
|
|
* @param room
|
|
*/
|
|
private static void addToMemoryLog(Date date, String user, String message,
|
|
String room) {
|
|
LogEntry entry = new LogEntry(date, user, message);
|
|
Queue<LogEntry> queue = null;
|
|
if (entries.containsKey(room)) {
|
|
queue = entries.get(room);
|
|
} else {
|
|
queue = addRoomToLog(room);
|
|
}
|
|
queue.add(entry);
|
|
}
|
|
|
|
public static Queue<LogEntry> addRoomToLog(String room) {
|
|
Queue<LogEntry> queue = new ConcurrentLinkedQueue<LogEntry>();
|
|
entries.put(room, queue);
|
|
return queue;
|
|
}
|
|
|
|
public static void removeRoomFromLog(String room) {
|
|
entries.remove(room);
|
|
}
|
|
|
|
private static String getSiteFromPresence(User user) {
|
|
Presence presence = XMPPServer.getInstance().getPresenceManager()
|
|
.getPresence(user);
|
|
|
|
// need to get the site from the presence, add that to the text that we
|
|
// log, and use that for filtering on the client side
|
|
Element props = presence.getChildElement("properties",
|
|
"http://www.jivesoftware.com/xmlns/xmpp/properties");
|
|
String site = null;
|
|
for (Object propObj : props.elements("property")) {
|
|
Element prop = (Element) propObj;
|
|
String name = prop.elementText("name");
|
|
String value = prop.elementText("value");
|
|
if (SITE_INFO.equals(name)) {
|
|
site = value;
|
|
break;
|
|
}
|
|
}
|
|
return site;
|
|
}
|
|
|
|
/**
|
|
* Write out the current in memory log to a file
|
|
*/
|
|
private void writeToFile() {
|
|
String logDir = Log.getLogDirectory();
|
|
try {
|
|
// writes out each log file for each room, all active and permanent,
|
|
// and for rooms that the purge has not removed all logs yet
|
|
for (String room : entries.keySet()) {
|
|
File file = new File(logDir + room + ".log");
|
|
FileWriter writer = new FileWriter(file);
|
|
|
|
for (LogEntry entry : entries.get(room)) {
|
|
writer.write("(" + dateFormat.format(entry.getDate()) + ")");
|
|
writer.write("|" + entry.getUsername() + "|");
|
|
writer.write(entry.getMessage());
|
|
writer.write("\n");
|
|
}
|
|
writer.close();
|
|
|
|
// clean up empty logs
|
|
if (file.length() == 0) {
|
|
removeRoomFromLog(room);
|
|
file.delete();
|
|
}
|
|
}
|
|
} catch (IOException e) {
|
|
logger.error("Unable to write to file", e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Method for starting the TimerTask that runs the purge on the file
|
|
*/
|
|
private void initPurge() {
|
|
task = new TimerTask() {
|
|
@Override
|
|
public void run() {
|
|
Thread thread = new Thread(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
// the current time minus the purge log time in
|
|
// millis creates the latest time to keep
|
|
Date latestTimeToKeep = new Date(
|
|
System.currentTimeMillis()
|
|
- (purgeLogTime * SECONDS_TO_MILLIS));
|
|
String dateText = dateFormat.format(latestTimeToKeep);
|
|
logger.info("Purging the log of anything before "
|
|
+ dateText);
|
|
|
|
for (String room : entries.keySet()) {
|
|
Queue<LogEntry> queue = entries.get(room);
|
|
LogEntry entry = queue.peek();
|
|
while (entry != null) {
|
|
if (entry.getDate().before(latestTimeToKeep)) {
|
|
queue.remove();
|
|
entry = queue.peek();
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// write to file now since we have possibly purged items
|
|
writeToFile();
|
|
}
|
|
});
|
|
thread.run();
|
|
}
|
|
};
|
|
// schedule this to start in runInterval and to run every runInterval
|
|
// seconds
|
|
TaskEngine.getInstance().schedule(task,
|
|
runInterval * SECONDS_TO_MILLIS,
|
|
runInterval * SECONDS_TO_MILLIS);
|
|
}
|
|
|
|
/**
|
|
* @return the log
|
|
*/
|
|
public static Queue<LogEntry> getLog(String room) {
|
|
return entries.get(room);
|
|
}
|
|
|
|
public void propertyDeleted(String arg0, Map<String, Object> arg1) {
|
|
// do nothing, as we want to keep the current properties if some are
|
|
// deleted
|
|
}
|
|
|
|
@Override
|
|
public void propertySet(String arg0, Map<String, Object> arg1) {
|
|
if (arg0.equals(LOG_PURGE_INTERVAL)) {
|
|
// 60 is the default value (1 minute)
|
|
int tempPurgeInterval = JiveGlobals.getIntProperty(arg0,
|
|
defaultRunInterval);
|
|
if (tempPurgeInterval != runInterval) {
|
|
runInterval = tempPurgeInterval;
|
|
logger.info("Log Purge Time has been changed to " + runInterval
|
|
+ " seconds");
|
|
TaskEngine.getInstance().cancelScheduledTask(task);
|
|
TaskEngine.getInstance().schedule(task,
|
|
runInterval * SECONDS_TO_MILLIS,
|
|
runInterval * SECONDS_TO_MILLIS);
|
|
}
|
|
} else if (arg0.equals(LOG_TIME_TO_KEEP)) {
|
|
// 21600 is the default value (6 hours)
|
|
int tempPurgeTime = JiveGlobals.getIntProperty(arg0,
|
|
defaultPurgeLogTime);
|
|
if (tempPurgeTime != purgeLogTime) {
|
|
purgeLogTime = tempPurgeTime;
|
|
logger.info("Log Time to Keep has been changed to "
|
|
+ purgeLogTime + " seconds");
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void xmlPropertyDeleted(String arg0, Map<String, Object> arg1) {
|
|
// do nothing, as we don't care about xml properties deleted
|
|
}
|
|
|
|
@Override
|
|
public void xmlPropertySet(String arg0, Map<String, Object> arg1) {
|
|
// do nothing, as we don't care about xml properties set
|
|
}
|
|
}
|