[AMBClient] - somewhat working json protocol engine
authorKevron Rees <tripzero.kev@gmail.com>
Mon, 2 Feb 2015 07:45:20 +0000 (23:45 -0800)
committerKevron Rees <tripzero.kev@gmail.com>
Mon, 2 Feb 2015 07:45:20 +0000 (23:45 -0800)
23 files changed:
README.md
lib/CMakeLists.txt
lib/abstractpropertytype.cpp
lib/abstractpropertytype.h
lib/debugout.h
lib/jsonhelper.cpp [new file with mode: 0644]
lib/jsonhelper.h [new file with mode: 0644]
lib/listplusplus.h
lib/mappropertytype.hpp
lib/vehicleproperty.cpp
lib/vehicleproperty.h
plugins/bluemonkey/bluemonkey.cpp
plugins/common/jsonprotocol.cpp
plugins/common/jsonprotocol.h
plugins/exampleplugin.cpp
plugins/testplugin/testplugin.cpp
plugins/testplugin/testplugin.h
plugins/websocket/common.cpp
plugins/websocket/common.h
tests/CMakeLists.txt
tests/testProtocol.cpp [new file with mode: 0644]
tests/testProtocolClient.cpp [new file with mode: 0644]
tests/testProtocolCommon.h [new file with mode: 0644]

index 7ed3e02..a1c5075 100644 (file)
--- a/README.md
+++ b/README.md
@@ -60,7 +60,7 @@ You will also need to edit your config to enable the Qt-based mainloop:
 
 ~~~~~~~~~~~~~{.json}
 {
-       "mainloop" : "/usr/lib/i386-linux-gnu/automotive-message-broker/qtmainloopplugin.so",
+       "mainloop" : "/usr/lib/x86_64-linux-gnu/automotive-message-broker/qtmainloopplugin.so",
        "plugins" : "/etc/ambd/plugins.d"
 }
 ~~~~~~~~~~~~~
index ce7fc7f..f0f04fa 100644 (file)
@@ -1,5 +1,5 @@
-set(amb_sources abstractpropertytype.cpp abstractroutingengine.cpp listplusplus.cpp abstractsink.cpp vehicleproperty.cpp abstractsource.cpp debugout.cpp timestamp.cpp uuidhelper.cpp mappropertytype.hpp propertyinfo.hpp superptr.hpp asyncqueue.hpp ambpluginimpl.cpp ambplugin.h picojson.h)
-set(amb_headers_install abstractpropertytype.h nullptr.h abstractroutingengine.h listplusplus.h abstractsink.h vehicleproperty.h debugout.h abstractsource.h timestamp.h uuidhelper.h mappropertytype.hpp propertyinfo.hpp superptr.hpp asyncqueue.hpp ambplugin.h ambpluginimpl.h picojson.h)
+set(amb_sources abstractpropertytype.cpp abstractroutingengine.cpp listplusplus.cpp abstractsink.cpp vehicleproperty.cpp abstractsource.cpp debugout.cpp timestamp.cpp uuidhelper.cpp mappropertytype.hpp propertyinfo.hpp superptr.hpp asyncqueue.hpp ambpluginimpl.cpp ambplugin.h picojson.h jsonhelper.cpp)
+set(amb_headers_install abstractpropertytype.h nullptr.h abstractroutingengine.h listplusplus.h abstractsink.h vehicleproperty.h debugout.h abstractsource.h timestamp.h uuidhelper.h mappropertytype.hpp propertyinfo.hpp superptr.hpp asyncqueue.hpp ambplugin.h ambpluginimpl.h picojson.h jsonhelper.h)
 
 add_library(amb SHARED ${amb_sources})
 
index 5ad2588..62321bf 100644 (file)
@@ -6,3 +6,29 @@ const Zone::Type Zone::MiddleRight = Zone::Type(Zone::Middle | Zone::Right);
 const Zone::Type Zone::MiddleLeft = Zone::Type(Zone::Middle | Zone::Left);
 const Zone::Type Zone::RearRight = Zone::Type(Zone::Rear | Zone::Right);
 const Zone::Type Zone::RearLeft = Zone::Type(Zone::Rear | Zone::Left);
+
+
+const picojson::value AbstractPropertyType::toJson()
+{
+       picojson::object obj;
+
+       obj["name"] = picojson::value(name);
+       obj["alias"] = picojson::value(alias());
+       obj["source"] = picojson::value(sourceUuid);
+       obj["zone"] = picojson::value((double)zone);
+       obj["timestamp"] = picojson::value(timestamp);
+       obj["sequence"] = picojson::value((double)sequence);
+       obj["type"] = picojson::value(amb::BasicTypes::fromAbstractProperty(this));
+
+       return picojson::value(obj);
+}
+
+void AbstractPropertyType::fromJson(const picojson::value &json)
+{
+       name = json.get("name").to_str();
+       mAlias = json.get("alias").to_str();
+       sourceUuid = json.get("source").to_str();
+       zone = json.get("zone").get<double>();
+       timestamp = json.get("timestamp").get<double>();
+       sequence = json.get("sequence").get<double>();
+}
index bfdd45a..e0a2f00 100644 (file)
 #ifndef _ABSTRACTPROPERTYTYPE_H_
 #define _ABSTRACTPROPERTYTYPE_H_
 
-#include <string>
-#include <sstream>
-#include <stdexcept>
-#include <vector>
-#include <iostream>
-#include <memory>
+#include "debugout.h"
+#include "jsonhelper.h"
+#include "picojson.h"
+#include "superptr.hpp"
+#include "timestamp.h"
+
+#include <boost/algorithm/string.hpp>
 #include <boost/any.hpp>
 #include <boost/lexical_cast.hpp>
 #include <boost/utility.hpp>
+#include <iostream>
+#include <list>
+#include <memory>
+#include <string>
+#include <sstream>
+#include <stdexcept>
 #include <type_traits>
+#include <vector>
+
 #include <glib.h>
-#include <list>
-#include "timestamp.h"
-#include <debugout.h>
-#include <boost/algorithm/string.hpp>
-#include <superptr.hpp>
 
 class Zone {
 
@@ -102,39 +106,61 @@ public:
                }
        }
 
-       /**
-        * @brief toString
-        * @return strigified value
+       /*!
+        * \brief toJson convert this type to json representation.
+        * The json typically looks something like this:
+        * \code
+        * {
+        *  "name" : "VehicleSpeed",
+        *  "type" : "UInt16",
+        *  "source" : "daf23v32342ddsdffafaeefe",
+        *  "zone" : 0,
+        *  "value" : 25
+        * }
+        * \endcode
+        * \return json value representing the type
+        */
+       virtual const picojson::value toJson();
+
+       /*!
+        * \brief fromJson instantiate this type from json
+        * \param json
+        */
+       virtual void fromJson(const picojson::value & json);
+
+       /*!
+        * \brief toString
+        * \return strigified value
         */
        virtual std::string toString() const = 0;
 
-       /**
-        * @brief fromString converts from string value
+       /*!
+        * \brief fromString converts from string value
         */
-       virtual void fromString(std::string)= 0;
+       virtual void fromString(std::string) = 0;
 
-       /**
-        * @brief toVariant
-        * @return GVariant representation of value. Caller must unref the returned GVariant
+       /*!
+        * \brief toVariant
+        * \return GVariant representation of value. Caller must unref the returned GVariant
         */
        virtual GVariant* toVariant() = 0;
 
-       /**
-        * @brief fromVariant converts GVariant value into compatible native value.  Caller owns
+       /*!
+        * \brief fromVariant converts GVariant value into compatible native value.  Caller owns
         * GVariant argument.
         */
        virtual void fromVariant(GVariant*) = 0;
 
-       /**
-        * @brief copy
-        * @return a copy of the AbstractPropertyType
+       /*!
+        * \brief copy
+        * \return a copy of the AbstractPropertyType
         */
        virtual AbstractPropertyType* copy() = 0;
 
-       /**
-        * @brief quickCopy is intended as a way to quickly copy the often changing bits from one abstract property to another
+       /*!
+        * \brief quickCopy is intended as a way to quickly copy the often changing bits from one abstract property to another
         * It assumes that the properties are almost identical in name, source, and zone.
-        * @param other the property to copy from
+        * \param other the property to copy from
         */
        virtual void quickCopy(AbstractPropertyType* other)
        {
@@ -160,32 +186,40 @@ public:
                return one != two;
        }
 
-       /**
-        * @brief name Property name. @see VehicleProperty for built-in supported property names
+       /*!
+        * \brief name Property name. \see VehicleProperty for built-in supported property names
         */
        std::string name;
 
-       /**
-        * @brief timestamp.  Timestamp when the value was last updated by the system. This is updated automatically
+       /*!
+        * \brief alias alias for the property name
+        * \return alias if any of name if alias has not been set
+        */
+       const std::string alias() { return mAlias.empty() ? name : mAlias; }
+
+       void setAlias(const std::string & a) { mAlias = a; }
+
+       /*!
+        * \brief timestamp.  Timestamp when the value was last updated by the system. This is updated automatically
         * any time setValue() is called
-        * @see amb::currentTime()
-        * @see setValue()
+        * \see amb::currentTime()
+        * \see setValue()
         */
        double timestamp;
 
-       /**
-        * @brief sequence internal counter.  Useful as a unique indentifier.  values is -1 if not used (default).
+       /*!
+        * \brief sequence internal counter.  Useful as a unique indentifier.  values is -1 if not used (default).
         */
        int32_t sequence;
 
-       /**
-        * @brief sourceUuid  uuid of the source that produced this property.  This is set by the routingengine
+       /*!
+        * \brief sourceUuid  uuid of the source that produced this property.  This is set by the routingengine
         * if left unmodified.
         */
        std::string sourceUuid;
 
-       /**
-        * @brief zone that the property is situated in.
+       /*!
+        * \brief zone that the property is situated in.
         */
        Zone::Type zone;
 
@@ -197,9 +231,9 @@ public:
         */
        Priority priority;
 
-       /**
-        * @brief setValue
-        * @param val boost::any value.  NOTE: boost::any does not accept type coercion.  Types must match exactly
+       /*!
+        * \brief setValue
+        * \param val boost::any value.  NOTE: boost::any does not accept type coercion.  Types must match exactly
         * with native type. (ie, don't use "int" if the native type is "uint")
         */
        virtual void setValue(boost::any val)
@@ -208,7 +242,7 @@ public:
                timestamp = amb::currentTime();
        }
 
-       /**
+       /*!
         * \brief value() native value.  Does not use type coercion.  Will throw if types do not match.
         */
        template <typename T>
@@ -217,9 +251,9 @@ public:
                return boost::any_cast<T>(mValue);
        }
 
-       /**
-        * @brief anyValue
-        * @return boost::any value
+       /*!
+        * \brief anyValue
+        * \return boost::any value
         */
        boost::any anyValue()
        {
@@ -242,8 +276,8 @@ public:
                return s;
        }
 
-       /**
-        * @brief destroyed is called if this property is destroyed.
+       /*!
+        * \brief destroyed is called if this property is destroyed.
         */
        std::vector<std::function<void(AbstractPropertyType*)>> destroyed;
 
@@ -251,6 +285,7 @@ protected:
 
        boost::any mValue;
 
+       std::string mAlias;
 };
 
 namespace amb
@@ -275,11 +310,64 @@ struct PropertyCompare
 }
 
 
+class JsonNumber
+{
+public:
+       static double fromJson(picojson::value v)
+       {
+               return v.get<double>();
+       }
+
+       static picojson::value toJson(double v)
+       {
+               return picojson::value(v);
+       }
+};
+
+class JsonBoolean
+{
+public:
+       static bool fromJson(picojson::value v)
+       {
+               return v.get<bool>();
+       }
+
+       static picojson::value toJson(bool v)
+       {
+               return picojson::value(v);
+       }
+};
+
+class JsonString
+{
+public:
+       static std::string fromJson(picojson::value v)
+       {
+               return v.get<std::string>();
+       }
+
+       static picojson::value toJson(std::string v)
+       {
+               return picojson::value(v);
+       }
+};
+
+
+template <typename T>
+class BaseGVS
+{
+public:
+       static T gvalue(T t)
+       {
+               return t;
+       }
+};
+
 template <typename T>
 class GVS;
 
 template <>
-class GVS<int>
+class GVS<int> : public BaseGVS<int>, public JsonNumber
 {
 public:
        static const char* signature() { return "i"; }
@@ -298,7 +386,7 @@ public:
 };
 
 template <>
-class GVS<double>
+class GVS<double> : public BaseGVS<double>, public JsonNumber
 {
 public:
        static const char* signature() { return "d"; }
@@ -314,7 +402,7 @@ public:
 };
 
 template <>
-class GVS<uint16_t>
+class GVS<uint16_t> : public BaseGVS<uint16_t>, public JsonNumber
 {
 public:
        static const char* signature() { return "q"; }
@@ -330,7 +418,7 @@ public:
 };
 
 template <>
-class GVS<int16_t>
+class GVS<int16_t> : public BaseGVS<int16_t>, public JsonNumber
 {
 public:
        static const char* signature() { return "n"; }
@@ -346,7 +434,7 @@ public:
 };
 
 template <>
-class GVS<char>
+class GVS<char> : public BaseGVS<char>, public JsonNumber
 {
 public:
        static const char* signature() { return "y"; }
@@ -362,7 +450,7 @@ public:
 };
 
 template <>
-class GVS<uint32_t>
+class GVS<uint32_t> : public BaseGVS<uint32_t>, public JsonNumber
 {
 public:
        static const char* signature() { return "u"; }
@@ -378,7 +466,7 @@ public:
 };
 
 template <>
-class GVS<int64_t>
+class GVS<int64_t> : public BaseGVS<int64_t>, public JsonNumber
 {
 public:
        static const char* signature() { return "x"; }
@@ -394,7 +482,7 @@ public:
 };
 
 template <>
-class GVS<uint64_t>
+class GVS<uint64_t> : public BaseGVS<uint64_t>, public JsonNumber
 {
 public:
        static const char* signature() { return "t"; }
@@ -410,7 +498,7 @@ public:
 };
 
 template <>
-class GVS<bool>
+class GVS<bool> : public BaseGVS<bool>, public JsonBoolean
 {
 public:
        static const char* signature() { return "b"; }
@@ -429,7 +517,27 @@ public:
        }
 };
 
-/**
+template <>
+class GVS<std::string> : public JsonString
+{
+public:
+       static const char* signature() { return "s"; }
+
+       static const char* value(GVariant *v)
+       {
+               return g_variant_get_string(v, nullptr);
+       }
+       static std::string stringize(std::string v)
+       {
+               return v;
+       }
+       static const char* gvalue(std::string v)
+       {
+               return v.c_str();
+       }
+};
+
+/*!
  * \brief BasicPropertyType is a typed property type.  Most internal types are derived from this class
  * \example
  * std::unique_ptr<BasicPropertyType<int>> boostPSI = new BasicPropertyType<int>("BoostPSI",5);
@@ -528,6 +636,24 @@ public:
                return new BasicPropertyType<T>(*this);
        }
 
+       const picojson::value toJson()
+       {
+               picojson::value v = AbstractPropertyType::toJson();
+
+               picojson::object object = v.get<picojson::object>();
+
+               object["value"] = amb::gvariantToJson(toVariant());
+
+               return picojson::value(object);
+       }
+
+       virtual void fromJson(const picojson::value &json)
+       {
+               AbstractPropertyType::fromJson(json);
+
+               fromVariant(amb::jsonToGVariant(json.get("value"), signature()));
+       }
+
        void fromString(std::string val)
        {
                if(!val.empty() && val != "")
@@ -555,9 +681,9 @@ public:
                setValue(deserializeVariant<T>(v));
        }
 
-       /**
-        * @brief basicValue
-        * @return Typed version of value.  Slightly more useful than @see AbstractPropertyType::value()
+       /*!
+        * \brief basicValue
+        * \return Typed version of value.  Slightly more useful than \see AbstractPropertyType::value()
         */
 
        T basicValue()
@@ -577,10 +703,8 @@ public:
 
 private:
 
-       //GVariant* mVariant;
-
        template <class N>
-       void serialize(std::string val,  typename std::enable_if<std::is_enum<N>::value, N>::type* = 0)
+       void serialize(const std::string & val,  typename std::enable_if<std::is_enum<N>::value, N>::type* = 0)
        {
                int someTemp;
 
@@ -591,7 +715,7 @@ private:
        }
 
        template <class N>
-       void serialize(std::string  val,  typename std::enable_if<!std::is_enum<N>::value, N>::type* = 0)
+       void serialize(const std::string & val,  typename std::enable_if<!std::is_enum<N>::value, N>::type* = 0)
        {
                std::stringstream stream(GVS<T>::stringize(val));
                N someTemp;
@@ -600,33 +724,26 @@ private:
        }
 
        template <class N>
-       GVariant* serializeVariant(T val, typename std::enable_if<std::is_enum<N>::value, N>::type* = 0)
+       GVariant* serializeVariant(const T val, typename std::enable_if<std::is_enum<N>::value, N>::type* = 0)
        {
-               //mVariant = Glib::VariantBase(Glib::Variant<gint16>::create((int)val).gobj());
-
                return (g_variant_new("i",(int)val));
        }
 
        template <class N>
-       GVariant* serializeVariant(T val, typename std::enable_if<!std::is_enum<N>::value, N>::type* = 0)
+       GVariant* serializeVariant(const T val, typename std::enable_if<!std::is_enum<N>::value, N>::type* = 0)
        {
-               //mVariant = Glib::Variant<T>::create(val);
-               //mVariant = g_variant_ref(g_variant_new(GVS<T>::signature(),val));
                return g_variant_new(GVS<T>::signature(),val);
        }
 
        template <class N>
        T deserializeVariant(GVariant* v, typename std::enable_if<std::is_enum<N>::value, N>::type* = 0)
        {
-//             return (T)((Glib::Variant<int>::cast_dynamic<Glib::Variant<int> >(*v)).get());
-
                return (T)GVS<int>::value(v);
        }
 
        template <class N>
        T deserializeVariant(GVariant* v, typename std::enable_if<!std::is_enum<N>::value, N>::type* = 0)
        {
-               //      return Glib::VariantBase::cast_dynamic<Glib::Variant<T> >(*v).get();
                return GVS<T>::value(v);
        }
 };
@@ -688,6 +805,21 @@ public:
                return value<std::string>() < other.value<std::string>();
        }
 
+       virtual const picojson::value toJson()
+       {
+               auto val = AbstractPropertyType::toJson();
+
+               picojson::object obj = val.get<picojson::object>();
+
+               obj["value"] = amb::gvariantToJson(toVariant());
+       }
+
+       virtual void fromJson(const picojson::value &json)
+       {
+               AbstractPropertyType::fromJson(json);
+
+               fromString(json.get("value").to_str());
+       }
 
        void fromString(std::string val)
        {
@@ -721,7 +853,7 @@ public:
 /*!
  * \brief ListPropertyType is a AbstractPropertyType for arrays of AbstractPropertyTypes
  */
-template <class T = AbstractPropertyType>
+template <class T>
 class ListPropertyType: public AbstractPropertyType
 {
 public:
@@ -759,8 +891,8 @@ public:
                clear();
        }
 
-       /** \brief append - appends a property to the list
-        * @arg property - property to be appended.
+       /*! \brief append - appends a property to the list
+        * \arg property - property to be appended.
         **/
        void append(T property)
        {
@@ -797,61 +929,41 @@ public:
 
        std::string toString() const
        {
-               std::string str = "[";
+               picojson::array array;
 
-               for(auto itr = mList.begin(); itr != mList.end(); itr++)
+               for(auto i : mList)
                {
-                       if(str != "[")
-                               str += ",";
-
-                       T t = *itr;
-
-                       str += t.toString();
+                       array.push_back(GVS<T>::toJson(i));
                }
 
-               str += "]";
-
-               return str;
+               return picojson::value(array).serialize();
        }
 
 
-       void fromString(std::string str )
+       void fromString(std::string str)
        {
-               clear();
+               picojson::value value;
+               picojson::parse(value, str);
 
-               if(!str.length())
-                       return;
+               picojson::array array = value.get<picojson::array>();
 
-               if(str[0] == '[' && str[str.length()-1] == ']')
+               for(auto i : array)
                {
-                       str = str.substr(1,str.length() - 2);
+                       mList.push_back(GVS<T>::fromJson(i));
                }
 
-               std::vector<std::string> elements;
-
-               std::istringstream f(str);
-
-               std::string element;
-               while(std::getline(f,element,','))
-               {
-                       T foo("", element);
-                       append (foo);
-               }
                timestamp = amb::currentTime();
        }
 
 
        GVariant* toVariant()
        {
-
                GVariantBuilder params;
                g_variant_builder_init(&params, ((const GVariantType *) "av"));
 
-               for(auto itr = mList.begin(); itr != mList.end(); itr++)
+               for(auto itr : mList)
                {
-                       T t = *itr;
-                       auto var = t.toVariant();
-                       GVariant *newvar = g_variant_new("v", var);
+                       GVariant *newvar = g_variant_new(GVS<T>::signature(), GVS<T>::gvalue(itr));
                        g_variant_builder_add_value(&params, newvar);
                }
 
@@ -871,9 +983,7 @@ public:
                {
                        GVariant *childvariant = g_variant_get_child_value(v,i);
                        GVariant *innervariant = g_variant_get_variant(childvariant);
-                       T t;
-                       t.fromVariant(innervariant);
-                       appendPriv(t);
+                       appendPriv(GVS<T>::value(innervariant));
                }
        }
 
index a164908..c63b183 100644 (file)
@@ -113,8 +113,6 @@ public:
 
        DebugOut const& operator << (ostream & (*manip)(std::ostream&)) const
        {
-
-
                if(mDebugLevel <= debugThreshhold || mDebugLevel == Error || mDebugLevel == Warning)
                {
                        ostream out(buf);
diff --git a/lib/jsonhelper.cpp b/lib/jsonhelper.cpp
new file mode 100644 (file)
index 0000000..ff1d879
--- /dev/null
@@ -0,0 +1,148 @@
+#include "jsonhelper.h"
+
+#include "abstractpropertytype.h"
+#include "debugout.h"
+
+const char * amb::BasicTypes::UInt16Str = "UInt16";
+const char * amb::BasicTypes::UInt32Str = "UInt32";
+const char * amb::BasicTypes::Int16Str = "Int16";
+const char * amb::BasicTypes::Int32Str = "Int32";
+const char * amb::BasicTypes::StringStr = "String";
+const char * amb::BasicTypes::DoubleStr = "Double";
+const char * amb::BasicTypes::BooleanStr = "Boolean";
+
+picojson::value amb::gvariantToJson(GVariant* value)
+{
+       std::string type = g_variant_get_type_string(value);
+       picojson::value v;
+
+       if (type == "i")
+       {
+               int tempVal = GVS<int>::value(value);
+               v = picojson::value(static_cast<double>(tempVal));
+       }
+       else if (type == "d")
+       {
+               v = picojson::value(GVS<double>::value(value));
+       }
+       else if (type == "q")
+       {
+               v = picojson::value(static_cast<double>(GVS<uint16_t>::value(value)));
+       }
+       else if (type == "n")
+       {
+               v = picojson::value(static_cast<double>(GVS<int16_t>::value(value)));
+       }
+       else if (type == "y")
+       {
+               v = picojson::value(static_cast<double>(GVS<char>::value(value)));
+       }
+       else if (type == "u")
+       {
+               v = picojson::value(static_cast<double>(GVS<uint32_t>::value(value)));
+       }
+       else if (type == "x")
+       {
+               v = picojson::value(static_cast<double>(GVS<int64_t>::value(value)));
+       }
+       else if (type == "t")
+       {
+               v = picojson::value(static_cast<double>(GVS<uint64_t>::value(value)));
+       }
+       else if (type == "b")
+       {
+               v = picojson::value(GVS<bool>::value(value));
+       }
+       else if (type == "s")
+       {
+               v = picojson::value(g_variant_get_string(value, nullptr));
+       }
+       else
+       {
+               DebugOut(DebugOut::Error) << "Unsupported type: " << type << endl;
+       }
+
+       return v;
+}
+
+const std::string amb::BasicTypes::fromSignature(const string &sig)
+{
+       if(sig.empty()) return "";
+
+       char c = sig[0];
+
+       if(c == G_VARIANT_CLASS_BOOLEAN)
+               return BooleanStr;
+
+       else if(c == G_VARIANT_CLASS_BYTE)
+               return "";
+
+       else if(c == G_VARIANT_CLASS_INT16)
+               return Int16Str;
+
+       else if(c == G_VARIANT_CLASS_UINT16)
+               return UInt16Str;
+
+       else if(c == G_VARIANT_CLASS_INT32)
+               return Int32Str;
+
+       else if(c ==  G_VARIANT_CLASS_UINT32)
+               return UInt32Str;
+
+       else if(c == G_VARIANT_CLASS_INT64)
+               return "";
+
+       else if(c == G_VARIANT_CLASS_UINT64)
+               return "";
+
+       else if(c == G_VARIANT_CLASS_DOUBLE)
+               return DoubleStr;
+
+       else if(c == G_VARIANT_CLASS_STRING)
+               return StringStr;
+
+       else if(c == G_VARIANT_CLASS_ARRAY)
+       {
+               ///TODO support array and map
+               return "";
+       }
+       return "";
+}
+
+
+
+
+const string amb::BasicTypes::fromAbstractProperty(AbstractPropertyType *property)
+{
+       return fromSignature(property->signature());
+}
+
+
+GVariant *amb::jsonToGVariant(const picojson::value & value, const std::string& type)
+{
+       GVariant* v = nullptr;
+
+       if (type == "i") {
+               v = g_variant_new(type.c_str(), (int32_t)value.get<double>());
+       } else if (type == "d") {
+               v = g_variant_new(type.c_str(), value.get<double>());
+       } else if (type == "q") {
+               v = g_variant_new(type.c_str(), (uint16_t)value.get<double>());
+       } else if (type == "n") {
+               v = g_variant_new(type.c_str(), (int16_t)value.get<double>());
+       } else if (type == "u") {
+               v = g_variant_new(type.c_str(), (uint32_t)value.get<double>());
+       } else if (type == "x") {
+               v = g_variant_new(type.c_str(), (int64_t)value.get<double>());
+       } else if (type == "t") {
+               v = g_variant_new(type.c_str(), (uint64_t)value.get<double>());
+       } else if (type == "b") {
+               v = g_variant_new(type.c_str(), value.get<bool>());
+       } else if (type == "s") {
+               v = g_variant_new(type.c_str(), value.get<std::string>().c_str());
+       } else {
+               DebugOut(DebugOut::Error) << "Unsupported type: " << type << endl;
+       }
+
+       return v;
+}
diff --git a/lib/jsonhelper.h b/lib/jsonhelper.h
new file mode 100644 (file)
index 0000000..70eb286
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef _JSON_HELPER_H_
+#define _JSON_HELPER_H_
+
+#include "picojson.h"
+
+#include <memory>
+
+#include <glib.h>
+
+class AbstractPropertyType;
+
+namespace amb
+{
+namespace BasicTypes
+{
+enum BasicTypeEnum
+{
+       UInt16,
+       UInt32,
+       Int16,
+       Int32,
+       String,
+       Double,
+       Boolean
+};
+
+extern const char * UInt16Str;
+extern const char * UInt32Str;
+extern const char * Int16Str;
+extern const char * Int32Str;
+extern const char * StringStr;
+extern const char * DoubleStr;
+extern const char * BooleanStr;
+
+const std::string fromSignature(std::string const & sig);
+
+const std::string fromAbstractProperty(AbstractPropertyType *property);
+
+} // BasicTypes
+
+picojson::value gvariantToJson(GVariant* value);
+
+GVariant * jsonToGVariant(const picojson::value & json, const std::string & signature);
+
+std::shared_ptr<AbstractPropertyType> jsonToProperty(const picojson::value& json);
+
+picojson::value propertyToJson(std::shared_ptr<AbstractPropertyType> property);
+
+}
+
+#endif
+
index 750f321..25e2039 100644 (file)
@@ -53,4 +53,13 @@ void removeOne(T * iteratable, V value)
        }
 }
 
+namespace amb
+{
+template <class T, class Key>
+bool containsKey(const T & map, const Key & key)
+{
+       return map.find(key) != map.end();
+}
+}
+
 #endif // LISTPLUSPLUS_H
index 6cdcc6e..c9e3d98 100644 (file)
@@ -8,7 +8,7 @@
 #include <debugout.h>
 #include "picojson.h"
 
-template <class N = AbstractPropertyType*>
+template <class N>
 class MapPropertyType: public AbstractPropertyType
 {
 public:
@@ -33,28 +33,6 @@ public:
                return t;
        }
 
-       bool contains(std::string key)
-       {
-               return mMap.find(key) != mMap.end();
-       }
-
-       N operator[](std::string key)
-       {
-               return mMap[key];
-       }
-
-       std::vector<std::string> keys()
-       {
-               std::vector<std::string> list;
-
-               for(auto itr : mMap)
-               {
-                       list.push_back(itr.first);
-               }
-
-               return list;
-       }
-
        std::string toString() const
        {
                std::stringstream str;
index a78df28..c4a25a1 100644 (file)
@@ -345,8 +345,7 @@ VehicleProperty::VehicleProperty()
        REGISTERPROPERTY( VehiclePowerMode, Power::Off);
        registerPropertyPriv(TripMeters, [](){
                TripMetersType* t = new TripMetersType();
-               BasicPropertyType<uint16_t> v(0);
-               t->append(v);
+               t->append(0);
                return t;
        });
 
@@ -388,9 +387,8 @@ VehicleProperty::VehicleProperty()
        REGISTERPROPERTY(Direction, 0);
        REGISTERPROPERTY(VehicleType, Vehicle::Unknown);
        registerPropertyPriv(DoorsPerRow, []() {
-               BasicPropertyType<uint16_t> d(0);
                DoorsPerRowType* doors = new DoorsPerRowType();
-               doors->append(d);
+               doors->append(0);
                return doors;
        });
        REGISTERPROPERTY(TransmissionGearType, Transmission::Unknown);
@@ -505,8 +503,7 @@ VehicleProperty::VehicleProperty()
        REGISTERPROPERTY(ActiveNoiseControlMode, false);
        registerPropertyPriv(AvailableSounds, [](){
                AvailableSoundsType* t = new AvailableSoundsType();
-               StringPropertyType v;
-               t->append(v);
+               t->append("");
                return t;
        });
        REGISTERPROPERTY(EngineSoundEnhancementMode, "");
index ced4a40..f627992 100644 (file)
@@ -616,19 +616,15 @@ public:
         */
        static const Property VehiclePowerMode;
        PROPERTYTYPE(VehiclePowerMode, VehiclePowerModeType, BasicPropertyType<Power::Modes>, Power::Modes)
-       //typedef BasicPropertyType<Power::PowerModes> VehiclePowerModeType;
 
        static const Property TripMeters;
-       PROPERTYTYPE(TripMeters, TripMetersType, ListPropertyType<BasicPropertyType<uint16_t> >, uint16_t)
-       //typedef ListPropertyType<BasicPropertyType<uint16_t> > TripMetersType;
+       PROPERTYTYPE(TripMeters, TripMetersType, ListPropertyType<uint16_t>, uint16_t)
 
        static const Property CruiseControlActive;
        PROPERTYTYPE(CruiseControlActive, CruiseControlActiveType, BasicPropertyType<bool>, bool)
-       //typedef BasicPropertyType<bool> CruiseControlActiveType;
 
        static const Property CruiseControlSpeed;
        PROPERTYTYPE(CruiseControlSpeed, CruiseControlSpeedType, BasicPropertyType<uint16_t>, uint16_t)
-       //typedef BasicPropertyType<uint16_t> CruiseControlSpeedType;
 
        static const Property LightHead;
        PROPERTYTYPE(LightHead, LightHeadType, BasicPropertyType<bool>, bool)
@@ -726,7 +722,7 @@ public:
        PROPERTYTYPE(VehicleType, VehicleTypeType, BasicPropertyType<Vehicle::Type>, Vehicle::Type)
 
        static const Property DoorsPerRow;
-       PROPERTYTYPE(DoorsPerRow, DoorsPerRowType, ListPropertyType<BasicPropertyType<uint16_t> >, uint16_t)
+       PROPERTYTYPE(DoorsPerRow, DoorsPerRowType, ListPropertyType<uint16_t>, uint16_t)
 
        static const Property TransmissionGearType;
        PROPERTYTYPE(TransmissionGearType, TransmissionGearTypeType, BasicPropertyType<Transmission::Type>, Transmission::Type)
@@ -1059,7 +1055,7 @@ public:
        PROPERTYTYPEBASIC(ActiveNoiseControlMode, bool)
 
        static const Property AvailableSounds;
-       PROPERTYTYPE(AvailableSounds, AvailableSoundsType, ListPropertyType<StringPropertyType>, StringPropertyType)
+       PROPERTYTYPE(AvailableSounds, AvailableSoundsType, ListPropertyType<std::string>, std::string)
 
        static const Property EngineSoundEnhancementMode;
        PROPERTYTYPE(EngineSoundEnhancementMode, EngineSoundEnhancementModeType, StringPropertyType, std::string)
index c407834..40f2c90 100644 (file)
@@ -115,15 +115,15 @@ AbstractPropertyType* qVariantToAbstractPropertyType(QString name, QVariant var)
        {
                QVariant subVariant = var.toList().at(0);
                if(subVariant.type() == QVariant::UInt)
-                       return new ListPropertyType<BasicPropertyType<uint>>(name.toStdString(), subVariant.toUInt());
+                       return new ListPropertyType<uint>(name.toStdString(), subVariant.toUInt());
                else if(subVariant.type() == QVariant::Double)
-                       return new ListPropertyType<BasicPropertyType<double>>(name.toStdString(), subVariant.toDouble());
+                       return new ListPropertyType<double>(name.toStdString(), subVariant.toDouble());
                else if(subVariant.type() == QVariant::Bool)
-                       return new ListPropertyType<BasicPropertyType<bool>>(name.toStdString(), subVariant.toBool());
+                       return new ListPropertyType<bool>(name.toStdString(), subVariant.toBool());
                else if(subVariant.type() == QVariant::Int)
-                       return new ListPropertyType<BasicPropertyType<int>>(name.toStdString(), subVariant.toInt());
+                       return new ListPropertyType<int>(name.toStdString(), subVariant.toInt());
                else if(subVariant.type() == QVariant::String)
-                       return new ListPropertyType<StringPropertyType>(name.toStdString(), subVariant.toString().toStdString());
+                       return new ListPropertyType<std::string>(name.toStdString(), subVariant.toString().toStdString());
        }
        return nullptr;
 }
index 84e79c9..5273542 100644 (file)
@@ -1,58 +1,9 @@
 #include "jsonprotocol.h"
 
-#include <glib.h>
-
-const char * amb::BasicTypes::UInt16Str = "UInt16";
-const char * amb::BasicTypes::UInt32Str = "UInt32";
-const char * amb::BasicTypes::Int16Str = "Int16";
-const char * amb::BasicTypes::Int32Str = "Int32";
-const char * amb::BasicTypes::StringStr = "String";
-const char * amb::BasicTypes::DoubleStr = "Double";
-const char * amb::BasicTypes::BooleanStr = "Boolean";
-
-const std::string amb::BasicTypes::fromSignature(const string &sig)
-{
-       if(sig.empty()) return "";
-
-       char c = sig[0];
-
-       if(c == G_VARIANT_CLASS_BOOLEAN)
-               return BooleanStr;
-
-       else if(c == G_VARIANT_CLASS_BYTE)
-               return "";
-
-       else if(c == G_VARIANT_CLASS_INT16)
-               return Int16Str;
-
-       else if(c == G_VARIANT_CLASS_UINT16)
-               return UInt16Str;
-
-       else if(c == G_VARIANT_CLASS_INT32)
-               return Int32Str;
-
-       else if(c ==  G_VARIANT_CLASS_UINT32)
-               return UInt32Str;
-
-       else if(c == G_VARIANT_CLASS_INT64)
-               return "";
-
-       else if(c == G_VARIANT_CLASS_UINT64)
-               return "";
-
-       else if(c == G_VARIANT_CLASS_DOUBLE)
-               return DoubleStr;
+#include <jsonhelper.h>
+#include <listplusplus.h>
 
-       else if(c == G_VARIANT_CLASS_STRING)
-               return StringStr;
-
-       else if(c == G_VARIANT_CLASS_ARRAY)
-       {
-               ///TODO support array and map
-               return "";
-       }
-       return "";
-}
+#include <glib.h>
 
 bool readCallback(GIOChannel *source, GIOCondition condition, gpointer data)
 {
@@ -92,32 +43,45 @@ void amb::AmbRemoteClient::list(amb::AmbRemoteClient::ListCallback cb)
 
 void amb::AmbRemoteClient::get(const string &objectName, amb::AmbRemoteClient::ObjectCallback cb)
 {
-
+       get(objectName, "", Zone::None, cb);
 }
 
 void amb::AmbRemoteClient::get(const string &objectName, const string &sourceUuid, amb::AmbRemoteClient::ObjectCallback cb)
 {
-
+       get(objectName, sourceUuid, Zone::None, cb);
 }
 
 void amb::AmbRemoteClient::get(const string &objectName, Zone::Type zone, amb::AmbRemoteClient::ObjectCallback cb)
 {
-
+       get(objectName, "", zone, cb);
 }
 
 void amb::AmbRemoteClient::get(const string &objectName, const string &sourceUuid, Zone::Type zone, amb::AmbRemoteClient::ObjectCallback cb)
 {
+       GetMethodCall getCall;
+       getCall.sourceUuid = sourceUuid;
+       getCall.zone = zone;
+
+       mGetMethodCalls[getCall.messageId] = cb;
 
+       send(getCall);
 }
 
-void amb::AmbRemoteClient::set(const string &objectName, MapPropertyType<> *value, amb::AmbRemoteClient::ObjectCallback cb)
+void amb::AmbRemoteClient::set(const string &objectName, const Object & value, SetCallback cb)
 {
-
+       set(objectName, value, "", Zone::None, cb);
 }
 
-void amb::AmbRemoteClient::set(const string &objectName, MapPropertyType<> *value, const string &sourceUuid, Zone::Type zone, amb::AmbRemoteClient::ObjectCallback cb)
+void amb::AmbRemoteClient::set(const string &objectName, const Object & value, const string &sourceUuid, Zone::Type zone, SetCallback cb)
 {
+       SetMethodCall setCall;
+       setCall.sourceUuid = sourceUuid;
+       setCall.zone = zone;
+       setCall.value = value;
 
+       mSetMethodCalls[setCall.messageId] = cb;
+
+       send(setCall);
 }
 
 void amb::AmbRemoteClient::listen(const string &objectName, const string &sourceUuid, Zone::Type zone, amb::AmbRemoteClient::ObjectCallback cb)
@@ -132,19 +96,13 @@ void amb::AmbRemoteClient::listen(const string &objectName, amb::AmbRemoteClient
 
 void amb::AmbRemoteClient::hasJsonMessage(const picojson::value &json)
 {
-       BaseMessage message;
-
-       message.fromJson(json);
+       DebugOut(7) << "json: " << json.serialize() << endl;
 
-       if(message.is<MethodCall>())
+       if(BaseMessage::is<MethodCall>(json))
        {
-               MethodCall methodCall(message);
-               methodCall.fromJson(json);
-
-               if(message.is<ListMethodCall>())
+               if(BaseMessage::is<ListMethodCall>(json))
                {
-                       ListMethodCall listMethodCall(methodCall);
-
+                       ListMethodCall listMethodCall;
                        listMethodCall.fromJson(json);
 
                        if(mListCalls.find(listMethodCall.messageId) != mListCalls.end())
@@ -163,6 +121,31 @@ void amb::AmbRemoteClient::hasJsonMessage(const picojson::value &json)
                                mListCalls.erase(listMethodCall.messageId);
                        }
                }
+               else if(BaseMessage::is<GetMethodCall>(json))
+               {
+                       GetMethodCall getCall;
+                       getCall.fromJson(json);
+
+                       if(amb::containsKey(mGetMethodCalls, getCall.messageId))
+                       {
+                               auto cb = mGetMethodCalls[getCall.messageId];
+
+                               try
+                               {
+                                       cb(getCall.value);
+                               }
+                               catch(...)
+                               {
+                                       DebugOut(DebugOut::Warning) << "Invalid Get callback " << endl;
+                               }
+
+                               mGetMethodCalls.erase(getCall.messageId);
+                       }
+               }
+               else if(BaseMessage::is<SetMethodCall>(json))
+               {
+
+               }
        }
 }
 
@@ -198,7 +181,7 @@ bool amb::BaseMessage::fromJson(const picojson::value &json)
        name = obj["name"].to_str();
        messageId = obj["messageId"].to_str();
 
-       if(data.contains("data"))
+       if(json.contains("data"))
        {
                data = json.get("data");
        }
@@ -215,7 +198,7 @@ picojson::value amb::ListMethodCall::toJson()
 
        for(auto i : objectNames)
        {
-               list.push_back(property2Json(i));
+               list.push_back(Object::toJson(i));
        }
 
        v["data"] = picojson::value(list);
@@ -225,17 +208,28 @@ picojson::value amb::ListMethodCall::toJson()
 
 bool amb::ListMethodCall::fromJson(const picojson::value &json)
 {
-       if(!MethodCall::fromJson(json) || json.get("type").to_str() != "list" || !data.is<picojson::array>())
+       if(!MethodCall::fromJson(json) || name != "list" || !data.is<picojson::array>())
        {
-               DebugOut(DebugOut::Error) << "type not 'list' or data not type json array";
+               DebugOut(DebugOut::Error) << "type not 'list' or data not type json array" << endl;
                return false;
        }
 
        objectNames.clear();
 
-       for(auto i : data.get<picojson::array>())
+       picojson::array dataList = json.get("data").get<picojson::array>();
+
+       for(auto i : dataList)
        {
-               objectNames.push_back(json2Property(i));
+               if(!i.is<picojson::object>())
+               {
+                       DebugOut(DebugOut::Warning) << "Malformed data.  Expected 'object'.  Got '" << i.to_str() << "'" << endl;
+                       continue;
+               }
+               picojson::object obj = i.get<picojson::object>();
+
+               Object ambObj = Object::fromJson(obj);
+
+               objectNames.push_back(ambObj);
        }
 
        return true;
@@ -302,19 +296,38 @@ void amb::BaseJsonMessageReader::canHasData()
 }
 
 
+picojson::value amb::MethodCall::toJson()
+{
+       picojson::value value = BaseMessage::toJson();
+
+       picojson::object obj = value.get<picojson::object>();
+
+       obj["source"] = picojson::value(sourceUuid);
+       obj["zone"] = picojson::value((double)zone);
+       obj["methodSuccess"] = picojson::value(success);
+
+       return picojson::value(obj);
+}
+
 bool amb::MethodCall::fromJson(const picojson::value &json)
 {
+       if(!BaseMessage::fromJson(json))
+               return false;
+
+       sourceUuid = json.get("source").to_str();
+       zone = json.get("zone").get<double>();
+
+       if(json.contains("success"))
+               success = json.get("methodSuccess").get<bool>();
 
        return true;
 }
 
 
-std::shared_ptr<AbstractPropertyType> amb::json2Property(const picojson::value &json)
+std::shared_ptr<AbstractPropertyType> amb::jsonToProperty(const picojson::value &json)
 {
-       Zone::Type zone = json.get("zone").get<double>();
-       std::string name = json.get("property").to_str();
+       std::string name = json.get("name").to_str();
        std::string type = json.get("type").to_str();
-       std::string source = json.get("source").to_str();
 
        auto t = VehicleProperty::getPropertyTypeForPropertyNameValue(name);
 
@@ -362,30 +375,14 @@ std::shared_ptr<AbstractPropertyType> amb::json2Property(const picojson::value &
                t = VehicleProperty::getPropertyTypeForPropertyNameValue(name);
        }
 
-       t->sourceUuid = source;
-       t->zone = zone;
+       t->fromJson(json);
 
        return std::shared_ptr<AbstractPropertyType>(t);
 }
 
 
-picojson::value amb::property2Json(std::shared_ptr<AbstractPropertyType> property)
-{
-       std::string signature = property->signature();
-       const std::string basicType = amb::BasicTypes::fromSignature(signature);
-
-       picojson::object map;
-       map["zone"] = picojson::value((double)property->zone);
-       map["property"] = picojson::value(property->name);
-       map["type"] = picojson::value(basicType);
-       map["source"] = picojson::value(property->sourceUuid);
-
-       return picojson::value(map);
-}
-
-
-amb::AmbRemoteServer::AmbRemoteServer(AbstractIo *io)
-       :BaseJsonMessageReader(io)
+amb::AmbRemoteServer::AmbRemoteServer(AbstractIo *io, AbstractRoutingEngine *re)
+       :BaseJsonMessageReader(io), routingEngine(re)
 {
 
 }
@@ -395,7 +392,7 @@ void amb::AmbRemoteServer::list(ListMethodCall &call)
 
 }
 
-void amb::AmbRemoteServer::get()
+void amb::AmbRemoteServer::get(GetMethodCall & get)
 {
 
 }
@@ -412,9 +409,12 @@ void amb::AmbRemoteServer::listen()
 
 void amb::AmbRemoteServer::hasJsonMessage(const picojson::value &json)
 {
+       DebugOut(7) << "json: " << json.serialize() << endl;
+
        if(!BaseMessage::validate(json))
        {
-               DebugOut(DebugOut::Warning) << "not a valid message" << endl;
+               DebugOut(DebugOut::Warning) << "not a valid message: " << json.serialize() << endl;
+               return;
        }
 
        if(BaseMessage::is<MethodCall>(json))
@@ -426,13 +426,81 @@ void amb::AmbRemoteServer::hasJsonMessage(const picojson::value &json)
                        listCall.fromJson(json);
 
                        list(listCall);
+               }
+               else if(BaseMessage::is<GetMethodCall>(json))
+               {
+                       GetMethodCall getCall;
+                       getCall.fromJson(json);
 
-                       send(&listCall);
+                       get(getCall);
                }
        }
 }
 
-void amb::AmbRemoteServer::send(amb::BaseMessage *msg)
+picojson::value amb::GetMethodCall::toJson()
+{
+       picojson::value val = MethodCall::toJson();
+
+       picojson::object obj = val.get<picojson::object>();
+
+       obj["data"] = Object::toJson(value);
+
+       return picojson::value(obj);
+}
+
+bool amb::GetMethodCall::fromJson(const picojson::value &json)
+{
+       MethodCall::fromJson(json);
+
+       value = Object::fromJson(json.get<picojson::object>());
+}
+
+
+amb::Object amb::Object::fromJson(const picojson::object &obj)
+{
+       if(!amb::containsKey(obj, "interfaceName"))
+       {
+               DebugOut(DebugOut::Warning) << "object missing interfaceName" << endl;
+               return Object();
+       }
+       Object ambObj(obj.at("interfaceName").to_str());
+
+       for(auto i : obj)
+       {
+               if(i.second.is<picojson::object>())
+                       ambObj[i.first] = std::shared_ptr<AbstractPropertyType>(amb::jsonToProperty(i.second));
+       }
+
+       return ambObj;
+}
+
+picojson::value amb::Object::toJson(const amb::Object &obj)
+{
+       picojson::object jsonObj;
+       jsonObj["interfaceName"] = picojson::value(obj.interfaceName);
+       for(auto i : obj)
+       {
+               jsonObj[i.second->alias()] = i.second->toJson();
+       }
+
+       return picojson::value(jsonObj);
+}
+
+
+picojson::value amb::SetMethodCall::toJson()
 {
-       mIo->write(msg->toJson().serialize());
+       picojson::value val = MethodCall::toJson();
+
+       picojson::object obj = val.get<picojson::object>();
+
+       obj["data"] = Object::toJson(value);
+
+       return picojson::value(obj);
+}
+
+bool amb::SetMethodCall::fromJson(const picojson::value &json)
+{
+       MethodCall::fromJson(json);
+
+       value = Object::fromJson(json.get<picojson::object>());
 }
index 83b5613..c641a36 100644 (file)
@@ -37,34 +37,23 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 namespace amb
 {
 
-namespace BasicTypes
+class Object : public std::unordered_map<std::string, std::shared_ptr<AbstractPropertyType>>
 {
-enum BasicTypeEnum
-{
-       UInt16,
-       UInt32,
-       Int16,
-       Int32,
-       String,
-       Double,
-       Boolean
-};
+public:
+       Object(): std::unordered_map<std::string, std::shared_ptr<AbstractPropertyType>>() { }
+       Object(const std::string & ifaceName): std::unordered_map<std::string, std::shared_ptr<AbstractPropertyType>>(),
+               interfaceName(ifaceName)
+       {
 
-extern const char * UInt16Str;
-extern const char * UInt32Str;
-extern const char * Int16Str;
-extern const char * Int32Str;
-extern const char * StringStr;
-extern const char * DoubleStr;
-extern const char * BooleanStr;
+       }
 
-const std::string fromSignature(std::string const & sig);
+       static Object fromJson(const picojson::object & obj);
 
-} // BasicTypes
+       static picojson::value toJson(const Object & obj);
 
-std::shared_ptr<AbstractPropertyType> json2Property(const picojson::value& json);
+       std::string interfaceName;
 
-picojson::value property2Json(std::shared_ptr<AbstractPropertyType> property );
+};
 
 class BaseMessage
 {
@@ -99,7 +88,7 @@ public:
 
        static bool validate(const picojson::value & json)
        {
-               return json.is<picojson::object>() && json.contains("type") && !json.contains("name") && json.contains("messageId");
+               return json.is<picojson::object>() && json.contains("type") && json.contains("name") && json.contains("messageId");
        }
 
        template <typename T>
@@ -119,13 +108,13 @@ class MethodCall : public BaseMessage
 {
 public:
        MethodCall(std::string name)
-               :BaseMessage(name, "method"), zone(Zone::None)
+               :BaseMessage(name, "method"), zone(Zone::None), success(false)
        {
 
        }
 
        MethodCall(const BaseMessage & other)
-               :BaseMessage(other), zone(Zone::None)
+               :BaseMessage(other), zone(Zone::None), success(false)
        {
                name = other.name;
        }
@@ -134,6 +123,8 @@ public:
                :MethodCall(other.name)
        {
                sourceUuid = other.sourceUuid;
+               zone = other.zone;
+               success = other.success;
        }
 
        static bool is(const BaseMessage * msg)
@@ -149,13 +140,16 @@ public:
         */
        static bool is(const picojson::value & json)
        {
-               return json.contains("sourceUuid") && json.contains("zone");
+               return json.contains("source") && json.get("source").is<std::string>()
+                               && json.contains("zone") && json.get("zone").is<double>();
        }
 
+       virtual picojson::value toJson();
        virtual bool fromJson(const picojson::value &json);
 
        std::string sourceUuid;
        Zone::Type zone;
+       bool success;
 };
 
 class ListMethodCall : public MethodCall
@@ -172,7 +166,7 @@ public:
        picojson::value toJson();
        bool fromJson(const picojson::value &json);
 
-       std::vector<std::shared_ptr<AbstractPropertyType>> objectNames;
+       std::vector<Object> objectNames;
 
        static bool is(const BaseMessage * msg)
        {
@@ -181,8 +175,58 @@ public:
 
        static bool is(const picojson::value & json)
        {
-               return json.get("type").to_str() != "list" && json.is<picojson::array>();
+               return json.get("name").to_str() == "list";
+       }
+};
+
+class GetMethodCall : public MethodCall
+{
+public:
+       GetMethodCall()
+               : MethodCall("get")
+       {
+
+       }
+
+       picojson::value toJson();
+       bool fromJson(const picojson::value &json);
+
+       static bool is(const BaseMessage * msg)
+       {
+               return msg->name == "get";
+       }
+
+       static bool is(const picojson::value & json)
+       {
+               return json.get("name").to_str() == "get";
        }
+
+       Object value;
+};
+
+class SetMethodCall : public MethodCall
+{
+public:
+       SetMethodCall()
+               : MethodCall("set")
+       {
+
+       }
+
+       picojson::value toJson();
+       bool fromJson(const picojson::value &json);
+
+       static bool is(const BaseMessage * msg)
+       {
+               return msg->name == "set";
+       }
+
+       static bool is(const picojson::value & json)
+       {
+               return json.get("name").to_str() != "set";
+       }
+
+       Object value;
 };
 
 class BaseJsonMessageReader
@@ -196,6 +240,12 @@ protected:
 
        virtual void hasJsonMessage(const picojson::value & message) = 0;
 
+       template <class T>
+       void send(T & msg)
+       {
+               mIo->write(msg.toJson().serialize());
+       }
+
        std::shared_ptr<AbstractIo> mIo;
 
 private:
@@ -207,8 +257,8 @@ private:
 class AmbRemoteClient: public BaseJsonMessageReader
 {
 public:
-       typedef std::function<void (std::vector<std::shared_ptr<AbstractPropertyType>>)> ListCallback;
-       typedef std::function<void (MapPropertyType<> *)> ObjectCallback;
+       typedef std::function<void (std::vector<Object>)> ListCallback;
+       typedef std::function<void (Object)> ObjectCallback;
        typedef std::function<void (bool)> SetCallback;
 
        AmbRemoteClient(AbstractIo* io);
@@ -223,9 +273,9 @@ public:
 
        void get(const std::string & objectName, const std::string & sourceUuid, Zone::Type zone, ObjectCallback cb);
 
-       void set(const std::string & objectName, MapPropertyType<>* value, ObjectCallback cb);
+       void set(const std::string & objectName, const Object & value, SetCallback cb);
 
-       void set(const std::string & objectName, MapPropertyType<>* value, const std::string & sourceUuid, Zone::Type zone, ObjectCallback cb);
+       void set(const std::string & objectName, const Object & value, const std::string & sourceUuid, Zone::Type zone, SetCallback cb);
 
        void listen(const std::string & objectName, const std::string & sourceUuid, Zone::Type zone, ObjectCallback cb);
 
@@ -239,14 +289,15 @@ private:
 
        std::string createSubscriptionId(const std::string & objectName,  const std::string & sourceUuid, Zone::Type zone);
        std::unordered_map<std::string, ListCallback> mListCalls;
-       std::unordered_map<std::string, AsyncPropertyReply*> mMethodCalls;
+       std::unordered_map<std::string, ObjectCallback> mGetMethodCalls;
+       std::unordered_map<std::string, SetCallback> mSetMethodCalls;
        std::unordered_map<std::string, std::vector<ObjectCallback>> mSubsriptions;
 };
 
 class AmbRemoteServer : public BaseJsonMessageReader
 {
 public:
-       AmbRemoteServer(AbstractIo* io);
+       AmbRemoteServer(AbstractIo* io, AbstractRoutingEngine* routingEngine);
 
 protected:
 
@@ -258,7 +309,7 @@ protected:
        /*!
         * \brief get called when a GetMessageCall was received
         */
-       virtual void get();
+       virtual void get(GetMethodCall &get);
 
        /*!
         * \brief set called when SetMessageCall was received
@@ -271,7 +322,10 @@ protected:
 
        void hasJsonMessage(const picojson::value & json);
 
-       void send(BaseMessage* msg);
+protected:
+       AbstractRoutingEngine* routingEngine;
+
+
 };
 
 } //namespace amb
index 4b643c6..6ea63cd 100644 (file)
@@ -196,13 +196,9 @@ void ExampleSourcePlugin::getPropertyAsync(AsyncPropertyReply *reply)
        {
                VehicleProperty::DoorsPerRowType temp;
 
-               BasicPropertyType<uint16_t> row1(2);
-               BasicPropertyType<uint16_t> row2(2);
-               BasicPropertyType<uint16_t> row3(1);
-
-               temp.append(row1);
-               temp.append(row2);
-               temp.append(row3);
+               temp.append(2);
+               temp.append(2);
+               temp.append(1);
 
                reply->value = &temp;
                reply->success = true;
index 9b76732..a1120bc 100644 (file)
@@ -343,12 +343,9 @@ TestPlugin::TestPlugin(AbstractRoutingEngine *re, map<string, string> config)
        DebugOut() << "Testing ListPropertyType... " << endl;
        VehicleProperty::TripMetersType* tfirst = new VehicleProperty::TripMetersType();
        VehicleProperty::TripMetersType* tsecond = new VehicleProperty::TripMetersType();
-       BasicPropertyType<uint16_t> v1(0);
-       BasicPropertyType<uint16_t> v2(5);
-       BasicPropertyType<uint16_t> v3(10);
-       tfirst->append(v1);
-       tfirst->append(v2);
-       tfirst->append(v3);
+       tfirst->append(0);
+       tfirst->append(5);
+       tfirst->append(10);
        tsecond->fromVariant(tfirst->toVariant());
 
        GVariant* testGVSVariant = g_variant_new("i", 9);
index 1b91efa..a678196 100644 (file)
@@ -18,10 +18,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
 
 
-#ifndef OBD2SOURCE_H
-#define OBD2SOURCE_H
-
-
+#ifndef TESTSOURCE_H
+#define TESTSOURCE_H
 
 #include <abstractsource.h>
 #include <string>
@@ -32,9 +30,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 #include <termios.h>
 #include <glib.h>
 
-
-
-
 class TestPlugin : public AbstractSource
 {
 
index 5088620..e4e49d0 100644 (file)
@@ -7,14 +7,6 @@
 
 bool doBinary = false;
 
-const char * amb::BasicTypes::UInt16Str = "UInt16";
-const char * amb::BasicTypes::UInt32Str = "UInt32";
-const char * amb::BasicTypes::Int16Str = "Int16";
-const char * amb::BasicTypes::Int32Str = "Int32";
-const char * amb::BasicTypes::StringStr = "String";
-const char * amb::BasicTypes::DoubleStr = "Double";
-const char * amb::BasicTypes::BooleanStr = "Boolean";
-
 int lwsWrite(libwebsocket *lws, QByteArray d)
 {
        if(!lws)
@@ -91,46 +83,3 @@ void cleanJson(QByteArray &json)
        json.replace("\t", "");
 }
 
-const std::string amb::BasicTypes::fromSignature(const string &sig)
-{
-       if(sig.empty()) return "";
-
-       char c = sig[0];
-
-       if(c == G_VARIANT_CLASS_BOOLEAN)
-               return BooleanStr;
-
-       else if(c == G_VARIANT_CLASS_BYTE)
-               return "";
-
-       else if(c == G_VARIANT_CLASS_INT16)
-               return Int16Str;
-
-       else if(c == G_VARIANT_CLASS_UINT16)
-               return UInt16Str;
-
-       else if(c == G_VARIANT_CLASS_INT32)
-               return Int32Str;
-
-       else if(c ==  G_VARIANT_CLASS_UINT32)
-               return UInt32Str;
-
-       else if(c == G_VARIANT_CLASS_INT64)
-               return "";
-
-       else if(c == G_VARIANT_CLASS_UINT64)
-               return "";
-
-       else if(c == G_VARIANT_CLASS_DOUBLE)
-               return DoubleStr;
-
-       else if(c == G_VARIANT_CLASS_STRING)
-               return StringStr;
-
-       else if(c == G_VARIANT_CLASS_ARRAY)
-       {
-               ///TODO support array and map
-               return "";
-       }
-       return "";
-}
index b246e1b..b4af8f3 100644 (file)
@@ -13,32 +13,4 @@ void cleanJson(QByteArray &json);
 int lwsWrite(struct libwebsocket *lws, QByteArray d);
 int lwsWriteVariant(struct libwebsocket *lws, QVariant d);
 
-namespace amb
-{
-namespace BasicTypes
-{
-enum BasicTypeEnum
-{
-       UInt16,
-       UInt32,
-       Int16,
-       Int32,
-       String,
-       Double,
-       Boolean
-};
-
-extern const char * UInt16Str;
-extern const char * UInt32Str;
-extern const char * Int16Str;
-extern const char * Int32Str;
-extern const char * StringStr;
-extern const char * DoubleStr;
-extern const char * BooleanStr;
-
-const std::string fromSignature(std::string const & sig);
-
-} // BasicTypes
-} // amb
-
 #endif
index ab924e2..cea4807 100644 (file)
@@ -11,3 +11,20 @@ configure_file (${CMAKE_CURRENT_SOURCE_DIR}/gendb.sh ${CMAKE_CURRENT_SOURCE_DIR}
 
 install (PROGRAMS ${amb_tests} DESTINATION bin)
 
+find_package(Qt5Network)
+find_package(Qt5Core)
+
+if(Qt5Network_FOUND)
+  set(QT_INCLUDE_DIRS ${Qt5Core_INCLUDE_DIRS} ${Qt5Network_INCLUDE_DIRS})
+  set(QT_LIBRARIES ${Qt5Core_LIBRARIES} ${Qt5Network_LIBRARIES})
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Core_EXECUTABLE_COMPILE_FLAGS}")
+  add_definitions(${Qt5Core_DEFINITIONS})
+
+  include_directories(${CMAKE_SOURCE_DIR}/lib ${include_dirs} ${QT_INCLUDE_DIRS} ${CMAKE_SOURCE_DIR}/plugins/common)
+
+  add_executable(testProtocol testProtocol.cpp testProtocolCommon.h)
+  target_link_libraries(testProtocol ${link_libraries} amb -L${CMAKE_CURRENT_BINARY_DIR}/lib amb-plugins-common amb-json-protocol -L${CMAKE_CURRENT_BINARY_DIR}/plugins/common ${QT_LIBRARIES})
+
+  add_executable(testProtocolClient testProtocolClient.cpp testProtocolCommon.h)
+  target_link_libraries(testProtocolClient ${link_libraries} amb -L${CMAKE_CURRENT_BINARY_DIR}/lib amb-plugins-common amb-json-protocol -L${CMAKE_CURRENT_BINARY_DIR}/plugins/common ${QT_LIBRARIES})
+endif()
diff --git a/tests/testProtocol.cpp b/tests/testProtocol.cpp
new file mode 100644 (file)
index 0000000..c29c566
--- /dev/null
@@ -0,0 +1,71 @@
+#include "testProtocolCommon.h"
+
+#include <debugout.h>
+#include <jsonprotocol.h>
+
+#include <QLocalSocket>
+#include <QLocalServer>
+#include <QCoreApplication>
+#include <QObject>
+
+#include <memory>
+
+class Server : public amb::AmbRemoteServer
+{
+public:
+       Server(QLocalSocket* socketConnection): amb::AmbRemoteServer(new DomainSocket(socketConnection), nullptr) {}
+
+
+       // AmbRemoteServer interface
+protected:
+       void list(amb::ListMethodCall &call)
+       {
+               DebugOut(0) << "list called" << endl;
+
+               amb::Object interface1("interface1");
+               amb::Object interface2("interface2");
+
+               interface1.emplace("vehicleSpeed", std::shared_ptr<AbstractPropertyType>(new VehicleProperty::VehicleSpeedType(100)));
+
+               call.objectNames.push_back(interface1);
+               call.objectNames.push_back(interface2);
+               call.success = true;
+
+               send(call);
+       }
+       void get(amb::GetMethodCall &get)
+       {
+               DebugOut(0) << "get called" << endl;
+       }
+};
+
+int main(int argc, char** argv)
+{
+       DebugOut::setDebugThreshhold(7);
+       DebugOut::setThrowErr(true);
+       DebugOut::setThrowWarn(true);
+
+       DebugOut(0) << "Testing AMB json server/client" << endl;
+
+       QCoreApplication app(argc, argv);
+
+       QLocalServer server;
+
+       QLocalServer::removeServer("/tmp/amb");
+
+       if(!server.listen("/tmp/amb"))
+       {
+               DebugOut(DebugOut::Error) << server.errorString().toStdString() << endl;
+       }
+
+
+       DebugOut(0) << "parent waiting for new connection..." << endl;
+       server.waitForNewConnection(-1);
+       QLocalSocket *clientSocket = server.nextPendingConnection();
+
+       g_assert(clientSocket);
+
+       Server *s = new Server(clientSocket);
+
+       app.exec();
+}
diff --git a/tests/testProtocolClient.cpp b/tests/testProtocolClient.cpp
new file mode 100644 (file)
index 0000000..07a728d
--- /dev/null
@@ -0,0 +1,46 @@
+#include "testProtocolCommon.h"
+
+#include <debugout.h>
+#include <jsonprotocol.h>
+
+#include <QLocalSocket>
+#include <QLocalServer>
+#include <QCoreApplication>
+#include <QObject>
+
+#include <memory>
+
+void runTest(amb::AmbRemoteClient *c)
+{
+       DebugOut(0) << "calling client->list()" << endl;
+       c->list([](std::vector<amb::Object> supported)
+       {
+               DebugOut(0) << "list call reply" << endl;
+               g_assert(supported.size() == 2);
+       });
+}
+
+int main(int argc, char** argv)
+{
+       DebugOut::setDebugThreshhold(7);
+       DebugOut::setThrowErr(true);
+       DebugOut::setThrowWarn(false);
+
+       DebugOut(0) << "Testing AMB json server/client" << endl;
+
+       QCoreApplication app(argc, argv);
+
+       DomainSocket socket;
+
+       socket.open();
+
+       socket.getSocket()->waitForConnected();
+
+       DebugOut(0) << "We are connected!" << endl;
+
+       amb::AmbRemoteClient client(&socket);
+
+       runTest(&client);
+
+       app.exec();
+}
diff --git a/tests/testProtocolCommon.h b/tests/testProtocolCommon.h
new file mode 100644 (file)
index 0000000..7e8feef
--- /dev/null
@@ -0,0 +1,63 @@
+#ifndef TESTS_PROTOCOL_COMMON_H_
+#define TESTS_PROTOCOL_COMMON_H_
+
+#include <jsonprotocol.h>
+#include <abstractio.hpp>
+#include <QLocalSocket>
+
+class DomainSocket : public AbstractIo
+{
+public:
+
+       DomainSocket() { }
+       DomainSocket(QLocalSocket* sock): socket(sock) { }
+       // AbstractIo interface
+public:
+       bool open()
+       {
+               if(!socket)
+                       socket = std::shared_ptr<QLocalSocket>(new QLocalSocket());
+
+               socket->connectToServer("/tmp/amb");
+
+               return socket->errorString().isEmpty();
+       }
+       bool close()
+       {
+               if(socket)
+                       socket->close();
+
+               return true;
+       }
+       bool isOpen()
+       {
+               return socket && socket->state() == QLocalSocket::ConnectedState;
+       }
+
+       string read()
+       {
+               return socket->readAll().data();
+       }
+
+       void write(string data)
+       {
+               socket->write(data.c_str(), data.length());
+       }
+
+       int fileDescriptor()
+       {
+               return socket->socketDescriptor();
+       }
+
+       std::string errorString()
+       {
+               return socket->errorString().toStdString();
+       }
+
+       QLocalSocket *getSocket() { return socket.get(); }
+
+private:
+       std::shared_ptr<QLocalSocket> socket;
+};
+
+#endif