package thaw.plugins;
import java.awt.BorderLayout;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.JButton;
import java.util.Observer;
import java.util.Observable;
import java.util.Vector;
import java.util.Iterator;
import java.sql.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.DataInputStream;
import java.io.BufferedReader;
import thaw.core.Core;
import thaw.core.Logger;
import thaw.gui.IconBox;
import thaw.gui.FileChooser;
import thaw.core.I18n;
import thaw.core.Plugin;
import thaw.core.ThawThread;
import thaw.core.ThawRunnable;
import thaw.fcp.FCPQueueManager;
import thaw.fcp.FCPTransferQuery;
import thaw.fcp.FreenetURIHelper;
import thaw.plugins.transferLogs.*;
public class TransferLogs implements Plugin, ActionListener, Observer {
public final static byte TRANSFER_TYPE_NULL = 0;
public final static byte TRANSFER_TYPE_DOWNLOAD = 1;
public final static byte TRANSFER_TYPE_INSERTION = 2;
public final static String[] TRANSFER_TYPE_NAMES = {
I18n.getMessage("thaw.plugin.transferLogs.importedKey"),
I18n.getMessage("thaw.common.download"),
I18n.getMessage("thaw.common.insertion")
};
private Core core;
private Hsqldb db;
private JPanel tab;
private JButton purgeLogs;
private JButton importKeys;
private JButton exportKeys;
private TransferTable table;
public TransferLogs() {
}
public boolean run(final Core core) {
this.core = core;
/* loading hsqldb */
if(core.getPluginManager().getPlugin("thaw.plugins.Hsqldb") == null) {
Logger.info(this, "Loading Hsqldb plugin");
if(core.getPluginManager().loadPlugin("thaw.plugins.Hsqldb") == null
|| !core.getPluginManager().runPlugin("thaw.plugins.Hsqldb")) {
Logger.error(this, "Unable to load thaw.plugins.Hsqldb !");
return false;
}
}
db = (Hsqldb)core.getPluginManager().getPlugin("thaw.plugins.Hsqldb");
db.registerChild(this);
createTables();
/* making GUI */
tab = new JPanel(new BorderLayout(5, 5));
JLabel topLabel = new JLabel(I18n.getMessage("thaw.plugin.transferLogs.transferLogs"));
topLabel.setIcon(IconBox.file);
table = new TransferTable(db, core.getConfig());
purgeLogs = new JButton(I18n.getMessage("thaw.plugin.transferLogs.purgeLogs"),
IconBox.minDelete);
importKeys = new JButton(I18n.getMessage("thaw.plugin.transferLogs.importKeys"),
IconBox.minImportAction);
exportKeys = new JButton(I18n.getMessage("thaw.plugin.transferLogs.exportKeys"),
IconBox.minExportAction);
purgeLogs.addActionListener(this);
importKeys.addActionListener(this);
exportKeys.addActionListener(this);
JPanel buttonPanel = new JPanel();
buttonPanel.add(purgeLogs);
buttonPanel.add(importKeys);
buttonPanel.add(exportKeys);
JPanel southPanel = new JPanel(new BorderLayout());
southPanel.add(buttonPanel, BorderLayout.WEST);
southPanel.add(new JLabel(""), BorderLayout.CENTER);
tab.add(topLabel, BorderLayout.NORTH);
tab.add(table.getPanel(), BorderLayout.CENTER);
tab.add(southPanel, BorderLayout.SOUTH);
setAsObserverEverywhere();
core.getMainWindow().addTab(I18n.getMessage("thaw.plugin.transferLogs.transferLogsShort"),
thaw.gui.IconBox.file,
tab);
return true;
}
public void stop() {
core.getMainWindow().removeTab(tab);
core.getQueueManager().deleteObserver(this);
/* TODO : delete observers ! */
/* Hm should we ? Just remove the observer on the queue should be enought ? */
/* Others observers will just keep data sync ? */
db.unregisterChild(this);
}
public String getNameForUser() {
return I18n.getMessage("thaw.plugin.transferLogs.transferLogs");
}
public javax.swing.ImageIcon getIcon() {
return thaw.gui.IconBox.file;
}
protected void createTables() {
sendQuery("CREATE CACHED TABLE transferLogs ("
+ "id INTEGER IDENTITY NOT NULL,"
+ "dateStart TIMESTAMP NOT NULL,"
+ "dateEnd TIMESTAMP NULL,"
+ "transferType TINYINT NOT NULL,"
+ "key VARCHAR(500) NULL,"
+ "filename VARCHAR(128) NULL, "
+ "size BIGINT NULL, " /* long */
+ "isDup BOOLEAN NOT NULL, "
+ "isSuccess BOOLEAN NOT NULL, "
+ "PRIMARY KEY (id))");
}
protected boolean isDup(String key) {
return isDup(db, key);
}
public static boolean isDup(Hsqldb db, String key) {
try {
synchronized(db.dbLock) {
PreparedStatement st;
st = db.getConnection().prepareStatement("SELECT id FROM transferLogs "+
"WHERE LOWER(key) LIKE ? AND isSuccess = TRUE");
st.setString(1, FreenetURIHelper.getComparablePart(key)+"%");
ResultSet set = st.executeQuery();
boolean b = set.next();
st.close();
return b;
}
} catch(SQLException e) {
Logger.error(new TransferLogs(), "Unable to know if a key is dup in the event because : "+e.toString());
}
return false;
}
protected boolean sendQuery(String query) {
return sendQuery(db, query);
}
/**
* Returns no error / Throws no exception.
* @return false if an exception happened
*/
protected static boolean sendQuery(Hsqldb db, final String query) {
try {
synchronized(db.dbLock) {
db.executeQuery(query);
}
return true;
} catch(final SQLException e) {
Logger.notice(e, "While (re)creating sql tables: "+e.toString());
return false;
}
}
/**
* Add the current plugin as an observer on all the running query
*/
public void setAsObserverEverywhere() {
Vector runningQueue = core.getQueueManager().getRunningQueue();
synchronized(runningQueue) {
for (Iterator it = runningQueue.iterator();
it.hasNext();) {
FCPTransferQuery query = (FCPTransferQuery)it.next();
notifyAddition(query);
}
core.getQueueManager().addObserver(this);
}
}
protected void notifyAddition(FCPTransferQuery query) {
if (!query.isPersistent())
return;
new Transfer(db, query, table);
table.refresh();
}
public void update(Observable o, Object param) {
if (o instanceof FCPQueueManager) {
if (param == null)
return;
FCPTransferQuery query = (FCPTransferQuery)param;
if(core.getQueueManager().isInTheQueues(query)
&& query.isRunning()) { // then it's an addition
notifyAddition(query);
return;
}
}
}
private File chooseFile(boolean save) {
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle(I18n.getMessage("thaw.plugin.transferLogs.chooseFile"));
fileChooser.setDirectoryOnly(false);
fileChooser.setDialogType(save ? FileChooser.SAVE_DIALOG
: FileChooser.OPEN_DIALOG);
return fileChooser.askOneFile();
}
public static java.sql.Timestamp getNow() {
return new java.sql.Timestamp((new java.util.Date()).getTime());
}
private class KeyImporter implements ThawRunnable {
public KeyImporter() { }
public void run() {
java.sql.Timestamp date = getNow();
File file = chooseFile(false);
if (file == null)
return;
try {
FileInputStream fstream = new FileInputStream(file);
DataInputStream in = new DataInputStream(fstream);
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String strLine;
PreparedStatement st = null;
try {
st = db.getConnection().prepareStatement("INSERT INTO transferLogs "+
"(dateStart, dateEnd, transferType,"+
" key, filename, size, isDup, isSuccess) "+
" VALUES "+
"(?, ?, 0, ?, ?, NULL, ?, TRUE)");
} catch(SQLException e) {
Logger.error(this, "Error while preparing to import keys : "+e.toString());
}
while ((strLine = br.readLine()) != null) {
String key = strLine.trim();
if (!FreenetURIHelper.isAKey(key))
continue;
boolean isDup = isDup(key);
try {
synchronized(db.dbLock) {
st.setTimestamp(1, date);
st.setTimestamp(2, date);
st.setString(3, key);
st.setString(4, FreenetURIHelper.getFilenameFromKey(key));
st.setBoolean(5, isDup);
st.execute();
}
} catch(SQLException e) {
Logger.error(this, "Error while adding an event to the logs: "+e.toString());
}
}
try {
st.close();
} catch(SQLException e) {
/* \_o< */
}
in.close();
} catch(java.io.FileNotFoundException e) {
Logger.error(this, "(1) Unable to import keys because: "+e.toString());
} catch(java.io.IOException e) {
Logger.error(this, "(2) Unable to import keys because: "+e.toString());
}
table.refresh();
}
public void stop() { /* \_o< */ }
}
private class KeyExporter implements ThawRunnable {
public KeyExporter() { }
public void run() {
File file = chooseFile(true);
if (file == null)
return;
try {
FileOutputStream out = new FileOutputStream(file);
synchronized(db.dbLock) {
PreparedStatement st;
st = db.getConnection().prepareStatement("SELECT DISTINCT key "+
"FROM transferLogs "+
"WHERE key is NOT NULL"+
" AND isSuccess = TRUE");
ResultSet set = st.executeQuery();
while(set.next()) {
out.write((set.getString("key")+"\n").getBytes("UTF-8"));
}
st.close();
}
out.close();
} catch(SQLException e) {
Logger.error(this, "Unable to export keys because: "+e.toString());
} catch(java.io.FileNotFoundException e) {
Logger.error(this, "(1) Unable to export keys because : "+e.toString());
} catch(java.io.IOException e) {
Logger.error(this, "(2) Unable to export keys because : "+e.toString());
}
}
public void stop() { /* \_o< */ }
}
public static void dropTables(Hsqldb db) {
sendQuery(db, "DROP TABLE transferEvents");
sendQuery(db, "DROP TABLE transferLogs");
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() == purgeLogs) {
dropTables(db);
createTables();
table.refresh();
return;
}
if (e.getSource() == importKeys) {
Thread th = new ThawThread(new KeyImporter(), "Key importer", this);
th.start();
return;
}
if (e.getSource() == exportKeys) {
Thread th = new ThawThread(new KeyExporter(), "Key exporter", this);
th.start();
return;
}
}
}