Author: jflesch
Date: 2006-07-06 17:38:01 +0000 (Thu, 06 Jul 2006)
New Revision: 9478

Added:
   trunk/apps/Thaw/src/thaw/core/WarningWindow.java
   trunk/apps/Thaw/src/thaw/fcp/
   trunk/apps/Thaw/src/thaw/fcp/FCPClientHello.java
   trunk/apps/Thaw/src/thaw/fcp/FCPConnection.java
   trunk/apps/Thaw/src/thaw/fcp/FCPMessage.java
   trunk/apps/Thaw/src/thaw/fcp/FCPQuery.java
   trunk/apps/Thaw/src/thaw/fcp/FCPQueryManager.java
   trunk/apps/Thaw/src/thaw/fcp/FCPQueueManager.java
Removed:
   trunk/apps/Thaw/src/thaw/queue/
Modified:
   trunk/apps/Thaw/src/thaw/core/Config.java
   trunk/apps/Thaw/src/thaw/core/Core.java
   trunk/apps/Thaw/src/thaw/core/Logger.java
   trunk/apps/Thaw/src/thaw/core/MainWindow.java
   trunk/apps/Thaw/src/thaw/core/NodeConfigPanel.java
   trunk/apps/Thaw/src/thaw/i18n/thaw.properties
Log:
Starting FCP implementation (ClientHello and NodeHello implemented)

Modified: trunk/apps/Thaw/src/thaw/core/Config.java
===================================================================
--- trunk/apps/Thaw/src/thaw/core/Config.java   2006-07-06 16:08:28 UTC (rev 
9477)
+++ trunk/apps/Thaw/src/thaw/core/Config.java   2006-07-06 17:38:01 UTC (rev 
9478)
@@ -5,6 +5,7 @@
 import java.io.File;
 import java.util.Set;
 import java.util.Iterator;
+import java.util.Random;

 /* XML */
 import org.w3c.dom.Document;
@@ -296,6 +297,7 @@
                setValue("nodePort", "9481");
                setValue("maxSimultaneousDownloads", "5");
                setValue("maxSimultaneousInsertions", "2");
+               setValue("thawId", "thaw-"+(new Integer((new 
Random()).nextInt(1000))).toString());
        }

 }

Modified: trunk/apps/Thaw/src/thaw/core/Core.java
===================================================================
--- trunk/apps/Thaw/src/thaw/core/Core.java     2006-07-06 16:08:28 UTC (rev 
9477)
+++ trunk/apps/Thaw/src/thaw/core/Core.java     2006-07-06 17:38:01 UTC (rev 
9478)
@@ -1,20 +1,29 @@

 package thaw.core;

+import java.util.Observer;
+import java.util.Observable;

 import thaw.i18n.I18n;
+import thaw.fcp.*;

 /**
  * A "core" contains references to all the main parts of Thaw.
  *
  */
-public class Core {
+public class Core implements Observer {
        private MainWindow mainWindow = null;
        private Config config = null;
        private PluginManager pluginManager = null;
        private ConfigWindow configWindow = null;

+       private FCPConnection connection = null;
+       private FCPQueryManager queryManager = null;
+       private FCPQueueManager queueManager = null;

+       private FCPClientHello clientHello = null;
+
+
        /**
         * Creates a core, but do nothing else (no initialization).
         */
@@ -64,6 +73,9 @@
                if(!initConfig())
                        return false;

+               if(!initNodeConnection())
+                       return false;
+
                if(!initGraphics())
                        return false;

@@ -101,8 +113,84 @@
                return true;
        }

+       
+       /**
+        * Init the connection to the node.
+        * If a connection is already established, it will disconnect, so this 
function could be call safely later.
+        */
+       public boolean initNodeConnection() {
+               if(getMainWindow() != null)
+                       
getMainWindow().setStatus(I18n.getMessage("thaw.statusBar.connecting"));

+               try {
+
+                       if(connection != null && connection.isConnected())
+                               connection.disconnect();
+                       
+                       connection = new 
FCPConnection(config.getValue("nodeAddress"),
+                                                      (new 
Integer(config.getValue("nodePort"))).intValue());
+                       
+                       if(!connection.connect()) {
+                               new WarningWindow(this, "Unable to connect to 
"+config.getValue("nodeAddress")+":"+
+                                                 config.getValue("nodePort"));
+                               
+                               /* Not returning false,
+                                  else it will break the loading */
+                       }
+                       
+                       queryManager = new FCPQueryManager(connection);
+                       queueManager = new FCPQueueManager(queryManager,
+                                                          (new 
Integer(config.getValue("maxSimultaneousDownloads"))).intValue(),
+                                                          (new 
Integer(config.getValue("maxSimultaneousInsertions"))).intValue());
+                       if(connection.isConnected()) {
+                               queryManager.startListening();
+                               
+                               clientHello = new 
FCPClientHello(config.getValue("thawId"));
+
+                               if(!clientHello.start(queryManager)) {
+                                       new WarningWindow(this, 
I18n.getMessage("thaw.error.idAlreadyUsed"));
+                               } else {
+                                       Logger.debug(this, "Hello successful");
+                                       Logger.debug(this, "Node name    : 
"+clientHello.getNodeName());
+                                       Logger.debug(this, "FCP  version : 
"+clientHello.getNodeFCPVersion());
+                                       Logger.debug(this, "Node version : 
"+clientHello.getNodeVersion());
+                               }
+                               
+                       }
+
+               } catch(Exception e) { /* A little bit not ... "nice" ... */
+                       Logger.warning(this, "Exception while connecting : 
"+e.toString()+" ; "+e.getMessage() + " ; "+e.getCause());
+                       e.printStackTrace();
+                       new WarningWindow(this, "Unable to connect to the node. 
Please check your configuration.");
+               }
+
+               if(connection.isConnected())
+                       connection.addObserver(this);
+
+               if(getMainWindow() != null)
+                       
getMainWindow().setStatus(I18n.getMessage("thaw.statusBar.ready"));
+
+               return true;
+       }
+
+       
+       public FCPConnection getConnectionManager() {
+               return connection;
+       }
+
+       public FCPQueueManager getQueueManger() {
+               return queueManager;
+       }
+
        /**
+        * FCPClientHello object contains all the information given by the node 
when the connection
+        * was initiated.
+        */
+       public FCPClientHello getClientHello() {
+               return clientHello;
+       }
+
+       /**
         * Init graphics.
         */
        public boolean initGraphics() {
@@ -148,4 +236,13 @@



+       public void update(Observable o, Object target) {
+               Logger.debug(this, "Move on the connection (?)");
+
+               if(o == connection && !connection.isConnected()) {
+                       new WarningWindow(this, "We have been disconnected");
+                       connection.deleteObserver(this);
+               }
+       }
+
 }

Modified: trunk/apps/Thaw/src/thaw/core/Logger.java
===================================================================
--- trunk/apps/Thaw/src/thaw/core/Logger.java   2006-07-06 16:08:28 UTC (rev 
9477)
+++ trunk/apps/Thaw/src/thaw/core/Logger.java   2006-07-06 17:38:01 UTC (rev 
9478)
@@ -19,16 +19,14 @@
         * 3 or more is recommanded.
         * 5 is never logged in a file, only on stdout.
         */
-       private final static int LOG_LEVEL = 3;
+       private final static int LOG_LEVEL = 5;


        protected static void displayErr(String msg) {
-               // TODO : Log to a file
                System.err.println(msg);
        }

        protected static void display(String msg) {
-               // TODO : Log to a file
                System.out.println(msg);
        }

@@ -82,6 +80,14 @@
         */
        public static void verbose(Object o, String msg) {
                if(LOG_LEVEL >= 5)
-                       System.out.println(o.getClass().getName()+": "+msg);
+                       System.out.println("[VERBOSE] "+ 
o.getClass().getName()+": "+msg);
        }
+
+       /**
+        * As it. Similar to verbose()
+        */
+       public static void asIt(Object o, String msg) {
+               if(LOG_LEVEL >= 5)
+                       System.out.println(msg);
+       }
 }

Modified: trunk/apps/Thaw/src/thaw/core/MainWindow.java
===================================================================
--- trunk/apps/Thaw/src/thaw/core/MainWindow.java       2006-07-06 16:08:28 UTC 
(rev 9477)
+++ trunk/apps/Thaw/src/thaw/core/MainWindow.java       2006-07-06 17:38:01 UTC 
(rev 9478)
@@ -97,10 +97,15 @@
                mainWindow.setVisible(v);
        }

+       
+       public JFrame getMainFrame() {
+               return mainWindow;
+       }

+
        /** 
         * Should not be used.
-        * @see #addTab(String, JPanel)
+        * @see #addTab(String, java.awt.Component)
         * @return In the future, it's possible that it will sometimes return 
null.
         */
        public JTabbedPane getTabbedPane() {
@@ -109,6 +114,7 @@

        /**
         * Used to add a tab in the main window.
+        * In the future, even if the interface, this function should remain 
available.
         */
        public boolean addTab(String tabName, java.awt.Component panel) {
                tabbedPane.addTab(tabName, panel);

Modified: trunk/apps/Thaw/src/thaw/core/NodeConfigPanel.java
===================================================================
--- trunk/apps/Thaw/src/thaw/core/NodeConfigPanel.java  2006-07-06 16:08:28 UTC 
(rev 9477)
+++ trunk/apps/Thaw/src/thaw/core/NodeConfigPanel.java  2006-07-06 17:38:01 UTC 
(rev 9478)
@@ -28,14 +28,16 @@
                I18n.getMessage("thaw.config.nodeAddress"),
                I18n.getMessage("thaw.config.nodePort"),
                I18n.getMessage("thaw.config.maxSimultaneousDownloads"),
-               I18n.getMessage("thaw.config.maxSimultaneousInsertions")
+               I18n.getMessage("thaw.config.maxSimultaneousInsertions"),
+               I18n.getMessage("thaw.config.thawId")
        };

        private final static String[] configNames = {
                "nodeAddress",
                "nodePort",
                "maxSimultaneousDownloads",
-               "maxSimultaneousInsertions"
+               "maxSimultaneousInsertions",
+               "thawId"
        };

        private JLabel[] paramLabels = new JLabel[paramNames.length];
@@ -75,6 +77,9 @@
                        for(int i=0;i < paramNames.length;i++) {
                                core.getConfig().setValue(configNames[i], 
paramFields[i].getText());
                        }
+
+                       /* should reinit the whole connection correctly */
+                       core.initNodeConnection();
                }



Added: trunk/apps/Thaw/src/thaw/core/WarningWindow.java
===================================================================
--- trunk/apps/Thaw/src/thaw/core/WarningWindow.java    2006-07-06 16:08:28 UTC 
(rev 9477)
+++ trunk/apps/Thaw/src/thaw/core/WarningWindow.java    2006-07-06 17:38:01 UTC 
(rev 9478)
@@ -0,0 +1,30 @@
+package thaw.core;
+
+import javax.swing.JOptionPane;
+
+
+/**
+ * Use to create a warning popup.
+ * Currently this popup is simple as possible, but
+ * in the future, it may become more complex, showing,
+ * for example, last log messages.
+ */
+public class WarningWindow {
+
+
+       public WarningWindow(Core core,
+                            String warning)
+       {
+               if(core.getMainWindow() != null) {
+                       
JOptionPane.showMessageDialog(core.getMainWindow().getMainFrame(),
+                                                     warning,
+                                                     "Warning",
+                                                     
JOptionPane.WARNING_MESSAGE);
+               } else {
+                       JOptionPane.showMessageDialog(null,
+                                                     warning,
+                                                     "Warning",
+                                                     
JOptionPane.WARNING_MESSAGE);
+               }
+       }
+}

Copied: trunk/apps/Thaw/src/thaw/fcp (from rev 9412, 
trunk/apps/Thaw/src/thaw/queue)

Added: trunk/apps/Thaw/src/thaw/fcp/FCPClientHello.java
===================================================================
--- trunk/apps/Thaw/src/thaw/queue/FCPClientHello.java  2006-06-30 20:35:07 UTC 
(rev 9412)
+++ trunk/apps/Thaw/src/thaw/fcp/FCPClientHello.java    2006-07-06 17:38:01 UTC 
(rev 9478)
@@ -0,0 +1,148 @@
+package thaw.fcp;
+
+import java.util.Observer;
+import java.util.Observable;
+
+import thaw.core.Logger;
+
+/**
+ * http://wiki.freenetproject.org/FreenetFCPSpec2Point0
+ * See "ClientHello" and "NodeHello".
+ * Note: This query disconnect you if node answer 
CloseConnectionDuplicateClientName
+ *       and start() returns false.
+ */
+public class FCPClientHello implements FCPQuery, Observer {
+
+       private final static String FCP_EXPECTED_VERSION = "2.0";
+       private String id = null;
+
+       private String nodeFCPVersion = null;
+       private String nodeVersion = null;
+       private String nodeName = null;
+       private boolean testnet = false; /* Hmm, in fact, we shouldn't have to 
bother about this one */
+       private int nmbCompressionCodecs = -1;
+
+       private boolean receiveAnswer = false;
+
+       private FCPQueryManager queryManager = null;
+
+
+       /**
+        * Need to know the id of the application (see FCP specs).
+        */
+       public FCPClientHello(String id) {
+               setID(id);
+       }
+
+
+       public void setID(String id) {
+               this.id = id;
+       }
+
+       public int getThawPriority() {
+               return -1;
+       }
+
+       public String getNodeFCPVersion() {
+               return nodeFCPVersion;
+       }
+
+       public String getNodeVersion() {
+               return nodeVersion;
+       }
+
+       public String getNodeName() {
+               return nodeName;
+       }
+
+       public boolean isOnTestnet() {
+               return testnet;
+       }
+
+       public int getNmbCompressionCodecs() {
+               return nmbCompressionCodecs;
+       }
+
+
+       /**
+        * Warning: This query is blocking (only this one) !
+        */
+       public boolean start(FCPQueryManager queryManager) {
+               this.queryManager = queryManager;
+
+               FCPMessage message = new FCPMessage();
+
+               message.setMessageName("ClientHello");
+               message.setValue("Name", id);
+               message.setValue("ExpectedVersion", FCP_EXPECTED_VERSION);
+
+               queryManager.addObserver(this);
+
+               if(!queryManager.writeMessage(message)) {
+                       Logger.warning(this, "Unable to say hello ... ;(");
+                       return false;
+               }
+
+               while(!receiveAnswer) {
+                       try {
+                               Thread.sleep(500);
+                       } catch(java.lang.InterruptedException e) {
+                               /* Dodo j'ai dis ! */
+                       }
+               }
+
+               if(nodeName != null) {
+                       Logger.info(this, "Hello "+nodeName+", I'm Thaw :)");
+               } else {
+                       Logger.warning(this, "Unable to connect, ID is probably 
already taken");
+                       return false;
+               }
+
+               return true;
+       }
+
+
+       public void update(Observable o, Object arg) {
+               if(arg == null)
+                       return;
+
+               FCPMessage answer = (FCPMessage)arg;
+
+               if(o == queryManager) {
+                       
+                       if(answer.getMessageName().equals("NodeHello")) {
+                               Logger.info(this, "Received a nodeHello");
+
+                               nodeFCPVersion = answer.getValue("FCPVersion");
+                               nodeVersion = answer.getValue("Version");
+                               nodeName = answer.getValue("Node");
+                               testnet = (new 
Boolean(answer.getValue("Testnet"))).booleanValue();
+                               nmbCompressionCodecs = (new 
Integer(answer.getValue("CompressionCodecs"))).intValue();
+
+                               queryManager.deleteObserver(this);
+
+                               receiveAnswer = true;
+                       }
+
+                       
if(answer.getMessageName().equals("CloseConnectionDuplicateClientName")) {
+                               /* Damn ... ! */
+                               Logger.warning(this, "According to the node, 
Thaw ID is already used. Please change it in the configuration");
+                               queryManager.deleteObserver(this);
+                               queryManager.getConnection().disconnect();
+                               receiveAnswer = true;
+                       }
+               }
+
+               if(!receiveAnswer) {
+                       Logger.warning(this, "This message wasn't for us ?! : 
"+answer.getMessageName());
+               }
+       }
+
+       /**
+        * Not used.
+        */
+       public boolean stop(FCPQueryManager queryManager) {
+               return false;
+       }
+
+}

Added: trunk/apps/Thaw/src/thaw/fcp/FCPConnection.java
===================================================================
--- trunk/apps/Thaw/src/thaw/queue/FCPConnection.java   2006-06-30 20:35:07 UTC 
(rev 9412)
+++ trunk/apps/Thaw/src/thaw/fcp/FCPConnection.java     2006-07-06 17:38:01 UTC 
(rev 9478)
@@ -0,0 +1,207 @@
+package thaw.fcp;
+
+import java.net.Socket;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.util.Observable;
+
+/* Should be the only real dep of the FCP package */
+import thaw.core.Logger;
+
+
+/**
+ * This object manages directly the socket attached to the node.
+ * After being instanciated, you should commit it to the FCPQueryManager, and 
then
+ * commit the FCPQueryManager to the FCPQueueManager.
+ * Call observer when connected / disconnected.
+ */
+public class FCPConnection extends Observable {
+
+       private String nodeAddress = null;
+       private int port = 0;
+
+       private Socket socket = null;
+       private InputStream in = null;
+       private OutputStream out = null;
+
+       private BufferedReader reader = null;
+
+       /** If == 1, then will print on stdout
+        * all fcp input / output.
+        */
+       private final static int DEBUG_MODE = 1;
+
+       /**
+        * Don't connect. Call connect() for that.
+        */
+       public FCPConnection(String nodeAddress,
+                            int port)
+       {
+               if(DEBUG_MODE == 1) {
+                       Logger.notice(this, "DEBUG_MODE ACTIVATED");
+               }
+
+               setNodeAddress(nodeAddress);
+               setNodePort(port);
+       }
+
+
+       /**
+        * You will probably have to use resetQueue() from the FCPQueueManager 
after using this function.
+        */
+       public void setNodeAddress(String nodeAddress) {
+               this.nodeAddress = nodeAddress;
+       }
+
+       /**
+        * You will probably have to use resetQueue() from the FCPQueueManager 
after using this function.
+        */
+       public void setNodePort(int port) {
+               this.port = port;
+       }
+       
+       
+       public void disconnect() {
+               try {
+                       socket.close();
+               } catch(java.io.IOException e) {
+                       Logger.warning(this, "Unable to close cleanly the 
connection : "+e.toString());
+               }
+
+               socket = null;
+               in = null;
+               out = null;
+
+               setChanged();
+               notifyObservers();
+       }
+
+
+       /**
+        * If already connected, disconnect before connecting.
+        * @return true if successful
+        */
+       public boolean connect() {
+               if(nodeAddress == null || port == 0) {
+                       Logger.warning(this, "Address or port not defined ! 
Unable to connect\n");
+                       return false;
+               }
+               
+               if(socket != null && !socket.isClosed())
+                       disconnect();
+
+               try {
+                       socket = new Socket(nodeAddress, port);
+
+               } catch(java.net.UnknownHostException e) {
+                       Logger.error(this, "Error while trying to connect to 
"+nodeAddress+":"+port+" : "+
+                                    e.toString());
+                       socket = null;
+                       return false;
+               } catch(java.io.IOException e) {
+                       Logger.error(this, "Error while trying to connect to 
"+nodeAddress+":"+port+" : "+
+                                    e.toString());
+                       socket = null;
+                       return false;
+               }
+               
+               if(!socket.isConnected()) {
+                       Logger.warning(this, "Unable to connect, but no 
exception ?! WTF ?\n");
+                       Logger.warning(this, "Will try to continue ...\n");
+               }
+               
+               try {
+                       in = socket.getInputStream();
+                       out = socket.getOutputStream();
+               } catch(java.io.IOException e) {
+                       Logger.error(this, "Socket and connection established, 
but unable to get in/output streams ?! : "+e.toString());
+                       return false;
+               }
+
+               reader = new BufferedReader(new InputStreamReader(in));
+
+               setChanged();
+               notifyObservers();
+               
+               return true;
+       }
+
+       
+       public boolean isConnected() {
+               if(socket == null)
+                       return false;
+               else
+                       return socket.isConnected();
+       }
+
+       
+
+       public boolean write(String toWrite) {
+               Logger.asIt(this, "Thaw >>> Node :");
+               Logger.asIt(this, toWrite);
+
+
+               if(out != null && socket != null && socket.isConnected()) {
+                       try {
+                               out.write(toWrite.getBytes());
+                       } catch(java.io.IOException e) {
+                               Logger.warning(this, "Unable to write() on the 
socket ?! : "+ e.toString());
+                               return false;
+                       }
+               } else {
+                       Logger.warning(this, "Cannot write if disconnected 
!\n");
+                       return false;
+               }
+               return true;
+       }
+
+       /**
+        * Read a line.
+        * @return null if error
+        */
+       public String readLine() {
+               String result;
+               
+               if(in != null && socket != null && socket.isConnected()) {
+                       try {
+                               /*
+                               reader = new BufferedReader(new 
InputStreamReader(in));
+                               result = reader.readLine();
+                               */
+                               
+                               result = reader.readLine();
+
+                               Logger.asIt(this, "Thaw <<< Node : "+result);
+                               
+                               return result;
+
+                       } catch (java.io.IOException e) {
+                               Logger.error(this, "Unable to read() on the 
socket ?! : "+e.toString());
+                               return null;
+                       }
+               } else {
+                       Logger.warning(this, "Cannot read if disconnected => 
null");
+               }
+
+               return null;
+       }
+
+
+       /**
+        * Use this when you want to fetch the data still waiting on the socket.
+        */
+       public InputStream getInputStream() {
+               return in;
+       }
+
+
+       /**
+        * Use this when you want to send raw data.
+        */
+       public OutputStream getOutputStream() {
+               return out;
+       }
+
+}

Added: trunk/apps/Thaw/src/thaw/fcp/FCPMessage.java
===================================================================
--- trunk/apps/Thaw/src/thaw/queue/FCPMessage.java      2006-06-30 20:35:07 UTC 
(rev 9412)
+++ trunk/apps/Thaw/src/thaw/fcp/FCPMessage.java        2006-07-06 17:38:01 UTC 
(rev 9478)
@@ -0,0 +1,136 @@
+package thaw.fcp;
+
+import java.util.Hashtable;
+import java.util.Enumeration;
+
+import thaw.core.Logger;
+
+/**
+ * This class is a generic class, able to handle all kind of FCPMessage.
+ * Raw data are NOT stored inside. You have to handle them by yourself
+ * (FCPConnection.getInputStream() / FCPConnection.getOutputStream())
+ * after reading / writing a message with this class.
+ */
+public class FCPMessage {
+
+       private String messageName = null;
+       private Hashtable fields = null; /* String (field) -> String (value) ; 
See http://wiki.freenetproject.org/FreenetFCPSpec2Point0 */
+       private long dataWaiting = 0;
+
+
+       public FCPMessage() {
+               fields = new Hashtable();
+       }
+
+       /**
+        * As you can't fetch the value returns by loadFromRawMessage(), this 
constructor is not recommanded.
+        */
+       public FCPMessage(String rawMessage) {
+               this();
+               loadFromRawMessage(rawMessage);
+       }
+
+
+       /**
+        * Raw message does not need to finish by "EndMessage" / "Data".
+        */
+       public boolean loadFromRawMessage(String rawMessage) {
+               int i;
+
+               String[] lines = rawMessage.split("\n");
+
+               /* TODO : Find why some messages from the node starts with an 
'\n' */
+
+               for(i = 0 ; lines[i].equals("");) {
+                       i++;
+               }
+                       
+
+               setMessageName(lines[i]);
+
+               
+               for(i++; i < lines.length ; i++) {
+                       /* Empty lines are ignored. */
+                       /* Line not containing '=' (like "Data" or 
"EndMessage") are ignored */
+                       if(lines[i].equals("") || !lines[i].contains("="))
+                               continue;
+
+                       String[] affectation = lines[i].split("=");
+                       
+                       setValue(affectation[0], affectation[1]);
+               }
+
+               return true;
+       }
+
+
+       public String getMessageName() {
+               return messageName;
+       }
+
+       public void setMessageName(String name) {
+               if(name == null || name.equals("")) {
+                       Logger.notice(this, "Setting name to empty ? weird");
+               }
+               
+               if(name.contains("\n")) {
+                       Logger.notice(this, "Name shouldn't contain '\n'");
+               }
+
+               messageName = name;
+       }
+
+       public String getValue(String field) {
+               return ((String)fields.get(field));
+       }
+
+       public void setValue(String field, String value) {
+               if(field.equals("DataLength")) {
+                       Logger.warning(this, "Trying to add field 'DataLength' 
to a message ! You don't have to !\n");
+                       return;
+               }
+
+               fields.put(field, value);
+       }
+
+       
+       /**
+        * Returns the amount of data waiting on socket (in octets).
+        * @return if > 0 : Data are still waiting, if == 0 : No data waiting, 
if < 0 : These data are now unavailable.
+        */
+       public long getAmountOfDataWaiting() {
+               return dataWaiting;
+       }
+
+       
+       public void setAmountOfDataWaiting(long amount) {
+               this.dataWaiting = amount;
+       }
+
+
+       /**
+        * Generate FCP String to send.
+        * If amount of data waiting is set to > 0, then, a field "DataLength" 
is added,
+        * and resulting string finish by "Data", else resulting string simply 
finish by "EndMessage".
+        */
+       public String toString() {
+               String result = "";
+
+               result = result + getMessageName() + "\n";
+
+               for(Enumeration fieldNames = fields.keys() ; 
fieldNames.hasMoreElements();) {
+                       String fieldName = ((String)fieldNames.nextElement());
+
+                       result = result + fieldName + "=" + getValue(fieldName) 
+ "\n";
+               }
+
+               if(getAmountOfDataWaiting() == 0)
+                       result = result + "EndMessage\n";
+               else {
+                       result = result + "DataLength="+ (new 
Long(getAmountOfDataWaiting())).toString();
+                       result = result + "Data\n";
+               }
+
+               return result;
+       }
+}

Added: trunk/apps/Thaw/src/thaw/fcp/FCPQuery.java
===================================================================
--- trunk/apps/Thaw/src/thaw/queue/FCPQuery.java        2006-06-30 20:35:07 UTC 
(rev 9412)
+++ trunk/apps/Thaw/src/thaw/fcp/FCPQuery.java  2006-07-06 17:38:01 UTC (rev 
9478)
@@ -0,0 +1,17 @@
+package thaw.fcp;
+
+interface FCPQuery {
+
+       public boolean start(FCPQueryManager queryManager);
+       public boolean stop(FCPQueryManager queryManager);
+
+       /**
+        * Used by the QueueManager only.
+        * Currently these priority are the same
+        * as FCP priority, but it can change in the
+        * future.
+        * -1 = No priority
+        */
+       public int getThawPriority();
+
+}

Added: trunk/apps/Thaw/src/thaw/fcp/FCPQueryManager.java
===================================================================
--- trunk/apps/Thaw/src/thaw/queue/FCPQueryManager.java 2006-06-30 20:35:07 UTC 
(rev 9412)
+++ trunk/apps/Thaw/src/thaw/fcp/FCPQueryManager.java   2006-07-06 17:38:01 UTC 
(rev 9478)
@@ -0,0 +1,112 @@
+package thaw.fcp;
+
+import java.util.Observable;
+
+import thaw.core.Logger;
+
+/**
+ * Manage all fcp messages (see corresponding object of each kind of query).
+ * Call observers each type a new message is received. The given object is
+ * the 
+ */
+public class FCPQueryManager extends Observable implements Runnable {
+       private Thread me;
+
+       private FCPConnection connection;
+       private FCPMessage latestMessage;
+
+
+       public FCPQueryManager(FCPConnection connection) {
+               me = null;
+               latestMessage = null;
+               setConnection(connection);
+       }
+
+       /**
+        * If you call yourself this function, you will probably have to call
+        * resetQueue() of FCPQueueManager.
+        */
+       public void setConnection(FCPConnection connection) {
+               this.connection = connection;
+       }
+
+       /**
+        * Try to not directly call functions from FCPConnection.
+        */
+       public FCPConnection getConnection() {
+               return connection;
+       }
+
+       public boolean writeMessage(FCPMessage message) {
+               return connection.write(message.toString());
+       }
+
+       /**
+        * Blocking until a message is reveived.
+        * More exactly, read until "Data\n" or "EndMessage\n" is read.
+        */
+       public FCPMessage readMessage() {
+               String whatsUp = new String("");
+               FCPMessage result = new FCPMessage();
+
+               while(true) {
+                       String read = new String("");
+
+                       read = connection.readLine();
+                       
+                       if(read == null) {
+                               Logger.notice(this, "readLine() returned null 
=> disconnected ?");
+                               return null;
+                       }
+
+                       if(read.equals("Data") || read.equals("EndMessage")) {
+                               break;
+                       }
+
+                       whatsUp = whatsUp + "\n"+ read;
+               }
+
+               Logger.verbose(this, "Parsing message ...");
+
+               result.loadFromRawMessage(whatsUp);
+
+               return result;
+       }
+
+
+       /**
+        * Will listen in loop for new incoming messages.
+        */
+       public void run() {
+
+               while(true) {
+                       latestMessage = readMessage();
+                       
+                       Logger.debug(this, "Message received. Notifying 
observers");
+
+                       if(latestMessage != null) {
+                               setChanged();
+                               notifyObservers(latestMessage);
+                       } else {
+                               Logger.info(this, "Stopping listening");
+                               return;
+                       }
+               }
+
+       }
+
+       
+       /**
+        * Create the thread listening for incoming message.
+        */
+       public void startListening() {
+               if(connection.isConnected()) {
+                       me = new Thread(this);
+                       me.start();
+               } else {
+                       Logger.warning(this, "Not connected, so not listening 
on the socket");
+               }
+       }
+
+}
+

Added: trunk/apps/Thaw/src/thaw/fcp/FCPQueueManager.java
===================================================================
--- trunk/apps/Thaw/src/thaw/queue/FCPQueueManager.java 2006-06-30 20:35:07 UTC 
(rev 9412)
+++ trunk/apps/Thaw/src/thaw/fcp/FCPQueueManager.java   2006-07-06 17:38:01 UTC 
(rev 9478)
@@ -0,0 +1,50 @@
+package thaw.fcp;
+
+import thaw.core.Logger;
+
+
+public class FCPQueueManager {
+
+       private FCPQueryManager queryManager;
+       private int maxDownloads, maxInsertions;
+
+
+       /**
+        * Calls setQueryManager() and then resetQueue().
+        */
+       public FCPQueueManager(FCPQueryManager queryManager,
+                              int maxDownloads, int maxInsertions) {
+               setMaxDownloads(maxDownloads);
+               setMaxInsertions(maxInsertions);
+
+               setQueryManager(queryManager);
+               resetQueue();
+       }
+
+       public void setMaxDownloads(int maxDownloads) {
+               this.maxDownloads = maxDownloads;
+       }
+
+       public void setMaxInsertions(int maxInsertions) {
+               this.maxInsertions = maxInsertions;
+       }
+
+       /**
+        * You should call resetQueue() after calling this function.
+        */
+       public void setQueryManager(FCPQueryManager queryManager) {
+               this.queryManager = queryManager;
+       }
+
+
+       /**
+        * Will purge the current known queue, and reload the queue according 
to the node.
+        * Assume you have already called FCPConnection.connect().
+        */
+       public void resetQueue() {
+               /* TODO */
+       }
+       
+
+}
+

Modified: trunk/apps/Thaw/src/thaw/i18n/thaw.properties
===================================================================
--- trunk/apps/Thaw/src/thaw/i18n/thaw.properties       2006-07-06 16:08:28 UTC 
(rev 9477)
+++ trunk/apps/Thaw/src/thaw/i18n/thaw.properties       2006-07-06 17:38:01 UTC 
(rev 9478)
@@ -38,6 +38,9 @@

 thaw.common.priority=Priority

+## Errors
+thaw.error.idAlreadyUsed=Unable to connect. Our Id is already used by another 
client connected to the node.
+
 ## Menus
 thaw.menu.file=File
 thaw.menu.item.options=Options
@@ -46,6 +49,7 @@
 ## Status bar
 thaw.statusBar.initPlugins=Loading plugins ...
 thaw.statusBar.ready=Ready
+thaw.statusBar.connecting=Connecting ...

 ## Config
 thaw.config.windowName=Configuration
@@ -58,6 +62,8 @@
 thaw.config.maxSimultaneousDownloads=Maximum simultaneous downloads
 thaw.config.maxSimultaneousInsertions=Maximum simultaneous insertions

+thaw.config.thawId=Thaw ID
+
 thaw.config.pluginsLoaded=Plugins loaded:

 ##?Plugins


Reply via email to