gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] r20588 - in gnunet-java: . .idea .idea/libraries src/org/gn


From: gnunet
Subject: [GNUnet-SVN] r20588 - in gnunet-java: . .idea .idea/libraries src/org/gnunet src/org/gnunet/construct src/org/gnunet/construct/parsers src/org/gnunet/dht src/org/gnunet/nse src/org/gnunet/statistics src/org/gnunet/util test/org/gnunet/construct
Date: Sun, 18 Mar 2012 14:42:47 +0100

Author: dold
Date: 2012-03-18 14:42:47 +0100 (Sun, 18 Mar 2012)
New Revision: 20588

Added:
   gnunet-java/src/org/gnunet/construct/ReflectUtil.java
   gnunet-java/src/org/gnunet/dht/
   gnunet-java/src/org/gnunet/dht/DistributedHashTable.java
   gnunet-java/src/org/gnunet/util/GnunetHash.java
   gnunet-java/src/org/gnunet/util/GnunetMessage.java
   gnunet-java/src/org/gnunet/util/PeerIdentity.java
Removed:
   gnunet-java/src/org/gnunet/construct/parsers/FieldParser.java
   gnunet-java/update-msgtypes.sh
Modified:
   gnunet-java/.idea/libraries/lib.xml
   gnunet-java/.idea/misc.xml
   gnunet-java/ISSUES
   gnunet-java/gnunet-java.eml
   gnunet-java/src/org/gnunet/construct/Construct.java
   gnunet-java/src/org/gnunet/construct/MessageLoader.java
   gnunet-java/src/org/gnunet/construct/MsgMap.txt
   gnunet-java/src/org/gnunet/construct/parsers/ByteFillParser.java
   gnunet-java/src/org/gnunet/construct/parsers/DoubleParser.java
   gnunet-java/src/org/gnunet/construct/parsers/FillParser.java
   gnunet-java/src/org/gnunet/construct/parsers/FixedSizeArrayParser.java
   gnunet-java/src/org/gnunet/construct/parsers/IntegerParser.java
   gnunet-java/src/org/gnunet/construct/parsers/NestedParser.java
   gnunet-java/src/org/gnunet/construct/parsers/Parser.java
   gnunet-java/src/org/gnunet/construct/parsers/SequenceParser.java
   gnunet-java/src/org/gnunet/construct/parsers/StringParser.java
   gnunet-java/src/org/gnunet/construct/parsers/UnionParser.java
   gnunet-java/src/org/gnunet/construct/parsers/VariableSizeArrayParser.java
   gnunet-java/src/org/gnunet/nse/NetworkSizeEstimation.java
   gnunet-java/src/org/gnunet/statistics/Statistics.java
   gnunet-java/src/org/gnunet/util/Client.java
   gnunet-java/src/org/gnunet/util/MessageReceiver.java
   gnunet-java/src/org/gnunet/util/MessageTransmitter.java
   gnunet-java/src/org/gnunet/util/Resolver.java
   gnunet-java/src/org/gnunet/util/Scheduler.java
   gnunet-java/test/org/gnunet/construct/ConstructTest.java
   gnunet-java/test/org/gnunet/construct/UnionTest.java
Log:
* refactored the Construct library to use ByteBuffer internally, some other 
fixes to the construct library
* clients can now handle disconnects correctly, implemented in NSE
* started implementation of the DHT api

Modified: gnunet-java/.idea/libraries/lib.xml
===================================================================
--- gnunet-java/.idea/libraries/lib.xml 2012-03-17 16:31:42 UTC (rev 20587)
+++ gnunet-java/.idea/libraries/lib.xml 2012-03-18 13:42:47 UTC (rev 20588)
@@ -4,7 +4,6 @@
       <root url="jar://$PROJECT_DIR$/lib/slf4j-api-1.6.4.jar!/" />
       <root url="jar://$PROJECT_DIR$/lib/slf4j-log4j12-1.6.4.jar!/" />
       <root url="jar://$PROJECT_DIR$/lib/log4j-1.2.16.jar!/" />
-      <root url="jar://$PROJECT_DIR$/lib/annotations.jar!/" />
     </CLASSES>
     <JAVADOC />
     <SOURCES />

Modified: gnunet-java/.idea/misc.xml
===================================================================
--- gnunet-java/.idea/misc.xml  2012-03-17 16:31:42 UTC (rev 20587)
+++ gnunet-java/.idea/misc.xml  2012-03-18 13:42:47 UTC (rev 20588)
@@ -10,7 +10,7 @@
     <default-html-doctype>http://www.w3.org/1999/xhtml</default-html-doctype>
   </component>
   <component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" 
assert-keyword="true" jdk-15="true" project-jdk-name="1.6" 
project-jdk-type="JavaSDK">
-    <output url="file://$PROJECT_DIR$/out" />
+    <output url="file://$PROJECT_DIR$/build" />
   </component>
   <component name="SvnBranchConfigurationManager">
     <option name="myConfigurationMap">

Modified: gnunet-java/ISSUES
===================================================================
--- gnunet-java/ISSUES  2012-03-17 16:31:42 UTC (rev 20587)
+++ gnunet-java/ISSUES  2012-03-18 13:42:47 UTC (rev 20588)
@@ -229,5 +229,73 @@
  * should we introduce a general interface "Cancelable" for requests?
  * what is the persistence in statistics? (esp. in the watch message)
  * general api question: should callbacks have their corresponding request 
handler passed?
- 
- 
\ No newline at end of file
+
+
+
+ ====================================================
+
+ * regarding IzPack:
+  * are there really any advantages over just shipping a zip-file?
+  * no way to extend the $PATH, local ~/bin/ directory does not exist on e.g. 
ubuntu
+
+
+
+
+ * where should stuff like PeerIdentity and HashCode/GnunetHash go?
+
+ * should there be a more elegant / convenient way to handle Enums/EnumSets?
+  * is the use of enums desireable anyway? (java enums are not very flexible / 
you have to implement
+    a construtor everytime you want to use custom values)
+  * a simple way to do this would be to allow enums for @Integer-annotated 
fields
+   * this would only allow us to access the ordinal of the enum value
+   * otherwise every enum would have to implement an interface like IntEnum 
(enums in java cannot use extends)
+
+
+ * what is the purpose of the GNUNET_BLOCK_evaluate function?
+  * does is just check the validity of blocks / block requests?
+ * who is responsible for processing a query for a specific block type?
+ * what is a HELLO, what is a transport?
+
+
+proposal:
+
+change
+
address@hidden(SomeMessage.MSG_ID)
+public class SomeMessage extends Message {
+  public static final int MSG_ID = 12345;
+
+  @Nested
+  MessageHeader header;
+  @Uint16
+  int someValue
+  @Nested
+  SomeOtherMessage msg;
+}
+
+to
+
address@hidden(12345)
+public class SomeMessage extends GnunetMessageBody {
+    @Uint16
+    int someValue
+    @Nested
+    SomeOtherMessage msg;
+}
+
+Advantages:
+ * the user doesn't have to take care of the message header (the message 
header is redundant anyways)
+  * no need to define the MSG_ID constant in every Message
+ * no extra code for MessageId, simpler annotation processing, simpler 
MsgMap.txt
+ * with the current implementation it is not trivial to insert the message 
header automatically,
+   Union/UnionCase already implements this.
+
+
+public class GnunetMessage implements Message {
+    MessageHeader header;
+    @Union(tag = "header.msgType")
+    GnunetMessageBody body;
+
+}
+
+public interface GnunetMessageBody extends MessageUnion { }
\ No newline at end of file

Modified: gnunet-java/gnunet-java.eml
===================================================================
--- gnunet-java/gnunet-java.eml 2012-03-17 16:31:42 UTC (rev 20587)
+++ gnunet-java/gnunet-java.eml 2012-03-18 13:42:47 UTC (rev 20588)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <component>
-       <output-test url="file://$MODULE_DIR$/bin"/>
+       <output-test url="file://$MODULE_DIR$/build"/>
        <contentEntry url="file://$MODULE_DIR$">
                <testFolder url="file://$MODULE_DIR$/test"/>
        </contentEntry>

Modified: gnunet-java/src/org/gnunet/construct/Construct.java
===================================================================
--- gnunet-java/src/org/gnunet/construct/Construct.java 2012-03-17 16:31:42 UTC 
(rev 20587)
+++ gnunet-java/src/org/gnunet/construct/Construct.java 2012-03-18 13:42:47 UTC 
(rev 20588)
@@ -7,52 +7,30 @@
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
-import java.math.BigInteger;
+import java.nio.ByteBuffer;
 import java.util.*;
 
 /**
- * A version of Python's construct library for Java.
- *
  * @author Christian Grothoff
  */
 public class Construct {
 
-    private static HashMap<Class<? extends Message>, Parser> parserCache = new 
HashMap<Class<? extends Message>, Parser>();
+    private static HashMap<Class<? extends Message>, Parser> parserCache = new 
HashMap<Class<? extends Message>, Parser>(100);
 
     /**
-     * Given a byte array with a message, parse it into an object of type c. 
The
+     * Given a byte buffer with a message, parse it into an object of type c. 
The
      * fields of the class are expected to be annotated with annotations from
      * the construct package.
      *
-     * @param data   serialized binary object data
-     * @param offset where the message starts in data
+     * @param srcBuf buffer with the serialized binary data
      * @param c      desired object type to return
      * @return instance of the desired object type
      */
-    public static <T extends Message> T parseAs(byte[] data, int offset,
-                                                Class<T> c) {
-        T m;
+    public static <T extends Message> T parseAs(ByteBuffer srcBuf, Class<T> c) 
{
+        T m = ReflectUtil.justInstantiate(c);
 
+        getParser(c).parse(srcBuf, 0, m, m);
 
-        /*
-        if (c.isMemberClass()) {
-            throw new InterfaceViolationException("cannot instantiaze member 
class " + c.getCanonicalName()
-                    + ": please make it static)");
-        }
-        */
-
-
-        try {
-            m = c.newInstance();
-        } catch (InstantiationException e) {
-            throw new InterfaceViolationException("Cannot instantiate " + c);
-        } catch (IllegalAccessException e) {
-            throw new InterfaceViolationException(
-                    String.format("Cannot instantiate Message %s (illegal 
access)", c));
-        }
-
-        getParser(c).parse(data, offset, 0, m, m);
-
         return m;
     }
 
@@ -134,7 +112,7 @@
         // the parser we are actually generating, used by the caller, set as
         // return value of
         // the runabout invocation
-        FieldParser parser;
+        Parser parser;
 
         // where are we currently, seen from the root message object
         List<Field> path = new LinkedList<Field>();
@@ -145,16 +123,36 @@
         private ParserGenerator() {
         }
 
-        public void visit(Union u) {
-            try {
-                parser = new UnionParser(frameSizePath, u.optional(), 
field.getType().getCanonicalName(),
-                        c.getField(u.tag()), field);
-            } catch (NoSuchFieldException e) {
-                throw new InterfaceViolationException(String.format("field 
'%s' does not exist in class '%s'", u.tag(), c));
+        private static List<Field> getFieldPathFromString(final String p, 
final Class root) {
+            Class current = root;
+
+            String[] components = p.split("[.]");
+
+            List<Field> fp = new ArrayList<Field>(components.length);
+            for (String member : components) {
+                Field f;
+                try {
+                    f = current.getField(member);
+                } catch (NoSuchFieldException e) {
+                    throw new InterfaceViolationException("invalid field path, 
component " + member + " not found");
+                }
+
+                fp.add(f);
+
+                current = f.getType();
             }
 
+            return fp;
+
         }
 
+        public void visit(Union u) {
+            parser = new UnionParser(frameSizePath, u.optional(), 
field.getType().getCanonicalName(),
+                    getFieldPathFromString(u.tag(), c), field);
+
+
+        }
+
         public void visit(FrameSize ts) {
 
             frameSizePath = new LinkedList<Field>(path);
@@ -296,13 +294,12 @@
      * construct package.
      *
      * @param o      object to serialize
-     * @param data   where to write the binary object data
-     * @param offset where to start writing data
+     * @param dstBuf where to write the binary object data
      * @return number of bytes written to data, -1 on error
      */
-    public static int write(Message o, byte[] data, int offset) {
-        Parser p = getParser(o.getClass());
-        return p.write(data, offset, o);
+    public static int write(ByteBuffer dstBuf, Message msg) {
+        Parser p = getParser(msg.getClass());
+        return p.write(dstBuf, msg);
     }
 
     /**
@@ -321,97 +318,14 @@
 
     public static byte[] toBinary(Message m) {
         byte[] a = new byte[getSize(m)];
-        write(m, a, 0);
+        ByteBuffer buf = ByteBuffer.wrap(a);
+        write(buf, m);
         return a;
     }
 
-    public static void patchSizeFields(Message m) {
+    public static void patch(Message m) {
         Parser p = getParser(m.getClass());
         p.patch(m, p.getSize(m));
     }
 
-    // the following are utility methods for the java reflection api
-
-    public static class ReflectionUtil {
-        /**
-         * assign an enum value to each numeric type we want to serialize in
-         * order do switch statements on field types
-         */
-        public enum NumFieldType {
-            BIGNUM, BYTE_PRIM, SHORT_PRIM, INT_PRIM, LONG_PRIM, CHAR_PRIM
-        }
-
-        /**
-         * Get the corresponding NumFieldType for a Field if possible
-         *
-         * @param f a field of numeric type
-         * @return the corresponding NumFieldType
-         */
-        public static NumFieldType getNumFieldType(Field f) {
-            if (f.getType().equals(Long.TYPE)) {
-                return NumFieldType.LONG_PRIM;
-            } else if (f.getType().equals(java.lang.Integer.TYPE)) {
-                return NumFieldType.INT_PRIM;
-            } else if (f.getType().equals(Short.TYPE)) {
-                return NumFieldType.SHORT_PRIM;
-            } else if (f.getType().equals(Byte.TYPE)) {
-                return NumFieldType.BYTE_PRIM;
-            } else if (f.getType().equals(Character.TYPE)) {
-                return NumFieldType.CHAR_PRIM;
-            } else if (f.getType().equals(BigInteger.class)) {
-                return NumFieldType.BIGNUM;
-            } else {
-                throw new InterfaceViolationException(
-                        "expected numeric type, got: " + f.getType());
-            }
-        }
-
-        public static void setNumField(Object obj, NumFieldType ft, Field f, 
long val) {
-            try {
-                switch (ft) {
-                    case LONG_PRIM:
-                        f.setLong(obj, val);
-                        break;
-                    case INT_PRIM:
-                        f.setInt(obj, (int) val);
-                        break;
-                    case SHORT_PRIM:
-                        f.setShort(obj, (short) val);
-                        break;
-                    case BYTE_PRIM:
-                        f.setByte(obj, (byte) val);
-                        break;
-                    case CHAR_PRIM:
-                        f.setChar(obj, (char) val);
-                        break;
-                    case BIGNUM:
-                        f.set(obj, BigInteger.valueOf(val));
-                        break;
-                }
-            } catch (IllegalArgumentException e) {
-                throw new InterfaceViolationException("cannot access field");
-            } catch (IllegalAccessException e) {
-                throw new InterfaceViolationException("cannot access field");
-            }
-        }
-
-        public static Object followFieldPath(List<Field> fl, Object obj,
-                                             int depth) {
-            for (int i = 0; i < depth; ++i) {
-                try {
-                    obj = fl.get(i).get(obj);
-                } catch (IllegalArgumentException e) {
-                    throw new RuntimeException();
-                } catch (IllegalAccessException e) {
-                    throw new RuntimeException();
-                }
-            }
-            return obj;
-        }
-
-        public static Object followFieldPath(List<Field> fl, Object obj) {
-            return followFieldPath(fl, obj, fl.size());
-        }
-    }
-
 }

Modified: gnunet-java/src/org/gnunet/construct/MessageLoader.java
===================================================================
--- gnunet-java/src/org/gnunet/construct/MessageLoader.java     2012-03-17 
16:31:42 UTC (rev 20587)
+++ gnunet-java/src/org/gnunet/construct/MessageLoader.java     2012-03-18 
13:42:47 UTC (rev 20588)
@@ -29,9 +29,9 @@
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStreamReader;
-import java.lang.*;
 import java.lang.Integer;
 import java.net.URL;
+import java.nio.ByteBuffer;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -87,7 +87,7 @@
         }
     }
 
-    public static Message loadMessage(int type, byte[] data, int offset) {
+    public static Message loadMessage(int type, ByteBuffer dstBuf) {
         String className = msgmap.get(type);
         if (className == null) {
             throw new MessageFormatException("don't know how to translate 
message of type " + type);
@@ -101,7 +101,7 @@
             throw new InternalLogicError(String.format("message class '%s' not 
found in classpath", className));
         }
         
-        return Construct.parseAs(data, offset, msgClass);
+        return Construct.parseAs(dstBuf, msgClass);
     }
     
     public static Class loadUnionClass(String unionType, int type) {

Modified: gnunet-java/src/org/gnunet/construct/MsgMap.txt
===================================================================
--- gnunet-java/src/org/gnunet/construct/MsgMap.txt     2012-03-17 16:31:42 UTC 
(rev 20587)
+++ gnunet-java/src/org/gnunet/construct/MsgMap.txt     2012-03-18 13:42:47 UTC 
(rev 20588)
@@ -12,4 +12,4 @@
 
1|org.gnunet.construct.UnionTest.TestUnion=org.gnunet.construct.UnionTest$TestUnionCase1
 0|org.gnunet.util.Resolver.AddressUnion=org.gnunet.util.Resolver$TextualAddress
 1|org.gnunet.util.Resolver.AddressUnion=org.gnunet.util.Resolver$NumericAddress
-# generated 2012/02/23 21:30:09
+# generated 2012/03/17 23:22:37

Added: gnunet-java/src/org/gnunet/construct/ReflectUtil.java
===================================================================
--- gnunet-java/src/org/gnunet/construct/ReflectUtil.java                       
        (rev 0)
+++ gnunet-java/src/org/gnunet/construct/ReflectUtil.java       2012-03-18 
13:42:47 UTC (rev 20588)
@@ -0,0 +1,183 @@
+package org.gnunet.construct;
+
+
+import org.gnunet.exceptions.InterfaceViolationException;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.math.BigInteger;
+import java.util.List;
+
+public class ReflectUtil {
+    public static <T> T justInstantiate(Class<T> c) {
+        try {
+            return c.getConstructor().newInstance();
+        } catch (InstantiationException e) {
+            throw new InterfaceViolationException("Cannot instantiate " + c);
+        } catch (IllegalAccessException e) {
+            throw new InterfaceViolationException(
+                    String.format("Cannot instantiate Message %s (illegal 
access)", c));
+        } catch (NoSuchMethodException e) {
+            throw new InterfaceViolationException(
+                    String.format("No suitable default constructor for class 
%s", c));
+        } catch (InvocationTargetException e) {
+            throw new InterfaceViolationException(
+                    String.format("Exception thrown while constructing object 
of class %s", c));
+        }
+    }
+
+    /**
+     * assign an enum value to each numeric type we want to serialize in
+     * order do switch statements on field types
+     */
+    public enum NumFieldType {
+        BIGNUM, BYTE_PRIM, SHORT_PRIM, INT_PRIM, LONG_PRIM, CHAR_PRIM
+    }
+
+
+    /**
+     * Convenience wrapper for a field that stores a numeric value.
+     */
+    public static class NumField {
+        final private Field targetField;
+        final private NumFieldType targetType;
+        
+        
+        public NumFieldType getNumFieldType() {
+            return targetType;
+        }
+
+        public NumField(Field f) {
+            this.targetField = f;
+            if (f.getType().equals(Long.TYPE)) {
+                targetType = NumFieldType.LONG_PRIM;
+            } else if (f.getType().equals(java.lang.Integer.TYPE)) {
+                targetType = NumFieldType.INT_PRIM;
+            } else if (f.getType().equals(Short.TYPE)) {
+                targetType = NumFieldType.SHORT_PRIM;
+            } else if (f.getType().equals(Byte.TYPE)) {
+                targetType = NumFieldType.BYTE_PRIM;
+            } else if (f.getType().equals(Character.TYPE)) {
+                targetType = NumFieldType.CHAR_PRIM;
+            } else if (f.getType().equals(BigInteger.class)) {
+                targetType = NumFieldType.BIGNUM;
+            } else {
+                throw new InterfaceViolationException(
+                        "expected numeric type, got: " + f.getType());
+            }
+        }
+
+        public void set(Object obj, long val) {
+            try {
+                switch (targetType) {
+                    case LONG_PRIM:
+                        targetField.setLong(obj, val);
+                        break;
+                    case INT_PRIM:
+                        targetField.setInt(obj, (int) val);
+                        break;
+                    case SHORT_PRIM:
+                        targetField.setShort(obj, (short) val);
+                        break;
+                    case BYTE_PRIM:
+                        targetField.setByte(obj, (byte) val);
+                        break;
+                    case CHAR_PRIM:
+                        targetField.setChar(obj, (char) val);
+                        break;
+                    case BIGNUM:
+                        targetField.set(obj, BigInteger.valueOf(val));
+                        break;
+                }
+            } catch (IllegalArgumentException e) {
+                throw new InterfaceViolationException("cannot access field");
+            } catch (IllegalAccessException e) {
+                throw new InterfaceViolationException("cannot access field");
+            }
+        }
+        
+        public void set(Object obj, BigInteger val) {
+            try {
+                targetField.set(obj, val);
+            } catch (IllegalAccessException e) {
+                throw new InterfaceViolationException("cannot access field");
+            }
+        }
+
+        public long get(Object obj) {
+            try {
+                switch (targetType) {
+                    case LONG_PRIM:
+                        return targetField.getLong(obj);
+                    case INT_PRIM:
+                        return targetField.getInt(obj);
+                    case SHORT_PRIM:
+                        return targetField.getShort(obj);
+                    case BYTE_PRIM:
+                        return targetField.getByte(obj);
+                    case CHAR_PRIM:
+                        return targetField.getChar(obj);
+                    case BIGNUM:
+                        throw new RuntimeException("get() called on NumField 
that is a BigInteger");
+                    default:
+                        throw new AssertionError("unreachable");
+                }
+            } catch (IllegalAccessException e) {
+                throw new InterfaceViolationException("cannot access field");
+            }
+        }
+        
+        public BigInteger getBig(Object obj) {
+            if (isBig()) {
+                return (BigInteger) justGet(obj, targetField);
+            } else {
+                return BigInteger.valueOf(this.get(obj));
+            }
+        }
+
+        public boolean isBig() {
+            return targetType.equals(NumFieldType.BIGNUM);
+        }
+    }
+
+
+    public static Object followFieldPath(List<Field> fl, Object obj,
+                                         int depth) {
+        for (int i = 0; i < depth; ++i) {
+            try {
+                obj = fl.get(i).get(obj);
+            } catch (IllegalArgumentException e) {
+                throw new RuntimeException();
+            } catch (IllegalAccessException e) {
+                throw new RuntimeException();
+            }
+        }
+        return obj;
+    }
+
+    public static Object followFieldPath(List<Field> fl, Object obj) {
+        return followFieldPath(fl, obj, fl.size());
+    }
+
+    public static Object followFieldPathToParent(List<Field> fl, Object obj) {
+        return followFieldPath(fl, obj, fl.size() - 1);
+    }
+
+    public static Object justGet(Object obj, Field f) {
+        try {
+            return f.get(obj);
+        } catch (IllegalAccessException e) {
+            throw new InterfaceViolationException(
+                    String.format("Cannot access private field %s in class 
%s", f, obj.getClass()));
+        }
+    }
+
+    public static void justSet(Object obj, Field f, Object val) {
+        try {
+            f.set(obj, val);
+        } catch (IllegalAccessException e) {
+            throw new InterfaceViolationException(
+                    String.format("Cannot access private field %s in class 
%s", f, obj.getClass()));
+        }
+    }
+}

Modified: gnunet-java/src/org/gnunet/construct/parsers/ByteFillParser.java
===================================================================
--- gnunet-java/src/org/gnunet/construct/parsers/ByteFillParser.java    
2012-03-17 16:31:42 UTC (rev 20587)
+++ gnunet-java/src/org/gnunet/construct/parsers/ByteFillParser.java    
2012-03-18 13:42:47 UTC (rev 20588)
@@ -1,88 +1,83 @@
 package org.gnunet.construct.parsers;
 
-import org.gnunet.construct.Construct;
-import org.gnunet.construct.Construct.ReflectionUtil;
 import org.gnunet.construct.Message;
+import org.gnunet.construct.ReflectUtil;
+import org.gnunet.exceptions.MessageFormatException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.lang.reflect.Array;
 import java.lang.reflect.Field;
+import java.nio.ByteBuffer;
 import java.util.List;
 
 /**
- * Parse an array that takes up all the available space.
+ * Parse a byte array that takes up all the remaining space in its frame.
  * A 0-element array takes up no space.
  * 'null' is an invalid value for a field of this type.
  * 
  * @author Florian Dold
  * 
  */
-public class ByteFillParser extends FieldParser {
+public class ByteFillParser implements Parser {
     private static final Logger logger = LoggerFactory
             .getLogger(ByteFillParser.class);
 
+    /**
+     * The total size path stores where the total size field is located,
+     * relative to the frame object.
+     */
+    private final List<Field> totalSizePath;
+    
+    private final ReflectUtil.NumField totalSizeField;
+    
+    private final Field targetField;
 
 
-    private List<Field> totalSizePath;
-
-    private ReflectionUtil.NumFieldType totalSizeFieldType;
-
     public ByteFillParser(List<Field> totalSizePath, Field field) {
-        super(field);
+        targetField = field;
         this.totalSizePath = totalSizePath;
-        totalSizeFieldType = Construct.ReflectionUtil
-                .getNumFieldType(totalSizePath.get(totalSizePath.size() - 1));
+        totalSizeField = new 
ReflectUtil.NumField(totalSizePath.get(totalSizePath.size() - 1));
     }
 
     @Override
-    public int getSize(final Message src) {
-        return Array.getLength(getFieldValue(src));
+    public int getSize(Message src) {
+        return Array.getLength(ReflectUtil.justGet(src, targetField));
     }
 
-    private int getSizeFieldValue(Message m) {
-        Object obj = Construct.ReflectionUtil.followFieldPath(totalSizePath, 
m);
-        return ((Number) obj).intValue();
-    }
 
     @Override
-    public int parse(final byte[] srcData, final int offset, int frameOffset,
-                     Message frameObj, final Message dst) {
-        int remaining = (frameOffset + getSizeFieldValue(frameObj)) - offset;
+    public int parse(ByteBuffer srcBuf, int frameOffset, Message frameObj, 
Message dst) {
+        int frameSize = (int) 
totalSizeField.get(ReflectUtil.followFieldPathToParent(totalSizePath, 
frameObj));
+        int remaining = frameOffset + frameSize - srcBuf.position();
 
-        if (remaining <= 0) {
-            setFieldValue(dst, new byte[0]);
+        if (remaining < 0) {
+            throw new MessageFormatException("negative size remaining for 
variable size message");
+        }
+
+        if (remaining == 0) {
+            ReflectUtil.justSet(dst, targetField, new byte[0]);
             return 0;
         }
 
         byte[] a = new byte[remaining];
 
-        System.arraycopy(srcData, offset, a, 0, remaining);
+        srcBuf.get(a);
 
-        setFieldValue(dst, a);
+        ReflectUtil.justSet(dst, targetField, a);
 
         return frameOffset;
     }
 
     @Override
-    public int write(final byte[] dstData, final int offset, final Message 
src) {
-        byte[] a = (byte[]) getFieldValue(src);
-        System.arraycopy(a, 0, dstData, offset, a.length);
+    public int write(ByteBuffer dstBuf, Message src) {
+        byte[] a = (byte[]) ReflectUtil.justGet(src, targetField);
+        dstBuf.put(a);
         return a.length;
     }
 
-    /**
-     * Currently every parser that uses a total size field sets the total size
-     * field. This works, but is very redundant.
-     */
     @Override
     public void patch(Message m, int frameSize) {
-        Object obj = ReflectionUtil.followFieldPath(totalSizePath, m,
-                totalSizePath.size() - 1);
-        Field f = totalSizePath.get(totalSizePath.size() - 1);
-
-        ReflectionUtil.setNumField(obj, totalSizeFieldType, f,
-                frameSize);
+        totalSizeField.set(ReflectUtil.followFieldPathToParent(totalSizePath, 
m), frameSize);
     }
-
 }

Modified: gnunet-java/src/org/gnunet/construct/parsers/DoubleParser.java
===================================================================
--- gnunet-java/src/org/gnunet/construct/parsers/DoubleParser.java      
2012-03-17 16:31:42 UTC (rev 20587)
+++ gnunet-java/src/org/gnunet/construct/parsers/DoubleParser.java      
2012-03-18 13:42:47 UTC (rev 20588)
@@ -7,40 +7,44 @@
 import java.lang.reflect.Field;
 import java.nio.ByteBuffer;
 
-public class DoubleParser extends FieldParser{
-    public DoubleParser(final Field f) {
-        super(f);
+public class DoubleParser implements Parser {
+    
+    private final Field targetField;
+    
+    public DoubleParser(Field f) {
+        targetField = f;
     }
 
     @Override
     public int getSize(Message srcObj) {
-        return 8;
+        return Double.SIZE / 8;
     }
 
     @Override
-    public int parse(byte[] srcData, int offset, int frameOffset, Message 
frameObj, Message dstObj) {
-        double d = ByteBuffer.wrap(srcData, offset, 8).getDouble();
+    public int parse(ByteBuffer srcBuf, int frameOffset, Message frameObj, 
Message dstObj) {
+        double d = srcBuf.getDouble();
         try {
-            field.setDouble(dstObj, d);
+            targetField.setDouble(dstObj, d);
         } catch (IllegalAccessException e) {
             throw new InternalLogicError("cannot access field (should have 
been caught in Construct)");
         }
-        return 8;
+        return Double.SIZE / 8;
     }
 
     @Override
-    public int write(byte[] dstData, int offset, Message srcObj) {
+    public int write(ByteBuffer dstBuf, Message srcObj) {
         double d;
         try {
-            d = field.getDouble(srcObj);
+            d = targetField.getDouble(srcObj);
         } catch (IllegalAccessException e) {
             throw new InternalLogicError("field does not exist (should be 
caught in Construct)");
         }
-        ByteBuffer.wrap(dstData, offset, 8).putDouble(d);
+        dstBuf.putDouble(d);
         return 8;
     }
 
     @Override
     public void patch(Message m, int frameSize) {
+        // nothing to do here
     }
 }

Deleted: gnunet-java/src/org/gnunet/construct/parsers/FieldParser.java
===================================================================
--- gnunet-java/src/org/gnunet/construct/parsers/FieldParser.java       
2012-03-17 16:31:42 UTC (rev 20587)
+++ gnunet-java/src/org/gnunet/construct/parsers/FieldParser.java       
2012-03-18 13:42:47 UTC (rev 20588)
@@ -1,43 +0,0 @@
-package org.gnunet.construct.parsers;
-
-import java.lang.reflect.Field;
-
-/**
- * Convenience super class for all parsers that store their result in the 
field 
- * of an object.
- * 
- * @author Florian Dold
- * 
- */
-public abstract class FieldParser implements Parser {
-
-    protected final Field field;
-
-    public FieldParser(final Field f) {
-        this.field = f;
-    }
-
-    public Class getFieldType() {
-        return field.getType();
-    }
-
-    public Object getFieldValue(final Object obj) {
-        try {
-            return field.get(obj);
-        } catch (final IllegalArgumentException e) {
-            throw new RuntimeException();
-        } catch (final IllegalAccessException e) {
-            throw new RuntimeException();
-        }
-    }
-    
-    public void setFieldValue(final Object obj, final Object val) {
-        try {
-            field.set(obj, val);
-        } catch (final IllegalArgumentException e) {
-            throw new RuntimeException(e);
-        } catch (final IllegalAccessException e) {
-            throw new RuntimeException();
-        }
-    }
-}

Modified: gnunet-java/src/org/gnunet/construct/parsers/FillParser.java
===================================================================
--- gnunet-java/src/org/gnunet/construct/parsers/FillParser.java        
2012-03-17 16:31:42 UTC (rev 20587)
+++ gnunet-java/src/org/gnunet/construct/parsers/FillParser.java        
2012-03-18 13:42:47 UTC (rev 20588)
@@ -1,119 +1,89 @@
 package org.gnunet.construct.parsers;
 
-import org.gnunet.construct.Construct.ReflectionUtil;
 import org.gnunet.construct.Message;
+import org.gnunet.construct.ReflectUtil;
+import org.gnunet.exceptions.InterfaceViolationException;
 
 import java.lang.reflect.Array;
 import java.lang.reflect.Field;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
 import java.util.List;
 
 /**
  * Parse an array that takes up all the available space.
- * 
+ *
  * @author Florian Dold
- * 
  */
-public class FillParser extends FieldParser {
-    private Parser elemParser;
-    
-    private List<Field> totalSizePath;
+public class FillParser implements Parser {
+    private final Parser elemParser;
 
-    private ReflectionUtil.NumFieldType totalSizeFieldType;
+    private final Field targetField;
 
+    private final List<Field> totalSizePath;
+    private final ReflectUtil.NumField totalSizeField;
+
     public FillParser(Parser p, List<Field> totalSizePath, Field field) {
-        super(field);
+        targetField = field;
         elemParser = p;
         this.totalSizePath = totalSizePath;
-        totalSizeFieldType = ReflectionUtil.getNumFieldType(totalSizePath
-                .get(totalSizePath.size() - 1));
+        totalSizeField = new 
ReflectUtil.NumField(totalSizePath.get(totalSizePath.size() - 1));
     }
 
     @Override
     public int getSize(final Message src) {
         int size = 0;
-        final Object arr = getFieldValue(src);
-        
+        final Object arr = ReflectUtil.justGet(src, targetField);
+
         if (arr == null) {
             throw new RuntimeException("array not initialized");
         }
-        
+
         for (int i = 0; i < Array.getLength(arr); ++i) {
             size += elemParser.getSize((Message) Array.get(arr, i));
         }
         return size;
     }
 
-    private int getSizeFieldValue(Message m) {
-        Object obj = ReflectionUtil.followFieldPath(totalSizePath, m);
-        return ((Number) obj).intValue();
-    }
-
     @Override
-    public int parse(final byte[] srcData, final int offset, int frameOffset,
+    public int parse(ByteBuffer srcBuf, int frameOffset,
                      Message frameObj, final Message dstObj) {
-        /*
-        int remaining = getSizeFieldValue(dstObj) - frameOffset;
 
-        int elemNumber;
-        try {
-            elemNumber = ((Number) sizeField.get(dstObj)).intValue();
-        } catch (IllegalArgumentException e1) {
-            throw new RuntimeException();
-        } catch (IllegalAccessException e1) {
-            throw new RuntimeException();
-        }
-        
+        final int frameSize = (int) 
totalSizeField.get(ReflectUtil.followFieldPathToParent(totalSizePath, 
frameObj));
+        int remaining = frameOffset + frameSize - srcBuf.position();
         int size = 0;
 
-        final Object arr = Array.newInstance(getFieldType().getComponentType(),
-                elemNumber);
-        setFieldValue(dstObj, arr);
+        ArrayList<Message> list = new ArrayList<Message>(10);
 
-        for (int i = 0; i < elemNumber; ++i) {
-            Message elemObj;
-            try {
-                elemObj = (Message) getFieldType().getComponentType()
-                        .newInstance();
-            } catch (final InstantiationException e) {
-                throw new RuntimeException();
-            } catch (final IllegalAccessException e) {
-                throw new RuntimeException();
-            }
-            
-            Array.set(arr, i, elemObj);
-            
-            size += elemParser.parse(srcData, offset + size,
-                    frameOffset - size, elemObj);
+        while (remaining > 0) {
+            Message next = ReflectUtil.justInstantiate((Class<Message>) 
targetField.getType().getComponentType());
+            int s = elemParser.parse(srcBuf, frameOffset, frameObj, next);
+            size += s;
+            remaining -= s;
         }
 
+        try {
+            targetField.set(dstObj, list.toArray());
+        } catch (IllegalAccessException e) {
+            throw new InterfaceViolationException("cannot acces field");
+        }
+
         return size;
-        */
-        throw new UnsupportedOperationException("not yet implemented");
     }
 
     @Override
-    public int write(final byte[] dstData, final int offset, final Message 
src) {
+    public int write(final ByteBuffer dstBuf, final Message src) {
         int size = 0;
-        final Object arr = getFieldValue(src);
+        final Object arr = ReflectUtil.justGet(src, targetField);
         for (int i = 0; i < Array.getLength(arr); ++i) {
-            size += elemParser.write(dstData, offset + size,
-                    (Message) Array.get(arr, i));
+            size += elemParser.write(dstBuf, (Message) Array.get(arr, i));
         }
         return size;
     }
 
-    
-    /**
-     * Currently every parser that uses a total size field sets the total size 
field.
-     * This works, but is very redundant.
-     */
     @Override
     public void patch(Message m, int frameSize) {
-        Object obj = ReflectionUtil.followFieldPath(totalSizePath, m,
-                totalSizePath.size() - 1);
-        Field f = totalSizePath.get(totalSizePath.size() - 1);
-
-        ReflectionUtil.setNumField(obj, totalSizeFieldType, f, frameSize);
+        totalSizeField.set(ReflectUtil.followFieldPathToParent(totalSizePath, 
m), frameSize);
     }
 
 }

Modified: gnunet-java/src/org/gnunet/construct/parsers/FixedSizeArrayParser.java
===================================================================
--- gnunet-java/src/org/gnunet/construct/parsers/FixedSizeArrayParser.java      
2012-03-17 16:31:42 UTC (rev 20587)
+++ gnunet-java/src/org/gnunet/construct/parsers/FixedSizeArrayParser.java      
2012-03-18 13:42:47 UTC (rev 20588)
@@ -1,19 +1,23 @@
 package org.gnunet.construct.parsers;
 
 import org.gnunet.construct.Message;
+import org.gnunet.construct.ReflectUtil;
 
 import java.lang.reflect.Array;
 import java.lang.reflect.Field;
+import java.nio.ByteBuffer;
 
-public class FixedSizeArrayParser extends FieldParser {
+public class FixedSizeArrayParser implements Parser {
 
-    private final FieldParser elemParser;
+    private final Parser elemParser;
 
+    private final Field targetField;
+
     private final int elemNumber;
 
     public FixedSizeArrayParser(final int elemNumber,
-            final FieldParser elemParser, final Field f) {
-        super(f);
+                                final Parser elemParser, final Field f) {
+        targetField = f;
         this.elemNumber = elemNumber;
         this.elemParser = elemParser;
     }
@@ -21,12 +25,12 @@
     @Override
     public int getSize(final Message srcObj) {
         int size = 0;
-        final Object arr = getFieldValue(srcObj);
-        
+        final Object arr = ReflectUtil.justGet(srcObj, targetField);
+
         if (arr == null) {
             throw new RuntimeException("array not initialized");
         }
-        
+
         for (int i = 0; i < Array.getLength(arr); ++i) {
             size += elemParser.getSize((Message) Array.get(arr, i));
         }
@@ -34,52 +38,39 @@
     }
 
     @Override
-    public int parse(final byte[] srcData, final int offset, int frameOffset,
+    public int parse(ByteBuffer srcBuf, int frameOffset,
                      Message frameObj, final Message dstObj) {
         int size = 0;
 
-        final Object arr = Array.newInstance(getFieldType().getComponentType(),
-                elemNumber);
-        setFieldValue(dstObj, arr);
+        final Object arr = 
Array.newInstance(targetField.getType().getComponentType(), elemNumber);
+        ReflectUtil.justSet(dstObj, targetField, arr);
 
         for (int i = 0; i < elemNumber; ++i) {
-            Message elemObj;
-            try {
-                elemObj = (Message) getFieldType().getComponentType()
-                        .newInstance();
-            } catch (final InstantiationException e) {
-                throw new RuntimeException();
-            } catch (final IllegalAccessException e) {
-                throw new RuntimeException();
-            }
-            
+            Message elemObj = 
ReflectUtil.justInstantiate((Class<Message>)targetField.getType().getComponentType());
             Array.set(arr, i, elemObj);
-            
-            size += elemParser.parse(srcData, offset + size,
-                    frameOffset - size, null, elemObj);
+
+            size += elemParser.parse(srcBuf, frameOffset - size, frameObj, 
elemObj);
         }
 
         return size;
     }
 
     @Override
-    public int write(final byte[] dstData, final int offset,
-            final Message srcObj) {
+    public int write(final ByteBuffer dstBuf,
+                     final Message srcObj) {
         int size = 0;
-        final Object arr = getFieldValue(srcObj);
+        final Object arr = ReflectUtil.justGet(srcObj, targetField);
         for (int i = 0; i < Array.getLength(arr); ++i) {
-            size += elemParser.write(dstData, offset + size,
-                    (Message) Array.get(arr, i));
+            size += elemParser.write(dstBuf, (Message) Array.get(arr, i));
         }
         return size;
     }
 
     @Override
     public void patch(Message m, int frameSize) {
-        final Object arr = getFieldValue(m);
+        final Object arr = ReflectUtil.justGet(m, targetField);
         for (int i = 0; i < Array.getLength(arr); ++i) {
             elemParser.patch((Message) Array.get(arr, i), frameSize);
         }
-
     }
 }

Modified: gnunet-java/src/org/gnunet/construct/parsers/IntegerParser.java
===================================================================
--- gnunet-java/src/org/gnunet/construct/parsers/IntegerParser.java     
2012-03-17 16:31:42 UTC (rev 20587)
+++ gnunet-java/src/org/gnunet/construct/parsers/IntegerParser.java     
2012-03-18 13:42:47 UTC (rev 20588)
@@ -1,13 +1,13 @@
 package org.gnunet.construct.parsers;
 
-import org.gnunet.construct.Construct.ReflectionUtil;
 import org.gnunet.construct.Message;
+import org.gnunet.construct.ReflectUtil;
 
 import java.lang.reflect.Field;
 import java.math.BigInteger;
-import java.util.Arrays;
+import java.nio.ByteBuffer;
 
-public class IntegerParser extends FieldParser {
+public class IntegerParser implements Parser {
 
     public static final boolean UNSIGNED = false;
     public static final boolean SIGNED = true;
@@ -16,15 +16,15 @@
 
     private final boolean isSigned;
 
-    private ReflectionUtil.NumFieldType ft;
+    private final ReflectUtil.NumField targetField;
 
+
     public IntegerParser(final int byteSize, final boolean isSigned,
                          final Field f) {
-        super(f);
         this.byteSize = byteSize;
         this.isSigned = isSigned;
 
-        ft = ReflectionUtil.getNumFieldType(f);
+        targetField = new ReflectUtil.NumField(f);
     }
 
     @Override
@@ -33,186 +33,103 @@
     }
 
     @Override
-    public int parse(final byte[] srcData, int offset, int frameOffset,
-                     Message frameObj, final Message dstObj) {
-        try {
-            switch (ft) {
-                case BYTE_PRIM:
-                    field.setByte(dstObj, readByte(srcData, offset));
-                    break;
-                case SHORT_PRIM:
-                    field.setShort(dstObj, (short) readLong(srcData, offset));
-                    break;
-                case INT_PRIM:
-                    field.setInt(dstObj, (int) readLong(srcData, offset));
-                    break;
-                case LONG_PRIM:
-                    field.setLong(dstObj, readLong(srcData, offset));
-                    break;
-                case BIGNUM:
-                case CHAR_PRIM:
-                    throw new UnsupportedOperationException("not yet 
implemented");
-                default:
-                    throw new RuntimeException("invalid member type");
-            }
-
-        } catch (IllegalArgumentException e) {
-            throw new RuntimeException(e);
-        } catch (IllegalAccessException e) {
-            throw new RuntimeException();
+    public int parse(final ByteBuffer srcBuf, int frameOffset, Message 
frameObj, final Message dstObj) {
+        if (targetField.isBig()) {
+            targetField.set(dstObj, readBigInteger(srcBuf));
+        } else {
+            targetField.set(dstObj, readLong(srcBuf));
         }
-
         return byteSize;
     }
 
     @Override
-    public int write(final byte[] dstData, final int offset,
-                     final Message srcObj) {
-
-        try {
-            switch (ft) {
-                case BYTE_PRIM:
-                    writeInt(field.getInt(srcObj), dstData, offset);
-                    break;
-                case INT_PRIM:
-                    writeInt(field.getInt(srcObj), dstData, offset);
-                    break;
-                case SHORT_PRIM:
-                    writeShort(field.getShort(srcObj), dstData, offset);
-                    break;
-                case LONG_PRIM:
-                    writeLong(field.getLong(srcObj), dstData, offset);
-                    break;
-                case BIGNUM:
-                case CHAR_PRIM:
-                    throw new UnsupportedOperationException("not yet 
implemented");
-                default:
-                    throw new RuntimeException("invalid member type: ");
-            }
-        } catch (IllegalArgumentException e) {
-            throw new RuntimeException();
-        } catch (IllegalAccessException e) {
-            throw new RuntimeException();
+    public int write(final ByteBuffer dstBuf, final Message srcObj) {
+        if (targetField.isBig()) {
+            writeBitInteger(targetField.getBig(srcObj), dstBuf);
+        } else {
+            // todo: error checking on numeric overflow, if requested
+            writeLong(targetField.get(srcObj), dstBuf);
         }
-
         return byteSize;
     }
 
+
+
     @Override
     public void patch(Message m, int frameSize) {
+        // nothing to do
     }
 
-    public void writeByte(byte val, byte[] data, int offset) {
-        // fill with zeroes if byteSize is too large for a byte
-        Arrays.fill(data, offset, offset + (byteSize - 1), (byte) 0);
-        data[offset + (byteSize - 1)] = val;
-        if (isSigned) {
-            byte sign = (byte) (val & 0x80);
-            // remove the sign bit sign
-            data[offset + (byteSize - 1)] &= ~sign;
-            // ... and put it in the right place (lowest byte)
-            data[offset] |= sign;
-        }
-    }
 
-    public void writeShort(short val, byte[] data, int offset) {
-        Arrays.fill(data, offset, offset + (byteSize - 1), (byte) 0);
-        data[offset + (byteSize - 1)] = (byte) (val & 0xFF);
-        if (byteSize >= 2) {
-            val >>= 8;
-            data[offset + (byteSize - 2)] = (byte) (val & 0xFF);
-        }
-        if (isSigned) {
-            byte sign = (byte) (val & 0x80);
-            // remove the sign bit sign
-            data[offset + (byteSize - 1)] &= ~sign;
-            // ... and put it in the right place (lowest byte)
-            data[offset] |= sign;
-        }
-    }
+    public void writeLong(final long val, final ByteBuffer dstBuf) {
 
-    public void writeInt(int val, byte[] data, int offset) {
-        Arrays.fill(data, offset, offset + (byteSize - 1), (byte) 0);
-        data[offset + (byteSize - 1)] = (byte) (val & 0xFF);
-        for (int i = 2; i <= 4; ++i) {
-            if (byteSize - i < 0) {
-                break;
-            }
-            val >>= 8;
-            data[offset + (byteSize - i)] = (byte) (val & 0xFF);
+        long myval = val;
+
+        //DBG
+        int startPos = dstBuf.position();
+
+
+        // position of the last byte we are responsible to write
+        int last = dstBuf.position() + byteSize - 1;
+
+        while (last >= dstBuf.position()) {
+            dstBuf.put(last, (byte) (myval & 0xFF));
+            myval >>>= 8;
+            last -= 1;
         }
+
         if (isSigned) {
-            byte sign = (byte) (val & 0x80);
-            // remove the sign bit sign
-            data[offset + (byteSize - 1)] &= ~sign;
+            // a long has 8 bytes, shift by 7 bytes (non-arithmetically) to 
get the sign
+            byte sign = (byte) ((val >>> (7*8)) & 0x80);
+            // remove the sign bit from the buffer
+            dstBuf.put(dstBuf.position() + byteSize - 1, (byte) 
(dstBuf.get(dstBuf.position() + byteSize - 1) & ~sign));
             // ... and put it in the right place (lowest byte)
-            data[offset] |= sign;
-        }
-    }
+            dstBuf.put(dstBuf.position(), (byte) 
(dstBuf.get(dstBuf.position()) | sign));
 
-    public void writeLong(long val, byte[] data, int offset) {
-        Arrays.fill(data, offset, offset + (byteSize - 1), (byte) 0);
-        data[offset + (byteSize - 1)] = (byte) (val & 0xFF);
-        for (int i = 2; i <= 8; ++i) {
-            if (byteSize - i < 0) {
-                break;
-            }
-            val >>= 8;
-            data[offset + (byteSize - i)] = (byte) (val & 0xFF);
         }
-        if (isSigned) {
-            byte sign = (byte) (val & 0x80);
-            // remove the sign bit sign
-            data[offset + (byteSize - 1)] &= ~sign;
-            // ... and put it in the right place (lowest byte)
-            data[offset] |= sign;
-        }
+
+        dstBuf.position(dstBuf.position() + byteSize);
     }
 
-    public byte readByte(byte[] data, int offset) {
-        byte val;
-        val = data[offset + (byteSize - 1)];
-        if (isSigned) {
-            // explicitly OR sign bit to the right place if the source buffer 
is
-            // too large
-            byte sign = (byte) (data[offset] & 0x80);
-            val |= sign;
-        }
-        return val;
+    private void writeBitInteger(BigInteger big, ByteBuffer dstBuf) {
+        throw new UnsupportedOperationException("not yet implemented");
     }
 
-    public long readLong(byte[] data, int offset) {
+    public long readLong(ByteBuffer srcBuf) {
         long val = 0;
+        
+        final int first = srcBuf.position();
+        final int last = first + byteSize - 1;
 
-        int pos = offset;
-        while (pos < offset + byteSize - 1) {
-            byte b = data[pos];
+        // read all bytes except the last
+        while (srcBuf.position() != last) {
+            byte b = srcBuf.get();
+            // byte b may be signed, if so interpret it as unsigned byte; 
store it in an int
             int s = b >= 0 ? b : (256 + b);
 
             val |= s;
             val <<= 8;
-
-            pos += 1;
         }
 
-        byte b = data[pos];
+        // read the last byte, we don't have to shift val after that
+        byte b = srcBuf.get();
         int s = b >= 0 ? b : (256 + b);
         val |= s;
 
         if (isSigned) {
             // explicitly OR sign bit to the right place if the source buffer 
is
             // too large
-            long sign = (data[offset] & 0x80);
+            long sign = (srcBuf.get(first) & 0x80);
             val |= (sign << 7);
         }
 
+
         return val;
     }
 
 
-    public BigInteger readBigInteger(byte[] data, int offset) {
-        // todo: implement
-        return null;
+    public BigInteger readBigInteger(final ByteBuffer srcBuf) {
+        throw new UnsupportedOperationException("not yet implemented");
     }
 
 }

Modified: gnunet-java/src/org/gnunet/construct/parsers/NestedParser.java
===================================================================
--- gnunet-java/src/org/gnunet/construct/parsers/NestedParser.java      
2012-03-17 16:31:42 UTC (rev 20587)
+++ gnunet-java/src/org/gnunet/construct/parsers/NestedParser.java      
2012-03-18 13:42:47 UTC (rev 20588)
@@ -1,21 +1,24 @@
 package org.gnunet.construct.parsers;
 
-import org.gnunet.construct.Construct;
 import org.gnunet.construct.Message;
+import org.gnunet.construct.ReflectUtil;
 import org.gnunet.exceptions.MessageFormatException;
 
 import java.lang.reflect.Field;
+import java.nio.ByteBuffer;
 import java.util.List;
 
 
-public class NestedParser extends FieldParser {
+public class NestedParser implements Parser {
+    private final Field targetField;
+
     private final Parser nestedParser;
     private List<Field> frameSizePath;
 
     boolean optional;
 
     public NestedParser(final Parser p, List<Field> frameSizePath, boolean 
optional, final Field f) {
-        super(f);
+        targetField = f;
         this.optional = optional;
         this.nestedParser = p;
         this.frameSizePath = frameSizePath;
@@ -23,49 +26,42 @@
 
     @Override
     public int getSize(final Message src) {
-        Message inner = (Message) getFieldValue(src);
+        Message inner = (Message) ReflectUtil.justGet(src, targetField);
         return nestedParser.getSize(inner);
     }
 
     private int getSizeFieldValue(Message m) {
-        Object obj = Construct.ReflectionUtil.followFieldPath(frameSizePath, 
m);
+        Object obj = ReflectUtil.followFieldPath(frameSizePath, m);
         return ((Number) obj).intValue();
     }
 
     @Override
-    public int parse(final byte[] src_data, final int offset,
-                     int frameOffset, Message frameObj, final Message dstObj) {
+    public int parse(final ByteBuffer srcBuf, int frameOffset, Message 
frameObj, final Message dstObj) {
 
 
         if (optional) {
-            int remaining = (frameOffset + getSizeFieldValue(frameObj)) - 
offset;
-            if (remaining <= 0) {
+            int remaining = frameOffset + getSizeFieldValue(frameObj) - 
srcBuf.position();
+            if (remaining < 0) {
+                throw new MessageFormatException("remaining size negative");
+            }
+            if (remaining == 0) {
                 if (!optional) {
                     throw new MessageFormatException("not optional");
                 }
-                setFieldValue(dstObj, null);
+                ReflectUtil.justSet(dstObj, targetField, null);
                 return 0;
             }
         }
 
+        ReflectUtil.justSet(dstObj, targetField, 
ReflectUtil.justInstantiate(targetField.getType()));
 
-        try {
-            setFieldValue(dstObj, getFieldType().newInstance());
-        } catch (InstantiationException e) {
-            throw new RuntimeException();
-        } catch (IllegalAccessException e) {
-            throw new RuntimeException();
-        }
-
-
-        return nestedParser.parse(src_data, offset, frameOffset,
-                frameObj, (Message) getFieldValue(dstObj));
+        return nestedParser.parse(srcBuf, frameOffset,
+                frameObj, (Message) ReflectUtil.justGet(dstObj, targetField));
     }
 
     @Override
-    public int write(final byte[] dst_data, final int offset, final Message 
src) {
-        return nestedParser.write(dst_data, offset,
-                (Message) getFieldValue(src));
+    public int write(final ByteBuffer dstBuf, final Message src) {
+        return nestedParser.write(dstBuf, (Message) ReflectUtil.justGet(src, 
targetField));
     }
 
     @Override

Modified: gnunet-java/src/org/gnunet/construct/parsers/Parser.java
===================================================================
--- gnunet-java/src/org/gnunet/construct/parsers/Parser.java    2012-03-17 
16:31:42 UTC (rev 20587)
+++ gnunet-java/src/org/gnunet/construct/parsers/Parser.java    2012-03-18 
13:42:47 UTC (rev 20588)
@@ -2,26 +2,28 @@
 
 import org.gnunet.construct.Message;
 
+import java.nio.ByteBuffer;
 
+
 public interface Parser {
     /**
      * Compute the exact size of the object's binary representation in bytes.
      * 
-     * @param srcObj
-     * @return
+     * @param srcObj a message object with all fields filled out appropriately
+     * @return the exact size of the object's binary representation in bytes
      */
     public int getSize(Message srcObj);
 
     /**
      * 
      *
-     * @param srcData
-     * @param offset
-     * @param frameStart start of the current frame, relative to the beginning 
of srcData
-     * @param frameObj
-     address@hidden dstObj  @return
+     * @param srcBuf the buffer containing the binary data to construct this 
object
+     * @param frameStart start of the current frame, relative to the beginning 
of srcBuf
+     * @param frameObj the object containing the dstObj, dstObj if dstObj 
itself is the frame object
+     * @param dstObj the object whose members are written according according 
to the data in srcBuf
+     * @return number of byres read from srcBuf
      */
-    public int parse(byte[] srcData, int offset, int frameStart, Message 
frameObj, Message dstObj);
+    public int parse(ByteBuffer srcBuf, int frameStart, Message frameObj, 
Message dstObj);
 
     /**
      * 
@@ -30,8 +32,16 @@
      * @param srcObj
      * @return
      */
-    public int write(byte[] dstData, int offset, Message srcObj);
+    public int write(ByteBuffer dstBuf, Message srcObj);
 
+    /**
+     * Parser-dependent method; sets members of the Message m (or Messages 
nested in m) which are
+     * values inferable by the parser.
+     * Examples: Union tags, size fields.
+     * 
+     * @param m the message object to patch
+     * @param frameSize the size of the containing message
+     */
     public void patch(Message m, int frameSize);
 
 }

Modified: gnunet-java/src/org/gnunet/construct/parsers/SequenceParser.java
===================================================================
--- gnunet-java/src/org/gnunet/construct/parsers/SequenceParser.java    
2012-03-17 16:31:42 UTC (rev 20587)
+++ gnunet-java/src/org/gnunet/construct/parsers/SequenceParser.java    
2012-03-18 13:42:47 UTC (rev 20588)
@@ -2,6 +2,7 @@
 
 import org.gnunet.construct.Message;
 
+import java.nio.ByteBuffer;
 import java.util.LinkedList;
 import java.util.List;
 
@@ -12,46 +13,46 @@
  */
 public class SequenceParser implements Parser {
 
-    private final List<FieldParser> childParsers = new 
LinkedList<FieldParser>();
+    private final List<Parser> childParsers = new LinkedList<Parser>();
 
     public SequenceParser() {
     }
 
-    public void add(final FieldParser p) {
+    public void add(final Parser p) {
         childParsers.add(p);
     }
 
     @Override
     public int getSize(final Message src) {
         int size = 0;
-        for (final FieldParser p : childParsers) {
+        for (final Parser p : childParsers) {
             size += p.getSize(src);
         }
         return size;
     }
 
     @Override
-    public int parse(final byte[] src_data, final int offset, int frameOffset,
+    public int parse(final ByteBuffer srcBuf, int frameOffset,
                      Message frameObj, final Message dst) {
         int size = 0;
-        for (final FieldParser p : childParsers) {
-            size += p.parse(src_data, offset + size, frameOffset, frameObj, 
dst);
+        for (final Parser p : childParsers) {
+            size += p.parse(srcBuf, frameOffset, frameObj, dst);
         }
         return size;
     }
 
     @Override
-    public int write(final byte[] dst_data, final int offset, final Message 
src) {
+    public int write(final ByteBuffer dstBuf, final Message src) {
         int size = 0;
-        for (final FieldParser p : childParsers) {
-            size += p.write(dst_data, offset + size, src);
+        for (final Parser p : childParsers) {
+            size += p.write(dstBuf, src);
         }
         return size;
     }
 
     @Override
     public void patch(Message m, int frameSize) {
-        for (final FieldParser p : childParsers) {
+        for (final Parser p : childParsers) {
             p.patch(m, frameSize);
         }  
     }

Modified: gnunet-java/src/org/gnunet/construct/parsers/StringParser.java
===================================================================
--- gnunet-java/src/org/gnunet/construct/parsers/StringParser.java      
2012-03-17 16:31:42 UTC (rev 20587)
+++ gnunet-java/src/org/gnunet/construct/parsers/StringParser.java      
2012-03-18 13:42:47 UTC (rev 20588)
@@ -1,27 +1,29 @@
 package org.gnunet.construct.parsers;
 
 import org.gnunet.construct.Message;
+import org.gnunet.construct.ReflectUtil;
 import org.gnunet.exceptions.InterfaceViolationException;
 import org.gnunet.exceptions.MessageFormatException;
 
 import java.io.UnsupportedEncodingException;
 import java.lang.reflect.Field;
+import java.nio.ByteBuffer;
 
-public class StringParser extends FieldParser {
+public class StringParser implements Parser {
 
-    String cset;
+    private final String cset;
+    private final boolean optional;
+    private final Field targetField;
 
-    boolean optional;
-
     public StringParser(final String charset, boolean optional, final Field f) 
{
-        super(f);
+        this.targetField = f;
         this.optional = optional;
         this.cset = charset;
     }
 
     @Override
     public int getSize(final Message srcObj) {
-        final String s = (String) getFieldValue(srcObj);
+        final String s = (String) ReflectUtil.justGet(srcObj, targetField);
         if (s == null) {
             if (optional) {
                 return 0;
@@ -38,24 +40,30 @@
     }
 
     @Override
-    public int parse(final byte[] srcData, final int offset, int frameOffset, 
Message frameObj, final Message dstObj) {
+    public int parse(final ByteBuffer srcBuf, int frameOffset, Message 
frameObj, final Message dstObj) {
 
-        if (srcData[offset] == 0) {
+        if (srcBuf.get(srcBuf.position()) == 0) {
             if (!optional) {
                 throw new MessageFormatException("no data received for 
non-optional string");
             }
-            setFieldValue(dstObj, null);
-            return 0;
+            ReflectUtil.justSet(dstObj, targetField, null);
+            return 1;
         }
 
         int length = 0;
-        while (srcData[offset + length] != 0) {
+
+
+        while (srcBuf.get(srcBuf.position() + length) != 0) {
             length++;
         }
 
         final byte[] stringData = new byte[length];
+        
+        srcBuf.get(stringData);
 
-        System.arraycopy(srcData, offset, stringData, 0, length);
+        if (srcBuf.get() != 0) {
+            throw new AssertionError("programming error");
+        }
 
         String str;
         try {
@@ -64,14 +72,14 @@
             throw new RuntimeException();
         }
 
-        setFieldValue(dstObj, str);
+        ReflectUtil.justSet(dstObj, targetField, str);
 
         return length + 1;
     }
 
     @Override
-    public int write(final byte[] dstData, final int offset, final Message 
srcObj) {        
-        String s = (String) getFieldValue(srcObj);
+    public int write(final ByteBuffer dstBuf, final Message srcObj) {
+        String s = (String) ReflectUtil.justGet(srcObj, targetField);
         
         if (s == null) {
             if (!optional) {
@@ -87,10 +95,9 @@
             throw new RuntimeException();
         }
 
-        System.arraycopy(b, 0, dstData, offset, b.length);
+        dstBuf.put(b);
+        dstBuf.put((byte) 0);
 
-        dstData[offset + b.length] = 0;
-
         // +1 for the 0-byte
         return b.length + 1;
     }

Modified: gnunet-java/src/org/gnunet/construct/parsers/UnionParser.java
===================================================================
--- gnunet-java/src/org/gnunet/construct/parsers/UnionParser.java       
2012-03-17 16:31:42 UTC (rev 20587)
+++ gnunet-java/src/org/gnunet/construct/parsers/UnionParser.java       
2012-03-18 13:42:47 UTC (rev 20588)
@@ -3,86 +3,85 @@
 import org.gnunet.construct.Construct;
 import org.gnunet.construct.Message;
 import org.gnunet.construct.MessageLoader;
+import org.gnunet.construct.ReflectUtil;
 import org.gnunet.exceptions.MessageFormatException;
 
 import java.lang.reflect.Field;
+import java.nio.ByteBuffer;
 import java.util.List;
 
 
-public class UnionParser extends FieldParser {
-    private List<Field> frameSizePath;
+public class UnionParser implements Parser {
+    private final List<Field> frameSizePath;
 
-    private Field unionTag;
-    private String unionType;
+    private final Field targetField;
 
+    private final List<Field> unionTagPath;
+    private final ReflectUtil.NumField unionTagField;
+    private final String unionType;
+
     boolean optional;
 
-    public UnionParser(List<Field> frameSizePath, boolean optional, String 
unionType, Field unionTag, Field f) {
-        super(f);
+    public UnionParser(List<Field> frameSizePath, boolean optional, String 
unionType, List<Field> unionTagPath, Field f) {
+        targetField = f;
         this.optional = optional;
         this.frameSizePath = frameSizePath;
-        this.unionTag = unionTag;
+        this.unionTagPath = unionTagPath;
+        this.unionTagField = new 
ReflectUtil.NumField(unionTagPath.get(unionTagPath.size() - 1));
         this.unionType = unionType;
     }
 
     @Override
     public int getSize(final Message src) {
-        return Construct.getSize((Message) getFieldValue(src));
+        return Construct.getSize((Message) ReflectUtil.justGet(src, 
targetField));
     }
 
     private int getSizeFieldValue(Message m) {
-        Object obj = Construct.ReflectionUtil.followFieldPath(frameSizePath, 
m);
+        Object obj = ReflectUtil.followFieldPath(frameSizePath, m);
         return ((Number) obj).intValue();
     }
 
     @Override
-    public int parse(final byte[] src_data, final int offset,
-                     int frameOffset, Message frameObj, final Message dstObj) {
+    public int parse(final ByteBuffer srcBuf, int frameOffset, Message 
frameObj, final Message dstObj) {
 
 
         if (optional) {
-            int remaining = (frameOffset + getSizeFieldValue(frameObj)) - 
offset;
+            int remaining = frameOffset + getSizeFieldValue(frameObj) - 
srcBuf.position();
             if (remaining <= 0) {
                 if (!optional) {
                     throw new MessageFormatException("not optional");
                 }
-                setFieldValue(dstObj, null);
+                ReflectUtil.justSet(dstObj, targetField, null);
                 return 0;
             }
         }
 
-        Class cls = null;
-        try {
-            cls = MessageLoader.loadUnionClass(unionType, ((Number) 
unionTag.get(dstObj)).intValue());
-        } catch (IllegalAccessException e) {
-            throw new RuntimeException();
-        }
-        try {
-            setFieldValue(dstObj, cls.newInstance());
-        } catch (InstantiationException e) {
-            throw new RuntimeException(e);
-            //throw new InterfaceViolationException("cannot instantiate class 
" + cls);
-        } catch (IllegalAccessException e) {
+        final Class cls;
+        long unionTag = 
unionTagField.get(ReflectUtil.followFieldPathToParent(unionTagPath, dstObj));
 
-        }
+        cls = MessageLoader.loadUnionClass(unionType, (int) unionTag);
 
+        ReflectUtil.justSet(dstObj, targetField, 
ReflectUtil.justInstantiate(cls));
 
-        return Construct.getParser((Class<? extends Message>) 
getFieldValue(dstObj).getClass())
-                .parse(src_data, offset, frameOffset, frameObj, (Message) 
getFieldValue(dstObj));
+        final Message theUnion = (Message) ReflectUtil.justGet(dstObj, 
targetField);
+
+        return Construct.getParser(cls).parse(srcBuf, frameOffset, frameObj, 
theUnion);
     }
 
     @Override
-    public int write(final byte[] dst_data, final int offset, final Message 
src) {
-        return Construct.getParser((Class<? extends Message>) 
getFieldValue(src).getClass())
-                .write(dst_data, offset, (Message) getFieldValue(src));
+    public int write(final ByteBuffer dstBuf, final Message src) {
+        final Class currentUnionClass = ReflectUtil.justGet(src, 
targetField).getClass();
+        final Parser p = Construct.getParser(currentUnionClass);
+
+        return p.write(dstBuf, (Message) ReflectUtil.justGet(src, 
targetField));
     }
 
     @Override
     public void patch(Message m, int frameSize) {
         // todo: nested/opaque frames
-        Parser p = Construct.getParser((Class<? extends Message>) 
getFieldValue(m).getClass());
+        final Class currentUnionClass = ReflectUtil.justGet(m, 
targetField).getClass();
+        final Parser p = Construct.getParser(currentUnionClass);
 
-        p.patch((Message) getFieldValue(m), frameSize);
+        p.patch((Message) ReflectUtil.justGet(m, targetField), frameSize);
     }
-
 }

Modified: 
gnunet-java/src/org/gnunet/construct/parsers/VariableSizeArrayParser.java
===================================================================
--- gnunet-java/src/org/gnunet/construct/parsers/VariableSizeArrayParser.java   
2012-03-17 16:31:42 UTC (rev 20587)
+++ gnunet-java/src/org/gnunet/construct/parsers/VariableSizeArrayParser.java   
2012-03-18 13:42:47 UTC (rev 20588)
@@ -1,33 +1,33 @@
 package org.gnunet.construct.parsers;
 
-import org.gnunet.construct.Construct.ReflectionUtil;
 import org.gnunet.construct.Message;
+import org.gnunet.construct.ReflectUtil;
 
 import java.lang.reflect.Array;
 import java.lang.reflect.Field;
+import java.nio.ByteBuffer;
 
-public class VariableSizeArrayParser extends FieldParser {
-    private final FieldParser elemParser;
-    private Field sizeField;
-    private ReflectionUtil.NumFieldType ft;
+public class VariableSizeArrayParser implements Parser {
+    private final Field targetField;
+    private final Parser elemParser;
+    private ReflectUtil.NumField sizeField;
 
 
-    public VariableSizeArrayParser(final FieldParser elemParser, Field 
sizeField, Field arrayField) {
-        super(arrayField);
+    public VariableSizeArrayParser(final Parser elemParser, Field sizeField, 
Field arrayField) {
+        targetField = arrayField;
         this.elemParser = elemParser;
-        this.sizeField = sizeField;
-        this.ft = ReflectionUtil.getNumFieldType(sizeField);
+        this.sizeField = new ReflectUtil.NumField(sizeField);
     }
 
     @Override
     public int getSize(final Message src) {
         int size = 0;
-        final Object arr = getFieldValue(src);
-        
+        final Object arr = ReflectUtil.justGet(src, targetField);
+
         if (arr == null) {
             throw new RuntimeException("array not initialized");
         }
-        
+
         for (int i = 0; i < Array.getLength(arr); ++i) {
             size += elemParser.getSize((Message) Array.get(arr, i));
         }
@@ -35,57 +35,43 @@
     }
 
     @Override
-    public int parse(final byte[] srcData, final int offset, int frameOffset, 
Message frameObj, final Message dstObj) {
-        int elemNumber;
-        try {
-            elemNumber = ((Number) sizeField.get(dstObj)).intValue();
-        } catch (IllegalArgumentException e1) {
-            throw new RuntimeException();
-        } catch (IllegalAccessException e1) {
-            throw new RuntimeException();
-        }
-        
+    public int parse(final ByteBuffer srcBuf, int frameOffset, Message 
frameObj, final Message dstObj) {
+        final int elemNumber = (int) sizeField.get(dstObj);
+        final Class arrayElementType = 
targetField.getType().getComponentType();
+
         int size = 0;
 
-        final Object arr = Array.newInstance(getFieldType().getComponentType(),
-                elemNumber);
-        setFieldValue(dstObj, arr);
+        final Object arr = Array.newInstance(arrayElementType, elemNumber);
+        ReflectUtil.justSet(dstObj, targetField, arr);
 
         for (int i = 0; i < elemNumber; ++i) {
             Message elemObj;
-            try {
-                elemObj = (Message) getFieldType().getComponentType()
-                        .newInstance();
-            } catch (final InstantiationException e) {
-                throw new RuntimeException();
-            } catch (final IllegalAccessException e) {
-                throw new RuntimeException();
-            }
-            
+
+            elemObj = (Message) ReflectUtil.justInstantiate(arrayElementType);
+
+
             Array.set(arr, i, elemObj);
-            
-            size += elemParser.parse(srcData, offset + size,
-                    frameOffset - size, null, elemObj);
+
+            size += elemParser.parse(srcBuf, frameOffset - size, null, 
elemObj);
         }
 
         return size;
     }
 
     @Override
-    public int write(final byte[] dstData, final int offset, final Message 
src) {
+    public int write(final ByteBuffer dstBuf, final Message src) {
         int size = 0;
-        final Object arr = getFieldValue(src);
+        final Object arr = ReflectUtil.justGet(src, targetField);
         for (int i = 0; i < Array.getLength(arr); ++i) {
-            size += elemParser.write(dstData, offset + size,
-                    (Message) Array.get(arr, i));
+            size += elemParser.write(dstBuf, (Message) Array.get(arr, i));
         }
         return size;
     }
 
     @Override
     public void patch(Message m, int frameSize) {
-        int size = Array.getLength(getFieldValue(m));
-        ReflectionUtil.setNumField(m, ft, sizeField, size);
+        int size = Array.getLength(ReflectUtil.justGet(m, targetField));
+        sizeField.set(m, size);
     }
 
 }

Added: gnunet-java/src/org/gnunet/dht/DistributedHashTable.java
===================================================================
--- gnunet-java/src/org/gnunet/dht/DistributedHashTable.java                    
        (rev 0)
+++ gnunet-java/src/org/gnunet/dht/DistributedHashTable.java    2012-03-18 
13:42:47 UTC (rev 20588)
@@ -0,0 +1,196 @@
+package org.gnunet.dht;
+
+import org.gnunet.construct.Message;
+import org.gnunet.construct.MessageHeader;
+import org.gnunet.construct.Nested;
+import org.gnunet.construct.UInt32;
+import org.gnunet.util.*;
+import org.gnunet.util.getopt.Option;
+import org.gnunet.util.getopt.OptionAction;
+
+import java.util.EnumSet;
+import java.util.List;
+
+public class DistributedHashTable {
+
+    enum BlockType {
+        /**
+         * Any type of block, used as a wildcard when searching.  Should
+         * never be attached to a specific block.
+         */
+        ANY(0),
+        /**
+         * Data block (leaf) in the CHK tree.
+         */
+        DBLOCK(1),
+        /**
+         * Inner block in the CHK tree.
+         */
+        IBLOCK(2),
+        /**
+         * Type of a block representing a keyword search result.  Note that
+         * the values for KBLOCK, SBLOCK and NBLOCK must be consecutive.
+         */
+        KBLOCK(3),
+        /**
+         * Type of a block that is used to advertise content in a namespace.
+         */
+        SBLOCK(4),
+        /**
+         * Type of a block that is used to advertise a namespace.
+         */
+        NBLOCK(5),
+        /**
+         * Type of a block representing a block to be encoded on demand from 
disk.
+         * Should never appear on the network directly.
+         */
+        FS_ONDEMAND(6),
+        /**
+         * Type of a block that contains a HELLO for a peer (for
+         * DHT find-peer operations).
+         */
+        DHT_HELLO(7),
+        /**
+         * Block for testing.
+         */
+        TEST(8),
+        /**
+         * Block for storing .gnunet-domains
+         */
+        DNS(10),
+        /**
+         * Block for storing record data
+         */
+        NAMERECORD(11);
+
+        private final int val;
+        BlockType(int i) {
+            val = i;
+        }
+    }
+
+    enum RouteOption {
+        /**
+         * Default.  Do nothing special.
+         */
+        NONE(0),
+
+        /**
+         * Each peer along the way should look at 'enc' (otherwise
+         * only the k-peers closest to the key should look at it).
+         */
+        DEMULTIPLEX_EVERYWHERE(1),
+
+        /**
+         * We should keep track of the route that the message
+         * took in the P2P network.
+         */
+        RECORD_ROUTE(2),
+
+        /**
+         * This is a 'FIND-PEER' request, so approximate results are fine.
+         */
+        FIND_PEER(4),
+
+        /**
+         * Possible message option for query key randomization.
+         */
+        RO_BART(8);
+
+        private final int val;
+        RouteOption(int i) {
+            val = i;
+        }
+    }
+
+
+    public static class DHTClientGetMessage implements Message {
+        @Nested
+        public MessageHeader header;
+
+        @UInt32
+        public int options;
+
+    }
+
+
+    private Client client;
+    
+    public DistributedHashTable(Configuration cfg) {
+        client = new Client("dht", cfg);
+    }
+
+    public interface Continuation {
+        public void done();
+    }
+
+    public interface ResultCallback {
+        public void handleResult(AbsoluteTime expiration, GnunetHash key,
+                            List<PeerIdentity> getPath, List<PeerIdentity> 
putPath,
+                            BlockType type, byte[] data);
+    }
+
+
+
+
+    public void put(GnunetHash key, int replicationLevel, EnumSet<RouteOption> 
routeOptions,
+                    BlockType type, byte[] data, AbsoluteTime expiration,
+                    RelativeTime timeout, Continuation cont) {
+
+    }
+
+    public Cancelable startGet(RelativeTime timeout, BlockType type, 
GnunetHash key,
+                               int replicatoin, EnumSet<RouteOption> 
routeOptions,
+                               byte[] xquery, ResultCallback cb) {
+        return null;
+    }
+
+
+
+    public static void main(String[] args) {
+        new Program(args) {
+            @Option(action = OptionAction.SET,
+                    shortname = "p",
+                    longname = "put",
+                    description = "set a value in the DHT; default is get")
+            boolean modePut = false;
+
+            @Option(action = OptionAction.STORE_STRING,
+                    shortname = "d",
+                    longname = "data",
+                    description = "data (only used with --put)")
+            String data=null;
+
+            @Option(action = OptionAction.STORE_STRING,
+                    shortname = "k",
+                    longname = "key",
+                    description = "key used for the operation")
+            String key=null;
+
+            @Option(action = OptionAction.STORE_STRING,
+                    shortname = "t",
+                    longname = "type",
+                    description = "type of data used in this operation")
+            String type=null;
+
+            @Option(action = OptionAction.STORE_STRING,
+                    shortname = "e",
+                    longname = "expire",
+                    description = "expiration")
+            String expiration=null;
+
+
+            @Option(action = OptionAction.STORE_STRING,
+                    shortname = "r",
+                    longname = "replication",
+                    description = "desired replication (only used with --put)")
+            String replication=null;
+
+
+
+            public void run() {
+
+            }
+        }.start();
+    }
+}

Modified: gnunet-java/src/org/gnunet/nse/NetworkSizeEstimation.java
===================================================================
--- gnunet-java/src/org/gnunet/nse/NetworkSizeEstimation.java   2012-03-17 
16:31:42 UTC (rev 20587)
+++ gnunet-java/src/org/gnunet/nse/NetworkSizeEstimation.java   2012-03-18 
13:42:47 UTC (rev 20588)
@@ -1,10 +1,12 @@
 package org.gnunet.nse;
 
 
+import org.gnunet.construct.Double;
 import org.gnunet.construct.*;
-import org.gnunet.construct.Double;
 import org.gnunet.exceptions.MessageFormatException;
 import org.gnunet.util.*;
+import org.gnunet.util.getopt.Option;
+import org.gnunet.util.getopt.OptionAction;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -27,6 +29,7 @@
     private Client client;
 
 
+
     @SuppressWarnings("InstanceVariableMayNotBeInitialized")
     @MessageId(NSE_StartMessage.MSG_ID)
     public static class NSE_StartMessage implements Message {
@@ -55,7 +58,6 @@
 
         @Double
         public double stdDeviation;
-
     }
 
 
@@ -77,9 +79,14 @@
         }
 
         @Override
-        public void handleTimeout() {
-            // can't happen
-            throw new RuntimeException("unreachable");
+        public void handleError(Client.ReceiveError e) {
+            if (e.equals(Client.ReceiveError.DISCONNECT)) {
+                logger.warn("NSE service disconnected us - trying to 
reconnect");
+            } else {
+                throw new RuntimeException("unexpected receive error");
+            }
+            client.reconnect();
+            requestUpdate();
         }
     }
 
@@ -97,9 +104,8 @@
         }
 
         @Override
-        public void handleTimeout() {
-            // can't happen
-            throw new AssertionError("unreachable");
+        public void handleError(Client.TransmitError error) {
+            throw new RuntimeException("unexpected transmitt error");
         }
     }
 
@@ -127,8 +133,6 @@
      * A NSE_Subscriber receives updates from the service.
      */
     public interface NSE_Subscriber {
-
-
         public void update(AbsoluteTime timestamp, double estimate, double 
deviation);
     }
 
@@ -141,6 +145,7 @@
      */
     public NSE_Subscription subscribe(NSE_Subscriber s) {
         subscribers.add(s);
+        requestUpdate();
         return new NSE_Subscription(s);
     }
 
@@ -153,6 +158,9 @@
     public NetworkSizeEstimation(Configuration cfg) {
         client = new Client("nse", cfg);
         logger.debug("lifeness in NSE ctor: {}", 
Scheduler.getCurrentLifeness());
+    }
+
+    private void requestUpdate() {
         client.notifyTransmitReady(RelativeTime.FOREVER, true, new 
NSE_Transmitter());
     }
 
@@ -161,19 +169,27 @@
      */
     public void disconnect() {
         disconnected = true;
-        client.disconnect();
+        client.disconnect(false);
     }
 
     public static void main(String[] args) {
         new Program(args) {
+            @Option(action = OptionAction.SET,
+                    shortname = "w",
+                    longname = "continuous",
+                    description = "don't exit after the first estimation 
response")
+            boolean cont = false;
+
             public void run() {
                 final NetworkSizeEstimation svc = new 
NetworkSizeEstimation(cfg);
 
                 NSE_Subscriber subscriber = new NSE_Subscriber() {
                     @Override
                     public void update(AbsoluteTime timestamp, double 
estimate, double deviation) {
-                        System.out.println("est:" + estimate + " dev: " + 
deviation + " t: ");
-                        svc.disconnect();
+                        System.out.println("est:" + estimate + " dev: " + 
deviation + " t: " + timestamp);
+                        if (!cont) {
+                            svc.disconnect();
+                        }
                     }
                 };
 
@@ -181,8 +197,6 @@
 
             }
         }.start();
-
-
     }
 
 }

Modified: gnunet-java/src/org/gnunet/statistics/Statistics.java
===================================================================
--- gnunet-java/src/org/gnunet/statistics/Statistics.java       2012-03-17 
16:31:42 UTC (rev 20587)
+++ gnunet-java/src/org/gnunet/statistics/Statistics.java       2012-03-18 
13:42:47 UTC (rev 20588)
@@ -88,6 +88,10 @@
         client.notifyTransmitReady(deadline.getRemaining(), true, new 
MessageTransmitter() {
             @Override
             public void transmit(Client.MessageSink sink) {
+                if (sink == null) {
+                    logger.error("unable to connect to statistics service");
+                    return;
+                }
                 RequestMessage rm = new RequestMessage();
                 rm.header = new MessageHeader();
                 rm.statisticsName = name;
@@ -114,17 +118,21 @@
                     }
 
                     @Override
-                    public void handleTimeout() {
+                    public void handleError(Client.ReceiveError e) {
                         logger.error("unable to read from statistics service");
                     }
-                });
+
+                }
+                );
             }
 
             @Override
-            public void handleTimeout() {
-                logger.error("unable to connect to statistics service");
+            public void handleError(Client.TransmitError error) {
+                throw new RuntimeException("unexpected transmit error");
             }
-        });
+        }
+
+        );
         return null;
     }
 
@@ -136,6 +144,7 @@
         public void onCompleted();
 
         public void onTimeout();
+
     }
 
 
@@ -145,6 +154,9 @@
 
             @Override
             public void transmit(Client.MessageSink sink) {
+                if (sink == null) {
+                    cb.onTimeout();
+                }
                 SetMessage sm = new SetMessage();
                 sm.statisticName = name;
                 sm.subsystemName = subsystem;
@@ -159,8 +171,8 @@
             }
 
             @Override
-            public void handleTimeout() {
-                cb.onTimeout();
+            public void handleError(Client.TransmitError error) {
+                throw new RuntimeException("unexpected transmit error");
             }
         });
         return new Cancelable() {

Modified: gnunet-java/src/org/gnunet/util/Client.java
===================================================================
--- gnunet-java/src/org/gnunet/util/Client.java 2012-03-17 16:31:42 UTC (rev 
20587)
+++ gnunet-java/src/org/gnunet/util/Client.java 2012-03-18 13:42:47 UTC (rev 
20588)
@@ -36,7 +36,6 @@
 import java.nio.ByteBuffer;
 import java.nio.channels.SocketChannel;
 import java.nio.channels.spi.SelectorProvider;
-import java.util.Arrays;
 import java.util.LinkedList;
 
 /**
@@ -46,26 +45,87 @@
     private static final Logger logger = LoggerFactory
             .getLogger(Client.class);
 
-    private static final int INITIAL_BUFFER_SIZE = 128;
-
+    /**
+     * The underlying socket the client is using to talk with the service.
+     */
     private SocketChannel chan = null;
-    private LinkedList<InetAddress> addressList = new 
LinkedList<InetAddress>();
-    private RelativeTime connectBackoff = new RelativeTime(5);
 
-
+    /**
+     * The host and port this client should be connected to, according to the 
configuration.
+     */
     private String connectionHost;
     private int connectionPort;
 
+
+    /**
+     * The list of possible IP addresses the service can be reached by.
+     */
+    private LinkedList<InetAddress> addressList = new 
LinkedList<InetAddress>();
+    /**
+     * True if we are requesting or receiving IP addresses from the resolver
+     */
+    private boolean resolveActive = false;
+
+    /**
+     * The task that is currently used by the resolve mechanism.
+     */
+    private Cancelable resolveHandle = null;
+    private Cancelable connectHandle = null;
+
+
+    /**
+     * Initial value for connectBackoff.
+     * @see Client.connectBackoff
+     */
+    private final RelativeTime INITAL_BACKOFF = new RelativeTime(5);
+
+    /**
+     * Maximum value for connectBackoff.
+     * @see Client.connectBackoff
+     */
+    private final RelativeTime MAX_BACKOFF = RelativeTime.SECOND.multiply(5);
+
+
+    /**
+     * The time to wait after an error occured while connecting.
+     * Every time an error occurs while connecting, this value is doubled 
until its maximum
+     * value (MAX_BACKOFF) has been reached. This strategy is called 
exponential backoff.
+     */
+    private RelativeTime connectBackoff = INITAL_BACKOFF;
+
+    /**
+     * The ReceiveHelper responsible for receiving a whole message from the 
service
+     * and calling the respective MessageReceiver.
+     */
     private ReceiveHelper currentReceiveHelper = null;
-    private ByteBuffer recvBuffer = ByteBuffer.allocate(INITIAL_BUFFER_SIZE);
 
+    /**
+     * The buffer with the (partial) message received from the service.
+     * Initially, this buffer has the size of the smallest possible messages, 
but grows when
+     * receiving larger messages.
+     */
+    private ByteBuffer recvBuffer = ByteBuffer.allocate(MessageHeader.SIZE);
+
+
+    /**
+     * The handle for the current transmission. The current transmission either
+     * writes data to the channel or waits for the channel to connect
+     */
     private TransmitHelper currentTransmitHelper = null;
+    /**
+     * The handle for the next transmission. The next transmission will become 
the current
+     * transmission once the current transmission has completed.
+     * While nextTransmitHelper is not null, no new transmit requests may be 
scheduled.
+     */
     private TransmitHelper nextTransmitHelper = null;
-    private Scheduler.TaskIdentifier nextTransmitTimeout = null;
-    private Scheduler.TaskIdentifier currentTransmitTimeout = null;
-    private ByteBuffer transmitBuffer = 
ByteBuffer.allocate(INITIAL_BUFFER_SIZE);
 
-    private boolean resolveActive;
+    /**
+     * The transmitters passed to transmitReadyNotify(...) write to this 
buffer by calling
+     * methods on the MessageSink passed to the 
Transmitter.transmit(MessageSink s) method.
+     * Initially, this buffer has the size of the smallest possible messages, 
but grows when
+     * transmitting larger messages.
+     */
+    private ByteBuffer transmitBuffer = 
ByteBuffer.allocate(MessageHeader.SIZE);
 
 
     /**
@@ -73,24 +133,32 @@
      */
     public interface TransmitHandle {
         /**
-         * Cancel a request for notification.
+         * Cancel a request for the transmit ready notification.
+         * This does *not* cancel a transmission that already has been started.
          */
         public void cancel();
     }
 
+    /**
+     * An interface that allows the Transmitter.transmit method to deliver 
their messages
+     * to the client, which sends them to the service.
+     */
     public interface MessageSink {
-        public int getRemaining();
-
         public void send(Message m);
     }
 
+
+    /**
+     * A ReceiveHelper is responsible for receiving a whole
+     * gnunet message and call the respective MessageReceiver with the message 
on success,
+     * and null on failure or timeout.
+     */
     private class ReceiveHelper implements Task {
-
         private MessageReceiver receiver;
         private RelativeTime timeout;
-        private boolean headerProcessed = false;
         private MessageHeader msgh = null;
         private Scheduler.TaskIdentifier recvTask = null;
+        private boolean finished = false;
 
         public ReceiveHelper(MessageReceiver receiver, RelativeTime timeout) {
             this.receiver = receiver;
@@ -99,43 +167,58 @@
 
         public void dispatchMessage() {
             assert msgh != null;
+            currentReceiveHelper = null;
+            finished = true;
             logger.debug("dispatching message with " + recvBuffer.position() + 
" bytes");
-
-            // XXX: this is extremely slow, only preliminary for testing
-            byte[] buf = Arrays.copyOf(recvBuffer.array(), 
recvBuffer.position());
-            receiver.process(MessageLoader.loadMessage(msgh.messageType, buf, 
0));
+            recvBuffer.flip();
+            receiver.process(MessageLoader.loadMessage(msgh.messageType, 
recvBuffer));
         }
 
         @Override
         public void run(Scheduler.RunContext ctx) {
             logger.debug("receiving in helper");
+            recvTask = null;
             if (ctx.reasons.contains(Scheduler.Reason.TIMEOUT)) {
                 currentReceiveHelper = null;
-                receiver.handleTimeout();
+                receiver.handleError(ReceiveError.TIMEOUT);
             } else if (ctx.reasons.contains(Scheduler.Reason.READ_READY)) {
                 try {
                     int n = chan.read(recvBuffer);
                     if (n == -1) {
                         logger.error("end of stream in channel before complete 
message, read {} bytes",
                                 recvBuffer.position());
+                        chan.close();
+                        chan = null;
+                        receiver.handleError(ReceiveError.DISCONNECT);
+                        if (currentTransmitHelper != null
+                                && currentTransmitHelper.autoRetry && 
!currentTransmitHelper.notifyDone()) {
+                            logger.debug("reconnecting due to transmitter 
autoRetry");
+                            reconnect();
+                        }
                         return;
                     }
                     logger.debug(String.format("chan read %s bytes", n));
                 } catch (IOException e) {
-                    throw new RuntimeException("read failed");
+                    logger.error("read failed with exception:", e);
+                    receiver.handleError(ReceiveError.MSG_FORMAT);
+                    return;
                 }
                 if (recvBuffer.remaining() == 0) {
-                    if (headerProcessed) {
-                        currentReceiveHelper = null;
+                    if (msgh != null) {
                         dispatchMessage();
                     } else {
-                        msgh = Construct.parseAs(recvBuffer.array(), 0, 
MessageHeader.class);
-                        headerProcessed = true;
+                        recvBuffer.rewind();
+                        msgh = Construct.parseAs(recvBuffer, 
MessageHeader.class);
                         if (msgh.messageSize > MessageHeader.SIZE) {
+                            if (recvBuffer.capacity() < msgh.messageSize) {
+                                ByteBuffer buf = 
ByteBuffer.allocate(msgh.messageSize);
+                                recvBuffer.flip();
+                                buf.put(recvBuffer);
+                                recvBuffer = buf;
+                            }
                             recvBuffer.limit(msgh.messageSize);
                             schedule();
                         } else {
-                            currentReceiveHelper = null;
                             dispatchMessage();
                         }
                     }
@@ -150,31 +233,55 @@
 
         private void schedule() {
             recvTask = Scheduler.addRead(timeout, chan, this);
-            logger.debug("receive task has lifeness {}", 
recvTask.getLifeness());
         }
 
         public void cancel() {
+            if (finished) {
+                throw new InterfaceViolationException("canceling finished 
receive");
+            }
             if (recvTask != null) {
                 recvTask.cancel();
             }
         }
     }
 
+
     private class TransmitHelper implements Task, MessageSink {
-        private MessageTransmitter transmitter;
+        private final MessageTransmitter transmitter;
+        private final boolean autoRetry;
+
+        private Scheduler.TaskIdentifier notifyTimeoutTask;
+
         private Scheduler.TaskIdentifier transmitTask = null;
-        private boolean desiredLifeness;
 
+        public TransmitHelper(final MessageTransmitter transmitter, 
RelativeTime notifyTimeout, boolean autoRetry) {
+            this.transmitter = transmitter;
+            this.autoRetry = autoRetry;
 
-        public TransmitHelper(MessageTransmitter transmitter, boolean 
desiredLifeness) {
-            this.transmitter = transmitter;
-            this.desiredLifeness = desiredLifeness;
+            Scheduler.TaskBuilder b = new Scheduler.TaskBuilder();
+            b.withTask(new Task() {
+                @Override
+                public void run(Scheduler.RunContext ctx) {
+                    transmitter.handleError(TransmitError.TIMEOUT);
+                }
+            });
+            b.withTimeout(notifyTimeout);
+            notifyTimeoutTask = Scheduler.add(b);
         }
 
+        public boolean notifyDone() {
+            return notifyTimeoutTask == null;
+        }
+
         public void cancel() {
             if (transmitTask != null) {
                 transmitTask.cancel();
+                transmitTask = null;
             }
+            if (notifyTimeoutTask != null) {
+                notifyTimeoutTask.cancel();
+                notifyTimeoutTask = null;
+            }
         }
 
         @Override
@@ -189,14 +296,7 @@
                 logger.debug("sent " + transmitBuffer.position() + "bytes 
complete message");
                 if (nextTransmitHelper == null) {
                     currentTransmitHelper = null;
-                    if (currentTransmitTimeout != null) {
-                        throw new AssertionError("error in timeout logic");
-                    }
                 } else {
-                    if (currentTransmitTimeout != null) {
-                        throw new AssertionError("error in timeout logic");
-                    }
-                    nextTransmitTimeout.cancel();
                     currentTransmitHelper = nextTransmitHelper;
                     nextTransmitHelper.start();
                     nextTransmitHelper = null;
@@ -206,19 +306,16 @@
             }
         }
 
+        /**
+         * called to notify when we are ready to put new messages in the 
transmit buffer
+         */
         public void start() {
-            Scheduler.TaskBuilder b = new Scheduler.TaskBuilder();
-            b.withTask(new Task() {
-                @Override
-                public void run(Scheduler.RunContext ctx) {
-                    transmitBuffer.clear();
-                    transmitter.transmit(TransmitHelper.this);
-                    transmitBuffer.flip();
-                    schedule();
-                }
-            });
-            b.withLifeness(desiredLifeness);
-            Scheduler.add(b);
+            notifyTimeoutTask.cancel();
+            notifyTimeoutTask = null;
+            transmitBuffer.clear();
+            transmitter.transmit(TransmitHelper.this);
+            transmitBuffer.flip();
+            schedule();
 
         }
 
@@ -227,19 +324,20 @@
             // of a message, only the max. wait time before transmission.
             // cancel must be called on the transmitTask if we disconnect
             Scheduler.TaskBuilder b = new Scheduler.TaskBuilder();
-            
b.withTimeout(RelativeTime.FOREVER).withSelectWrite(chan).withTask(this).withLifeness(desiredLifeness);
-            Scheduler.add(b);
+            
b.withTimeout(RelativeTime.FOREVER).withSelectWrite(chan).withTask(this);
+            this.transmitTask = Scheduler.add(b);
         }
 
         @Override
-        public int getRemaining() {
-            throw new UnsupportedOperationException("not yet implemented");
-        }
-
-        @Override
         public void send(Message m) {
             byte[] b = Construct.toBinary(m);
             logger.debug("sending msg size=" + b.length);
+            if (transmitBuffer.remaining() < b.length) {
+                ByteBuffer buf = ByteBuffer.allocate(b.length + 
transmitBuffer.capacity());
+                transmitBuffer.flip();
+                buf.put(transmitBuffer);
+                transmitBuffer = buf;
+            }
             transmitBuffer.put(b);
         }
     }
@@ -258,7 +356,7 @@
             throw new ConfigurationException(String.format("'%s' is not a 
valid port", port));
         }
         connectionPort = port;
-        // ditto for hostname
+        // get the hostname from the configuration
         connectionHost = cfg.getValueString(serviceName, "HOSTNAME");
         // todo: further validity checks
         if (connectionHost.isEmpty()) {
@@ -298,15 +396,7 @@
         if (resolveActive) {
             return;
         }
-        Scheduler.TaskBuilder b = new Scheduler.TaskBuilder();
-        b.withTask(new Task() {
-            @Override
-            public void run(Scheduler.RunContext ctx) {
-                Resolver.getInstance().resolveHostname(connectionHost, 
RelativeTime.FOREVER, new AddressHandler());
-            }
-        });
-        b.withLifeness(false);
-        Scheduler.add(b);
+        resolveHandle = Resolver.getInstance().resolveHostname(connectionHost, 
RelativeTime.FOREVER, new AddressHandler());
     }
 
     private void connectDelayed() {
@@ -315,16 +405,18 @@
             @Override
             public void run(Scheduler.RunContext ctx) {
                 logger.debug("calling connect from delayed task");
+                connectHandle = null;
                 connect();
             }
         });
         b.withTimeout(connectBackoff);
-        Scheduler.add(b);
+        connectHandle = Scheduler.add(b);
     }
 
     private void increaseBackoff() {
         connectBackoff = RelativeTime.min(connectBackoff.multiply(2), new 
RelativeTime(5000));
     }
+    
 
     private void connectNextAddress() {
         if (addressList.isEmpty()) {
@@ -340,6 +432,7 @@
             b.withTask(new Task() {
                 @Override
                 public void run(Scheduler.RunContext ctx) {
+                    connectHandle = null;
                     if (ctx.reasons.contains(Scheduler.Reason.SHUTDOWN)) {
                         return;
                     }
@@ -354,18 +447,16 @@
                         connectDelayed();
                     }
                     if (connected) {
+                        //connectBackoff = INITAL_BACKOFF;
                         if (currentTransmitHelper != null) {
-                            currentTransmitTimeout.cancel();
-                            currentTransmitTimeout = null;
                             currentTransmitHelper.start();
                         }
                     }
                 }
             });
-            b.withLifeness(false);
             b.withSelectConnect(chan);
             b.withTimeout(RelativeTime.FOREVER);
-            Scheduler.add(b);
+            connectHandle = Scheduler.add(b);
         } catch (IOException e) {
             logger.debug("unable to connect: {}", e);
             increaseBackoff();
@@ -375,6 +466,9 @@
         }
     }
 
+    /**
+     * Open a channel for this connection in non-blocking mode
+     */
     private void openChannel() {
         try {
             chan = SelectorProvider.provider().openSocketChannel();
@@ -390,11 +484,21 @@
         connectNextAddress();
     }
 
+    public void reconnect() {
+        if (currentReceiveHelper != null) {
+            currentReceiveHelper.cancel();
+            currentReceiveHelper = null;
+        }
+
+        if (connectHandle == null && (chan == null || !chan.isOpen() || 
!chan.isConnected())) {
+            connect();
+        }
+    }
+
     public interface ReceiveHandle {
         public void cancel();
     }
 
-
     /**
      * Receive one message from the service.
      *
@@ -424,8 +528,8 @@
     }
 
 
-    public Scheduler.TaskIdentifier scheduleTransmitTimeout(final 
MessageTransmitter t, RelativeTime timeout,
-                                                            final boolean 
forCurrent) {
+    private Scheduler.TaskIdentifier scheduleTransmitTimeout(final 
MessageTransmitter t, RelativeTime timeout,
+                                                             final boolean 
forCurrent) {
         Scheduler.TaskBuilder b = new Scheduler.TaskBuilder();
         b.withTask(new Task() {
             @Override
@@ -437,7 +541,7 @@
                     nextTransmitHelper.cancel();
                     nextTransmitHelper = null;
                 }
-                t.handleTimeout();
+                t.transmit(null);
             }
         });
         b.withTimeout(timeout);
@@ -449,14 +553,14 @@
      * Ask the client to call us once it is able to send a message.
      *
      * @param size        number of bytes to send
-     * @param timeout     after how long should we give up (and call
-     *                    notify with buf NULL and size 0)?
+     * @param timeout     after how long should we give up (and call 
transmitter.transmit(null))
      * @param autoRetry   if the connection to the service dies, should we
-     *                    automatically re-connectStep and retry (within the 
deadline period)
-     *                    or should we immediately fail in this case?  Pass 
GNUNET_YES
+     *                    automatically reconnect and retry (within the 
deadline period)
+     *                    or should we immediately fail in this case?  Pass 
true
      *                    if the caller does not care about temporary 
connection errors,
      *                    for example because the protocol is stateless
-     * @param transmitter ...
+     * @param transmitter the MessageTransmitter object to call once the 
client is ready to transmit or
+     *                    when the timeout is over.
      * @return a handle that can be used to cancel the transmit request
      */
     public TransmitHandle notifyTransmitReady(RelativeTime timeout,
@@ -466,8 +570,15 @@
                     "previous transmit request must have completed before 
calling notifyTransmitReady again");
         }
 
+        // negative timeout
         if (timeout.getMilliseconds() <= 0) {
-            transmitter.handleTimeout();
+            transmitter.handleError(TransmitError.TIMEOUT);
+            return new TransmitHandle() {
+                @Override
+                public void cancel() {
+                    throw new InterfaceViolationException("cancel() called on 
timed-out TransmitHandle");
+                }
+            };
         }
 
         logger.debug("notifyTransmitReady with timeout {}", timeout);
@@ -475,22 +586,17 @@
         logger.debug("lifeness notifyTransmitReady {}", 
Scheduler.getCurrentLifeness());
 
 
-        final TransmitHelper transmit = new TransmitHelper(transmitter, 
Scheduler.getCurrentLifeness());
+        final TransmitHelper transmit = new TransmitHelper(transmitter, 
timeout, autoRetry);
 
         if (currentTransmitHelper == null) {
             currentTransmitHelper = transmit;
             if (chan.isConnected()) {
-                currentTransmitTimeout = null;
                 currentTransmitHelper.start();
-            } else {
-                currentTransmitTimeout = scheduleTransmitTimeout(transmitter, 
timeout, true);
             }
         } else {
             nextTransmitHelper = transmit;
-            nextTransmitTimeout = scheduleTransmitTimeout(transmitter, 
timeout, false);
         }
 
-
         return new TransmitHandle() {
             @Override
             public void cancel() {
@@ -505,21 +611,35 @@
      * todo: introduce finishPendingWrites parameter
      */
     public void disconnect() {
-        if (currentTransmitHelper != null) {
-            currentTransmitHelper.cancel();
+        disconnect(false);
+    }
+
+    public void disconnect(boolean finishPendingWrites) {
+        if (!finishPendingWrites || !currentTransmitHelper.notifyDone()) {
+            if (currentTransmitHelper != null) {
+                currentTransmitHelper.cancel();
+                currentReceiveHelper = null;
+            }
         }
-        if (currentTransmitTimeout != null) {
-            currentTransmitTimeout.cancel();
-        }
+
         if (nextTransmitHelper != null) {
             nextTransmitHelper.cancel();
+            nextTransmitHelper = null;
         }
-        if (nextTransmitTimeout != null) {
-            nextTransmitTimeout.cancel();
-        }
         if (currentReceiveHelper != null) {
             currentReceiveHelper.cancel();
+            currentReceiveHelper = null;
         }
+
+        if (resolveHandle != null) {
+            resolveHandle.cancel();
+            resolveHandle = null;
+        }
+
+        if (connectHandle != null) {
+            connectHandle.cancel();
+            connectHandle = null;
+        }
     }
 
 
@@ -529,4 +649,11 @@
         disconnect();
     }
 
+    public enum ReceiveError {
+        TIMEOUT, DISCONNECT, MSG_FORMAT
+    }
+
+    public enum TransmitError {
+        TIMEOUT, DISCONNECT
+    }
 }

Added: gnunet-java/src/org/gnunet/util/GnunetHash.java
===================================================================
--- gnunet-java/src/org/gnunet/util/GnunetHash.java                             
(rev 0)
+++ gnunet-java/src/org/gnunet/util/GnunetHash.java     2012-03-18 13:42:47 UTC 
(rev 20588)
@@ -0,0 +1,5 @@
+package org.gnunet.util;
+
+
+public class GnunetHash {
+}

Added: gnunet-java/src/org/gnunet/util/GnunetMessage.java
===================================================================
--- gnunet-java/src/org/gnunet/util/GnunetMessage.java                          
(rev 0)
+++ gnunet-java/src/org/gnunet/util/GnunetMessage.java  2012-03-18 13:42:47 UTC 
(rev 20588)
@@ -0,0 +1,36 @@
+package org.gnunet.util;
+
+
+import org.gnunet.construct.*;
+
+public class GnunetMessage implements Message {
+    public final int MINIMAL_SIZE = Header.SIZE;
+
+    public static class Header {
+        public static final int SIZE = 4;
+
+        @FrameSize
+        @UInt16
+        public int messageSize;
+
+        @UInt16
+        public int messageType;
+    }
+
+    public static interface Body extends MessageUnion {
+    }
+    
+    public static GnunetMessage fromBody(Body b) {
+        GnunetMessage msg = new GnunetMessage();
+        msg.header = new Header();
+        msg.header.messageSize = Header.SIZE + Construct.getSize(b);
+
+        return msg;
+    }
+
+    @Nested
+    public Header header;
+
+    @Union(tag = "header.messageType", optional = true)
+    public Body body;
+}

Modified: gnunet-java/src/org/gnunet/util/MessageReceiver.java
===================================================================
--- gnunet-java/src/org/gnunet/util/MessageReceiver.java        2012-03-17 
16:31:42 UTC (rev 20587)
+++ gnunet-java/src/org/gnunet/util/MessageReceiver.java        2012-03-18 
13:42:47 UTC (rev 20588)
@@ -32,13 +32,9 @@
     /**
      * Method to call when we receive a message from the service.
      * 
-     * @param msg
-     *            message received, NULL on deadline or fatal error
+     * @param msg   message received, null on deadline or fatal error
      */
     public void process(Message msg);
 
-    /**
-     * Method to call on deadline.
-     */
-    public void handleTimeout();
+    public void handleError(Client.ReceiveError e);
 }

Modified: gnunet-java/src/org/gnunet/util/MessageTransmitter.java
===================================================================
--- gnunet-java/src/org/gnunet/util/MessageTransmitter.java     2012-03-17 
16:31:42 UTC (rev 20587)
+++ gnunet-java/src/org/gnunet/util/MessageTransmitter.java     2012-03-18 
13:42:47 UTC (rev 20588)
@@ -1,7 +1,13 @@
 package org.gnunet.util;
 
 public interface MessageTransmitter {
+    /**
+     * Called when the client is ready to transmit messages, or on 
timeout/error.
+     *
+     * @param sink A message sink that receives messages to be transmitted by 
the client,
+     *             or null on timeout/error.
+     */
     public void transmit(Client.MessageSink sink);
 
-    public void handleTimeout();
+    void handleError(Client.TransmitError error);
 }

Added: gnunet-java/src/org/gnunet/util/PeerIdentity.java
===================================================================
--- gnunet-java/src/org/gnunet/util/PeerIdentity.java                           
(rev 0)
+++ gnunet-java/src/org/gnunet/util/PeerIdentity.java   2012-03-18 13:42:47 UTC 
(rev 20588)
@@ -0,0 +1,5 @@
+package org.gnunet.util;
+
+
+public class PeerIdentity {
+}

Modified: gnunet-java/src/org/gnunet/util/Resolver.java
===================================================================
--- gnunet-java/src/org/gnunet/util/Resolver.java       2012-03-17 16:31:42 UTC 
(rev 20587)
+++ gnunet-java/src/org/gnunet/util/Resolver.java       2012-03-18 13:42:47 UTC 
(rev 20588)
@@ -14,7 +14,6 @@
 import java.net.Inet6Address;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
-import java.util.Arrays;
 import java.util.LinkedList;
 
 public class Resolver {
@@ -214,7 +213,7 @@
         }
     }
 
-    public class ResolveHandle {
+    public class ResolveHandle implements Cancelable {
         private String hostname;
         private AbsoluteTime deadline;
         private AddressCallback cb;
@@ -322,6 +321,9 @@
                 new MessageTransmitter() {
                     @Override
                     public void transmit(Client.MessageSink sink) {
+                        if (sink == null) {
+                                onTimeout(rh);
+                        }
                         sink.send(req);
                         rh.transmitTask = null;
 
@@ -354,18 +356,20 @@
                             }
 
                             @Override
-                            public void handleTimeout() {
-                                logger.debug("timeout in recv");
-                                onTimeout(rh);
+                            public void handleError(Client.ReceiveError e) {
+                                if (e.equals(Client.ReceiveError.TIMEOUT)) {
+                                    onTimeout(rh);
+                                } else {
+                                    throw new RuntimeException("unexpected 
receive error");
+                                }
                             }
                         });
 
                     }
 
                     @Override
-                    public void handleTimeout() {
-                        logger.debug("timeout in notifyTransmitReady");
-                        onTimeout(rh);
+                    public void handleError(Client.TransmitError error) {
+                        throw new RuntimeException("unexpected transmit 
error");
                     }
                 });
     }

Modified: gnunet-java/src/org/gnunet/util/Scheduler.java
===================================================================
--- gnunet-java/src/org/gnunet/util/Scheduler.java      2012-03-17 16:31:42 UTC 
(rev 20587)
+++ gnunet-java/src/org/gnunet/util/Scheduler.java      2012-03-18 13:42:47 UTC 
(rev 20588)
@@ -79,7 +79,7 @@
     /**
      * A TaskIdentifier represents a Task that will execute or has already 
been executed.
      */
-    public static class TaskIdentifier implements Comparable<TaskIdentifier> {
+    public static class TaskIdentifier implements Comparable<TaskIdentifier>, 
Cancelable {
         private final Task task;
         private TaskIdentifier prereq;
         private RunContext ctx = new RunContext();
@@ -157,7 +157,7 @@
             this.lifeness = true;
         }
 
-        void run() {
+        private void run() {
             TaskIdentifier old = activeTask;
             activeTask = this;
             task.run(ctx);
@@ -176,11 +176,6 @@
             return lifeness;
         }
 
-        public void setLifeness(boolean newLifeness) {
-            lifeness = newLifeness;
-        }
-
-
         @Override
         public int compareTo(TaskIdentifier other) {
             return this.deadline.compareTo(other.deadline);
@@ -238,7 +233,7 @@
 
         }
 
-        public void deregister() {
+        private void deregister() {
             if (this.rs != null) {
                 for (SelectableChannel sc : this.rs) {
                     deregisterOne(sc, SelectionKey.OP_READ);

Modified: gnunet-java/test/org/gnunet/construct/ConstructTest.java
===================================================================
--- gnunet-java/test/org/gnunet/construct/ConstructTest.java    2012-03-17 
16:31:42 UTC (rev 20587)
+++ gnunet-java/test/org/gnunet/construct/ConstructTest.java    2012-03-18 
13:42:47 UTC (rev 20588)
@@ -4,28 +4,34 @@
 import org.junit.Test;
 
 import java.math.BigInteger;
+import java.nio.ByteBuffer;
 
 public class ConstructTest {
     
     
     @Test
     public void test_ByteFillMessage() {
-        System.out.println("testing ByteFillMessage");
         
         ByteFillMessage bfm = new ByteFillMessage();
         bfm.header = new MessageHeader();
         bfm.someValue = 42;
-        bfm.rest = new byte[] {1,2,3,4,5,6,7,100};
+        bfm.rest = new byte[] {1,2,3,4,5,6,7,100, 8};
         
-        Construct.patchSizeFields(bfm);
+        Construct.patch(bfm);
         
         bfm.header.messageSize = Construct.getSize(bfm);
+
+        bfm.header.messageType = 42;
         
         System.out.println(bfm.header.messageSize);
         
         byte[] data = Construct.toBinary(bfm);
+        
+        Assert.assertEquals(Construct.getSize(bfm), data.length);
+        
+        System.out.println("data size: " + data.length);
 
-        ByteFillMessage bfm2 = Construct.parseAs(data, 0, 
ByteFillMessage.class);
+        ByteFillMessage bfm2 = Construct.parseAs(ByteBuffer.wrap(data), 
ByteFillMessage.class);
         
         Assert.assertArrayEquals(bfm.rest, bfm2.rest);
     }
@@ -43,7 +49,7 @@
 
         byte[] a = Construct.toBinary(vtm);
 
-        VarTestMessage vtm2 = Construct.parseAs(a, 0, VarTestMessage.class);
+        VarTestMessage vtm2 = Construct.parseAs(ByteBuffer.wrap(a), 
VarTestMessage.class);
 
         Assert.assertEquals(vtm2.length, 5);
         for (int i = 0; i < 5; ++i) {
@@ -66,7 +72,7 @@
         }
 
         byte[] a = Construct.toBinary(stm);
-        SimpleTestMessage stm2 = Construct.parseAs(a, 0,
+        SimpleTestMessage stm2 = Construct.parseAs(ByteBuffer.wrap(a),
                 SimpleTestMessage.class);
 
         Assert.assertEquals(stm.v1, stm2.v1);
@@ -93,7 +99,7 @@
         strm.num2 = 80;
 
         byte[] a = Construct.toBinary(strm);
-        StringMessage strm2 = Construct.parseAs(a, 0, StringMessage.class);
+        StringMessage strm2 = Construct.parseAs(ByteBuffer.wrap(a), 
StringMessage.class);
 
         for (byte b : a) {
             System.out.print((char) b);
@@ -114,13 +120,13 @@
         qm.varsize = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
                 14, 15 };
 
-        Construct.patchSizeFields(qm);
+        Construct.patch(qm);
 
         byte[] a = Construct.toBinary(qm);
         
         Assert.assertEquals(a.length, qm.header.messageSize);
 
-        QueryMessage qm2 = Construct.parseAs(a, 0, QueryMessage.class);
+        QueryMessage qm2 = Construct.parseAs(ByteBuffer.wrap(a), 
QueryMessage.class);
 
         Assert.assertEquals(qm.header.messageSize, qm2.header.messageSize);
         Assert.assertEquals(qm.header.messageType, qm2.header.messageType);
@@ -136,11 +142,11 @@
         stm.someValue = 42;
         stm.rest = new byte[] { 1, 2, 3, 4, 5 };
 
-        Construct.patchSizeFields(stm);
+        Construct.patch(stm);
 
         byte[] a = Construct.toBinary(stm);
 
-        SizeTestMessage stm2 = Construct.parseAs(a, 0, SizeTestMessage.class);
+        SizeTestMessage stm2 = Construct.parseAs(ByteBuffer.wrap(a), 
SizeTestMessage.class);
 
         Assert.assertEquals(stm.someValue, stm2.someValue);
         Assert.assertEquals(stm.totalSize, stm2.totalSize);
@@ -157,7 +163,7 @@
 
         byte[] a = Construct.toBinary(h1);
 
-        MessageHeader h2 = Construct.parseAs(a, 0, MessageHeader.class);
+        MessageHeader h2 = Construct.parseAs(ByteBuffer.wrap(a), 
MessageHeader.class);
 
         byte[] b = Construct.toBinary(h2);
 

Modified: gnunet-java/test/org/gnunet/construct/UnionTest.java
===================================================================
--- gnunet-java/test/org/gnunet/construct/UnionTest.java        2012-03-17 
16:31:42 UTC (rev 20587)
+++ gnunet-java/test/org/gnunet/construct/UnionTest.java        2012-03-18 
13:42:47 UTC (rev 20588)
@@ -1,8 +1,11 @@
 package org.gnunet.construct;
 
 
+import org.junit.Assert;
 import org.junit.Test;
 
+import java.nio.ByteBuffer;
+
 public class UnionTest {
     public static interface TestUnion extends MessageUnion {}
     
@@ -37,8 +40,13 @@
         byte[] a = Construct.toBinary(utm);
         
         System.out.println(a.length);
+        System.out.println(Construct.getSize(utm));
+
         
-        UnionTestMessage utm2 = Construct.parseAs(a, 0, 
UnionTestMessage.class);
+        UnionTestMessage utm2 = Construct.parseAs(ByteBuffer.wrap(a), 
UnionTestMessage.class);
+        
+        
+        Assert.assertEquals(((TestUnionCase0) utm.instance).val, 
((TestUnionCase0) utm2.instance).val);
 
     }
 }

Deleted: gnunet-java/update-msgtypes.sh
===================================================================
--- gnunet-java/update-msgtypes.sh      2012-03-17 16:31:42 UTC (rev 20587)
+++ gnunet-java/update-msgtypes.sh      2012-03-18 13:42:47 UTC (rev 20588)
@@ -1,13 +0,0 @@
-#!/bin/sh
-
-# collect all source files
-find ./src/ ./test/ -name "*.java" > sources.txt
-
-# run annotation processor
-javac -cp "./bin/:./lib/*" -processor 
org.gnunet.construct.MessageIdAnnotationProcessor -proc:only -s src @sources.txt
-
-if [ $? ] ; then
-    rm sources.txt
-else
-    exit 1
-fi




reply via email to

[Prev in Thread] Current Thread [Next in Thread]