[geary/wip/714217-offline] Finishing up on persistance/ module



commit 4c4d37c1ffb715e1312dc553ebaa19bb290dcc57
Author: Jim Nelson <jim yorba org>
Date:   Thu Dec 12 19:12:14 2013 -0800

    Finishing up on persistance/ module

 src/CMakeLists.txt                                 |    1 +
 .../persistance-data-flavor-serializer.vala        |   20 +++---
 .../persistance/persistance-data-flavor.vala       |    3 +
 .../persistance/persistance-deserializer.vala      |   40 +++++++---
 src/engine/persistance/persistance-error.vala      |   12 +++
 .../persistance/persistance-flavor-keyfile.vala    |   61 ++++++++++-----
 .../persistance/persistance-serializable.vala      |   27 ++++++-
 .../persistance/persistance-serialized-type.vala   |   81 ++++++++++++++++++-
 src/engine/persistance/persistance-serializer.vala |   10 ++-
 src/engine/persistance/persistance.vala            |    4 +-
 10 files changed, 205 insertions(+), 54 deletions(-)
---
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 9dcaf88..8385f02 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -245,6 +245,7 @@ engine/persistance/persistance-data-flavor.vala
 engine/persistance/persistance-data-flavor-deserializer.vala
 engine/persistance/persistance-data-flavor-serializer.vala
 engine/persistance/persistance-deserializer.vala
+engine/persistance/persistance-error.vala
 engine/persistance/persistance-flavor-keyfile.vala
 engine/persistance/persistance-serializable.vala
 engine/persistance/persistance-serialized-type.vala
diff --git a/src/engine/persistance/persistance-data-flavor-serializer.vala 
b/src/engine/persistance/persistance-data-flavor-serializer.vala
index 641bfc1..38f9fa8 100644
--- a/src/engine/persistance/persistance-data-flavor-serializer.vala
+++ b/src/engine/persistance/persistance-data-flavor-serializer.vala
@@ -13,27 +13,27 @@
  */
 
 public interface Geary.Persistance.DataFlavorSerializer : BaseObject {
-    public abstract void set_bool(string name, bool b);
+    public abstract void set_bool(string name, bool b) throws Error;
     
-    public abstract void set_int(string name, int i);
+    public abstract void set_int(string name, int i) throws Error;
     
-    public abstract void set_int64(string name, int64 i64);
+    public abstract void set_int64(string name, int64 i64) throws Error;
     
-    public abstract void set_float(string name, float f);
+    public abstract void set_float(string name, float f) throws Error;
     
-    public abstract void set_double(string name, double d);
+    public abstract void set_double(string name, double d) throws Error;
     
-    public abstract void set_utf8(string name, string utf8);
+    public abstract void set_utf8(string name, string utf8) throws Error;
     
-    public abstract void set_int_array(string name, int[] iar);
+    public abstract void set_int_array(string name, int[] iar) throws Error;
     
-    public abstract void set_utf8_array(string name, string[] utf8ar);
+    public abstract void set_utf8_array(string name, string[] utf8ar) throws Error;
     
     /**
      * Returns the serialized byte stream as a { link Geary.Memory.Buffer}.
      *
-     * The DataFlavorSerializer is not required to reset its state after this call.  It should
-     * expect to be discarded soon after commit() is invoked.
+     * The { link DataFlavorSerializer} is not required to reset its state after this call.  It
+     * should expect to be discarded soon after commit() is invoked.
      */
     internal abstract Geary.Memory.Buffer commit() throws Error;
 }
diff --git a/src/engine/persistance/persistance-data-flavor.vala 
b/src/engine/persistance/persistance-data-flavor.vala
index e3f52ba..7c18b4b 100644
--- a/src/engine/persistance/persistance-data-flavor.vala
+++ b/src/engine/persistance/persistance-data-flavor.vala
@@ -23,6 +23,9 @@ public interface Geary.Persistance.DataFlavor : BaseObject {
      */
     internal abstract DataFlavorSerializer create_serializer(Serializable sobj);
     
+    /**
+     * Create a new { link DataFlavorDeserializer} to generate a { link Serializable} object.
+     */
     internal abstract DataFlavorDeserializer create_deserializer(Geary.Memory.Buffer buffer) throws Error;
 }
 
diff --git a/src/engine/persistance/persistance-deserializer.vala 
b/src/engine/persistance/persistance-deserializer.vala
index c860e79..151b99f 100644
--- a/src/engine/persistance/persistance-deserializer.vala
+++ b/src/engine/persistance/persistance-deserializer.vala
@@ -33,20 +33,24 @@ public class Geary.Persistance.Deserializer : BaseObject {
     
     public Serializable deserialize_properties(DataFlavorDeserializer deserializer)
         throws Error {
-        Serializable? sobj = activator.activate(deserializer.get_classname(),
-            deserializer.get_serialized_version());
-        // TODO: Need Errors
-        assert(sobj != null);
+        string classname = deserializer.get_classname();
+        if (String.is_empty(classname))
+            throw new PersistanceError.ACTIVATION("Unable to activate record: no classname");
+        
+        int version = deserializer.get_serialized_version();
+        Serializable? sobj = activator.activate(classname, version);
+        if (sobj == null)
+            throw new PersistanceError.ACTIVATION("Unable to activate %s:%d", classname, version);
         
         foreach (ParamSpec param_spec in sobj.get_class().list_properties()) {
+            // quietly pass over unserializable properties ... up to Activator to fill them with
+            // values
             if (!is_serializable(param_spec, false))
                 continue;
             
             if (!deserializer.has_value(param_spec.name)) {
-                debug("WARNING: Serialized stream does not contain parameter for %s",
-                    param_spec.name);
-                
-                continue;
+                throw new PersistanceError.NOT_FOUND("Property %s not stored for class %s:%d",
+                    param_spec.name, classname, version);
             }
             
             // Give the object the chance to manually deserialize the property
@@ -70,11 +74,25 @@ public class Geary.Persistance.Deserializer : BaseObject {
                     value.set_int64(deserializer.get_int64(param_spec.name));
                 break;
                 
+                case SerializedType.FLOAT:
+                    value = Value(typeof(float));
+                    value.set_float(deserializer.get_float(param_spec.name));
+                break;
+                
+                case SerializedType.DOUBLE:
+                    value = Value(typeof(double));
+                    value.set_double(deserializer.get_double(param_spec.name));
+                break;
+                
+                case SerializedType.UTF8:
+                    value = Value(typeof(string));
+                    value.set_string(deserializer.get_utf8(param_spec.name));
+                break;
+                
                 case SerializedType.INT_ARRAY:
                 case SerializedType.UTF8_ARRAY:
-                    debug("WARNING: int[] and string[] properties must be manually deserialized");
-                    
-                    continue;
+                    throw new PersistanceError.UNAVAILABLE("Property %s is an array, must be manually 
deserialized (%s:%d)",
+                        param_spec.name, classname, version);
                 
                 default:
                     assert_not_reached();
diff --git a/src/engine/persistance/persistance-error.vala b/src/engine/persistance/persistance-error.vala
new file mode 100644
index 0000000..276b10b
--- /dev/null
+++ b/src/engine/persistance/persistance-error.vala
@@ -0,0 +1,12 @@
+/* Copyright 2013 Yorba Foundation
+ *
+ * This software is licensed under the GNU Lesser General Public License
+ * (version 2.1 or later).  See the COPYING file in this distribution.
+ */
+
+public errordomain Geary.PersistanceError {
+    INVALID,
+    NOT_FOUND,
+    UNAVAILABLE,
+    ACTIVATION
+}
diff --git a/src/engine/persistance/persistance-flavor-keyfile.vala 
b/src/engine/persistance/persistance-flavor-keyfile.vala
index bccc3a0..4b7c185 100644
--- a/src/engine/persistance/persistance-flavor-keyfile.vala
+++ b/src/engine/persistance/persistance-flavor-keyfile.vala
@@ -12,7 +12,7 @@
  */
 
 public class Geary.Persistance.Flavor.GKeyFile : BaseObject, Geary.Persistance.DataFlavor {
-    private const string VERSION_NAME = "__version__";
+    private const string VERSION_NAME = "__v__";
     
     private class KeyFileSerializer :  BaseObject, DataFlavorSerializer {
         private string groupname;
@@ -21,47 +21,55 @@ public class Geary.Persistance.Flavor.GKeyFile : BaseObject, Geary.Persistance.D
         public KeyFileSerializer(Serializable sobj) {
             groupname = sobj.serialize_classname();
             
-            // set the object version number
-            keyfile.set_integer(groupname, VERSION_NAME, sobj.serialize_version());
+            // set the object interface version number
+            keyfile.set_integer(groupname, VERSION_NAME, sobj.interface_version());
         }
         
-        public void set_bool(string name, bool b) {
-            keyfile.set_integer(groupname, typename(name), SerializedType.BOOL.serialize());
+        public void set_bool(string name, bool b) throws Error {
+            check_name(name);
+            keyfile.set_value(groupname, typename(name), SerializedType.BOOL.serialize());
             keyfile.set_boolean(groupname, name, b);
         }
         
-        public void set_int(string name, int i) {
-            keyfile.set_integer(groupname, typename(name), SerializedType.INT.serialize());
+        public void set_int(string name, int i) throws Error {
+            check_name(name);
+            keyfile.set_value(groupname, typename(name), SerializedType.INT.serialize());
             keyfile.set_integer(groupname, name, i);
         }
         
-        public void set_int64(string name, int64 i64) {
-            keyfile.set_integer(groupname, typename(name), SerializedType.INT64.serialize());
+        public void set_int64(string name, int64 i64) throws Error {
+            check_name(name);
+            keyfile.set_value(groupname, typename(name), SerializedType.INT64.serialize());
             keyfile.set_int64(groupname, name, i64);
         }
         
-        public void set_float(string name, float f) {
-            keyfile.set_integer(groupname, typename(name), SerializedType.FLOAT.serialize());
+        public void set_float(string name, float f) throws Error {
+            check_name(name);
+            keyfile.set_value(groupname, typename(name), SerializedType.FLOAT.serialize());
             keyfile.set_double(groupname, name, f);
         }
         
-        public void set_double(string name, double d) {
-            keyfile.set_integer(groupname, typename(name), SerializedType.DOUBLE.serialize());
+        public void set_double(string name, double d) throws Error {
+            check_name(name);
+            keyfile.set_value(groupname, typename(name), SerializedType.DOUBLE.serialize());
             keyfile.set_double(groupname, name, d);
         }
         
-        public void set_utf8(string name, string utf8) {
-            keyfile.set_integer(groupname, typename(name), SerializedType.UTF8.serialize());
+        public void set_utf8(string name, string utf8) throws Error {
+            check_name(name);
+            keyfile.set_value(groupname, typename(name), SerializedType.UTF8.serialize());
             keyfile.set_string(groupname, name, utf8);
         }
         
-        public void set_int_array(string name, int[] iar) {
-            keyfile.set_integer(groupname, typename(name), SerializedType.INT_ARRAY.serialize());
+        public void set_int_array(string name, int[] iar) throws Error {
+            check_name(name);
+            keyfile.set_value(groupname, typename(name), SerializedType.INT_ARRAY.serialize());
             keyfile.set_integer_list(groupname, name, iar);
         }
         
-        public void set_utf8_array(string name, string[] utf8ar) {
-            keyfile.set_integer(groupname, typename(name), SerializedType.UTF8_ARRAY.serialize());
+        public void set_utf8_array(string name, string[] utf8ar) throws Error {
+            check_name(name);
+            keyfile.set_value(groupname, typename(name), SerializedType.UTF8_ARRAY.serialize());
             keyfile.set_string_list(groupname, name, utf8ar);
         }
         
@@ -94,7 +102,7 @@ public class Geary.Persistance.Flavor.GKeyFile : BaseObject, Geary.Persistance.D
         }
         
         public SerializedType get_value_type(string name) throws Error {
-            return SerializedType.deserialize(keyfile.get_integer(groupname, typename(name)));
+            return SerializedType.deserialize(keyfile.get_value(groupname, typename(name)));
         }
         
         public bool get_bool(string name) throws Error {
@@ -153,6 +161,19 @@ public class Geary.Persistance.Flavor.GKeyFile : BaseObject, Geary.Persistance.D
         return "__t_%s__".printf(name);
     }
     
+    /**
+     * TODO: Rather than spit invalid names back at the caller, transform them into something
+     * suitable and transform them back at deserialization time.  For now, however, KeyFile doesn't
+     * support certain property names.
+     */
+    private static void check_name(string name) throws Error {
+        if (name.has_prefix("__")) {
+            throw new PersistanceError.INVALID(
+                "Data flavor KeyFile doesn't support property names with two leading underscores (%s)",
+                name);
+        }
+    }
+    
     internal DataFlavorSerializer create_serializer(Serializable sobj) {
         return new KeyFileSerializer(sobj);
     }
diff --git a/src/engine/persistance/persistance-serializable.vala 
b/src/engine/persistance/persistance-serializable.vala
index b501b5d..c05a407 100644
--- a/src/engine/persistance/persistance-serializable.vala
+++ b/src/engine/persistance/persistance-serializable.vala
@@ -24,7 +24,7 @@ public interface Geary.Persistance.Serializable : Object {
      *
      * If the properties of the implementing class changes, this value should be incremented.
      */
-    public abstract int serialize_version();
+    public abstract int interface_version();
     
     /**
      * Manual serialization of a property.
@@ -32,9 +32,30 @@ public interface Geary.Persistance.Serializable : Object {
      * If { link Serializer} is incapable of serializing a property, this method is called.
      * The object must either manually serialize the property (use name to determine which) and
      * return true, or return false.
+     *
+     * In particular, although { link DataFlavorSerializer} offers methods to serialize integer
+     * and string arrays, Serializer is ''unable'' to automatically determine the type of those
+     * properties due to limitations of GType, and so the Serializable object must do those itself.
      */
-    public abstract bool serialize_property(string name, DataFlavorSerializer serializer) throws Error;
+    public virtual bool serialize_property(string name, DataFlavorSerializer serializer) throws Error {
+        return false;
+    }
     
-    public abstract bool deserialize_property(string name, DataFlavorDeserializer deserializer) throws Error;
+    /**
+     * Manual deserialization of a property.
+     *
+     * { link Deserializer} gives the { link Serializable} object a chance to manually deserialize
+     * a property before it attempts to do it automatically.
+     *
+     * If { link Serializer} is incapable of serializing a property, this method is called.
+     * The object must either manually serialize the property (use name to determine which) and
+     * return true, or return false.  Integer and string arrays in particular must be deserialized
+     * manually.
+     *
+     * @see serialize_property
+     */
+    public virtual bool deserialize_property(string name, DataFlavorDeserializer deserializer) throws Error {
+        return false;
+    }
 }
 
diff --git a/src/engine/persistance/persistance-serialized-type.vala 
b/src/engine/persistance/persistance-serialized-type.vala
index 30df04c..8efd21e 100644
--- a/src/engine/persistance/persistance-serialized-type.vala
+++ b/src/engine/persistance/persistance-serialized-type.vala
@@ -10,7 +10,7 @@
  * The integer values for this enumeration are immutable and will not change in the future.
  */
 
-public enum SerializedType {
+public enum Geary.Persistance.SerializedType {
     BOOL = 0,
     INT,
     INT64,
@@ -20,12 +20,83 @@ public enum SerializedType {
     INT_ARRAY,
     UTF8_ARRAY;
     
-    public int serialize() {
-        return (int) this;
+    /**
+     * Returns a somewhat human-readable string for serializing a type.
+     *
+     * The enumerated values (0..n) won't change in the future, but if the { link DataFlavor}
+     * prefers to use a string rather than an integer value to store type information, this and
+     * { link deserialize} are available.
+     */
+    public unowned string serialize() throws Error {
+        if (!is_valid())
+            throw new PersistanceError.INVALID("Invalid SerializedType: %d", (int) this);
+        
+        switch (this) {
+            case BOOL:
+                return "b";
+            
+            case INT:
+                return "i";
+            
+            case INT64:
+                return "i64";
+            
+            case FLOAT:
+                return "f";
+            
+            case DOUBLE:
+                return "d";
+            
+            case UTF8:
+                return "s";
+            
+            case INT_ARRAY:
+                return "iar";
+            
+            case UTF8_ARRAY:
+                return "sar";
+            
+            default:
+                assert_not_reached();
+        }
     }
     
-    public static SerializedType deserialize(int value) throws Error {
-        return (SerializedType) value;
+    /**
+     * Deserializes a string from { link serialize} into a { link SerializedType}.
+     */
+    public static SerializedType deserialize(string value) throws Error {
+        switch (value) {
+            case "b":
+                return BOOL;
+            
+            case "i":
+                return INT;
+            
+            case "i64":
+                return INT64;
+            
+            case "f":
+                return FLOAT;
+            
+            case "d":
+                return DOUBLE;
+            
+            case "s":
+                return UTF8;
+            
+            case "iar":
+                return INT_ARRAY;
+            
+            case "sar":
+                return UTF8_ARRAY;
+            
+            default:
+                throw new PersistanceError.INVALID("Invalid SerializedType: %d", value);
+        }
+    }
+    
+    public bool is_valid() {
+        return Numeric.int_in_range_inclusive(this, BOOL, UTF8_ARRAY);
     }
 }
 
diff --git a/src/engine/persistance/persistance-serializer.vala 
b/src/engine/persistance/persistance-serializer.vala
index 7139c29..c85b9d3 100644
--- a/src/engine/persistance/persistance-serializer.vala
+++ b/src/engine/persistance/persistance-serializer.vala
@@ -21,6 +21,12 @@
 public class Geary.Persistance.Serializer : BaseObject {
     private DataFlavor flavor;
     
+    /**
+     * Fired during serialization when a property is encountered that { link Serializer} cannot
+     * serialize and the object itself does not manually serialize.
+     */
+    public signal void unsupported_property(Serializable sobj, string prop_name);
+    
     public Serializer(DataFlavor flavor) {
         this.flavor = flavor;
     }
@@ -60,11 +66,9 @@ public class Geary.Persistance.Serializer : BaseObject {
             } else if (param_spec.value_type == typeof(string)) {
                 serializer.set_utf8(param_spec.name, (string) value);
             } else if (!sobj.serialize_property(param_spec.name, serializer)) {
-                debug("WARNING: %s type %s not supported by Serializer", param_spec.name,
-                    param_spec.value_type.name());
+                unsupported_property(sobj, param_spec.name);
             }
         }
     }
 }
 
-
diff --git a/src/engine/persistance/persistance.vala b/src/engine/persistance/persistance.vala
index 40f6f99..81141a2 100644
--- a/src/engine/persistance/persistance.vala
+++ b/src/engine/persistance/persistance.vala
@@ -19,14 +19,14 @@ namespace Geary.Persistance {
 private bool is_serializable(ParamSpec param_spec, bool warn) {
     if ((param_spec.flags & ParamFlags.READWRITE) == 0) {
         if (warn) {
-            debug("WARNING: %s type %s not read/write, cannot be serialized", param_spec.name,
+            debug("%s type %s not read/write, cannot be serialized", param_spec.name,
                 param_spec.value_type.name());
         }
         
         return false;
     } else if ((param_spec.flags & ParamFlags.CONSTRUCT_ONLY) != 0) {
         if (warn) {
-            debug("WARNING: %s type %s is construct-only, cannot be serialized", param_spec.name,
+            debug("%s type %s is construct-only, cannot be serialized", param_spec.name,
                 param_spec.value_type.name());
         }
         


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