package thaw.plugins.index;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Observable;
import java.util.Observer;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import java.util.Iterator;
import thaw.fcp.FreenetURIHelper;
import thaw.core.Logger;
import thaw.fcp.FCPClientGet;
import thaw.fcp.FCPClientPut;
import thaw.fcp.FCPQueueManager;
import thaw.fcp.FCPTransferQuery;
import thaw.plugins.Hsqldb;
public class File implements Observer, FileContainer {
private Hsqldb db = null;
private int id = -1; /* -1 = undefined */
private String filename = null;
private String publicKey = null;
private java.io.File localPath = null;
private String mime = null;
private long size = 0;
private int parentId;
private Index parent;
/* if not null, the transfer will be removed when finished */
private FCPQueueManager queueManager = null;
public File(final Hsqldb db, final int id) {
this.db = db;
this.id = id;
reloadDataFromDb(id);
}
public File(final Hsqldb db, final int id, final String filename,
String publicKey, java.io.File localPath,
String mime, long size, int parentId) {
this.db = db;
this.id = id;
this.filename = filename;
this.publicKey = publicKey;
this.localPath = localPath;
this.mime = mime;
this.size = size;
}
public File(final Hsqldb db, final int id, final String filename,
String publicKey, java.io.File localPath,
String mime, long size, int parentId, Index parent) {
this.db = db;
this.id = id;
this.filename = filename;
this.publicKey = publicKey;
this.localPath = localPath;
this.mime = mime;
this.size = size;
this.parentId = parentId;
this.parent = parent;
}
public void update(Observable o, Object param) {
if (o instanceof FCPClientPut) {
FCPClientPut put = (FCPClientPut)o;
String key = put.getFileKey();
if (FreenetURIHelper.isAKey(key)) {
setPublicKey(key);
}
if (put.isFinished() && put.isSuccessful()) {
o.deleteObserver(this);
if (queueManager != null) {
Logger.notice(this, "REMOVING");
if(put.stop(queueManager)) {
queueManager.remove(put);
}
queueManager = null;
}
}
return;
}
Logger.error(this, "Unknow object: "+o.toString());
}
public void reloadDataFromDb(int id) {
this.id = id;
try {
synchronized(db.dbLock) {
PreparedStatement st;
st = db.getConnection().prepareStatement("SELECT filename, publicKey, localPath, mime, size, indexParent "+
" FROM files WHERE id = ? LIMIT 1");
st.setInt(1, id);
ResultSet rs = st.executeQuery();
if (rs.next()) {
String lp;
filename = rs.getString("filename");
publicKey = rs.getString("publicKey");
lp = rs.getString("localPath");
localPath = (lp == null ? null : new java.io.File(lp));
mime = rs.getString("mime");
size = rs.getLong("size");
parentId = rs.getInt("indexParent");
} else {
Logger.error(this, "File '"+Integer.toString(id)+"' not found");
}
st.close();
}
} catch(SQLException e) {
Logger.error(this, "Unable to get info for file '"+Integer.toString(id)+"'");
}
}
public void forceReload() {
reloadDataFromDb(id);
}
public void setParent(int parent_id) {
try {
synchronized(db.dbLock) {
PreparedStatement st;
st = db.getConnection().prepareStatement("UPDATE files SET indexParent = ? "+
"WHERE id = ?");
st.setInt(1, parent_id);
st.setInt(2, id);
st.execute();
st.close();
}
} catch(SQLException e) {
Logger.error(this, "Unable to set parent: "+e.toString());
}
}
public String getFilename() {
if (filename == null)
reloadDataFromDb(id);
String res;
try {
res = java.net.URLDecoder.decode(filename, "UTF-8");
} catch (final java.io.UnsupportedEncodingException e) {
res = filename;
}
return res;
}
public String getMime() {
return mime;
}
public long getSize() {
return size;
}
public String getLocalPath() {
if (localPath == null)
reloadDataFromDb(id);
if (localPath == null)
return null;
return localPath.getAbsolutePath();
}
public String getPublicKey() {
if (publicKey == null)
reloadDataFromDb(id);
return publicKey;
}
private FCPTransferQuery transfer = null;
public FCPTransferQuery getTransfer(FCPQueueManager q) {
if (transfer != null)
return transfer;
transfer = q.getTransfer(getPublicKey());
return transfer;
}
public void setPublicKey(final String publicKey) {
this.publicKey = FreenetURIHelper.cleanURI(publicKey);
try {
synchronized(db.dbLock) {
PreparedStatement st;
st = db.getConnection().prepareStatement("UPDATE files SET publicKey = ? "+
"WHERE id = ?");
st.setString(1, publicKey);
st.setInt(2, id);
st.execute();
st.close();
}
} catch(SQLException e) {
Logger.error(this, "Unable to set publicKey: "+e.toString());
}
}
public void setSize(final long size) {
try {
synchronized(db.dbLock) {
PreparedStatement st;
st = db.getConnection().prepareStatement("UPDATE files SET size = ? "+
"WHERE id = ?");
st.setLong(1, size);
st.setInt(2, id);
st.execute();
st.close();
}
} catch(SQLException e) {
Logger.error(this, "Unable to set publicKey: "+e.toString());
}
}
public FCPClientPut recalculateCHK(final FCPQueueManager queueManager) {
if (localPath == null) {
Logger.notice(this, "Trying to recalculate key from a file where we don't have the local path");
return null;
}
if (getTransfer(queueManager) != null) {
Logger.notice(this, "Another transfer is already running for this file");
return null;
}
final FCPClientPut insertion = new FCPClientPut(localPath,
FCPClientPut.KEY_TYPE_CHK,
0 /* rev */,
null /* name */,
null /* private key */,
FCPClientPut.DEFAULT_PRIORITY,
true /* global */, FCPClientPut.PERSISTENCE_FOREVER,
true /* getCHKOnly */,
true /* doCompress */,
-1); /* compression codec */
this.queueManager = queueManager; /* so the transfer will be removed when finished */
queueManager.addQueryToTheRunningQueue(insertion);
insertion.addObserver(this);
return insertion;
}
public FCPClientGet download(final String targetPath, final FCPQueueManager queueManager) {
FCPTransferQuery q;
String publicKey = getPublicKey();
if (publicKey == null) {
Logger.notice(this, "No key !");
return null;
}
if (!FreenetURIHelper.isAKey(publicKey)) {
Logger.warning(this, "Can't start download: file key is unknown");
return null;
}
if ( (q = getTransfer(queueManager)) != null && q.isRunning()) {
Logger.warning(this, "Can't download: a transfer is already running");
return null;
}
final FCPClientGet clientGet = new FCPClientGet(publicKey,
FCPClientGet.DEFAULT_PRIORITY,
FCPClientGet.PERSISTENCE_FOREVER,
true, /* <= global queue */
-1, /* <= max retries */
targetPath);
queueManager.addQueryToThePendingQueue(clientGet);
return clientGet;
}
public FCPClientPut insertOnFreenet(final FCPQueueManager queueManager) {
FCPTransferQuery q;
String localPath;
if ( (q = getTransfer(queueManager)) != null && q.isRunning()) {
Logger.warning(this, "Another transfer is already running : can't insert");
return null;
}
localPath = getLocalPath();
if (localPath == null) {
Logger.warning(this, "No local path => can't insert");
return null;
}
final FCPClientPut clientPut = new FCPClientPut(new java.io.File(localPath),
FCPClientPut.KEY_TYPE_CHK,
0, /* rev : EDONTCARE */
null, /* name : EDONTCARE */
null, /* privateKey : EDONTCARE */
FCPClientPut.DEFAULT_PRIORITY,
true, /* global queue */
FCPClientPut.PERSISTENCE_FOREVER,
true, /* doCompress */
-1); /* compression codec*/
queueManager.addQueryToThePendingQueue(clientPut);
clientPut.addObserver(this);
return clientPut;
}
public int getId() {
return id;
}
public int getParentId() {
try {
synchronized(db.dbLock) {
PreparedStatement st;
st = db.getConnection().prepareStatement("SELECT indexParent FROM files "+
"WHERE id = ? LIMIT 1");
st.setInt(1, id);
ResultSet rs = st.executeQuery();
if (rs.next()) {
int i = rs.getInt("indexParent");
st.close();
return i;
} else {
Logger.error(this, "File id not found: "+Integer.toString(id));
}
st.close();
}
} catch(SQLException e) {
Logger.error(this, "Unable to get parent id because: "+e.toString());
}
return -1;
}
public Element getXML(final Document xmlDoc) {
/* TODO */
return null;
}
public void delete() {
try {
synchronized(db.dbLock) {
PreparedStatement st;
st = db.getConnection().prepareStatement("DELETE FROM files WHERE id = ?");
st.setInt(1, id);
st.execute();
st.close();
}
} catch(SQLException e) {
Logger.error(this, "Unable to remove file because: "+e.toString());
}
}
/**
* Modifiable in the database<br/>
* Note: Do a SQL requests each time
*/
public boolean isModifiable() {
if (parent == null) {
Logger.debug(this, "isModifiable() => new Index().isModifiable()");
return (new Index(db, null, parentId)).isModifiable();
}
return parent.isModifiable();
}
/**
* Will browse the queue to see if one of the transfers match
* a file in the database
*/
public static boolean resumeTransfers(FCPQueueManager queue, Hsqldb db) {
synchronized(db.dbLock) {
PreparedStatement st;
try {
st = db.getConnection().prepareStatement("SELECT a.id, a.filename, a.publicKey, "+
"a.localPath, a.mime, a.size, a.indexParent "+
"FROM files AS a JOIN indexes AS b ON (a.indexParent = b.id)"+
"WHERE b.privateKey IS NOT NULL AND a.filename LIKE ?");
} catch(SQLException e) {
Logger.error("thaw.plugin.index.File", "Error while sending query to the database : "+e.toString());
return false;
}
for (Iterator it = queue.getRunningQueue().iterator();
it.hasNext();) {
FCPTransferQuery tq = (FCPTransferQuery)it.next();
if (tq instanceof FCPClientPut) {
try {
st.setString(1, tq.getFilename());
ResultSet rs = st.executeQuery();
while(rs.next()) {
File file = new File(db,
rs.getInt("id"),
rs.getString("filename"),
rs.getString("publicKey"),
rs.getString("localPath") != null ? new java.io.File(rs.getString("localPath")) : null,
rs.getString("mime"),
rs.getLong("size"),
rs.getInt("indexParent"));
((Observable)tq).addObserver(file);
if (tq.getFileKey() != null)
file.update(((Observable)tq), null);
}
} catch(SQLException e) {
Logger.warning("thaw.plugins.index.File", "Error while resuming key computations : "+e.toString());
return false;
}
}
}
try {
st.close();
} catch(SQLException e) {
/* \_o< */
}
}
return true;
}
}