Implemented JSON Serialization using Cereal Library
authorErich Keane <erich.keane@intel.com>
Wed, 22 Oct 2014 20:31:13 +0000 (13:31 -0700)
committerErich Keane <erich.keane@intel.com>
Mon, 1 Dec 2014 23:08:03 +0000 (15:08 -0800)
Previously we were hand-mangling strings for JSON serialization and using
boost::property_tree for parsing.  Now we are using an open source library (cereal)
to do both sides in the C++ stack

Change-Id: I2db2657552a31cdf37c2f2dbbcfdb34e48549f00
Signed-off-by: Erich Keane <erich.keane@intel.com>
36 files changed:
.gitignore
resource/examples/fridgeserver.cpp
resource/examples/garageserver.cpp
resource/examples/makefile
resource/examples/ocicuc/Makefile
resource/examples/ocicuc/client.cpp
resource/examples/ocicuc/demo_client.hpp
resource/examples/ocicuc/server.cpp
resource/examples/ocicuc/utility.hpp
resource/examples/roomserver.cpp
resource/examples/simpleclient.cpp
resource/include/AttributeValue.h [new file with mode: 0644]
resource/include/IClientWrapper.h
resource/include/IServerWrapper.h
resource/include/InProcClientWrapper.h
resource/include/InProcServerWrapper.h
resource/include/OCApi.h
resource/include/OCRepresentation.h
resource/include/OCResource.h
resource/include/OCResourceRequest.h
resource/include/OCResourceResponse.h
resource/include/OCSerialization.h [new file with mode: 0644]
resource/include/OicJsonSerializer.hpp [new file with mode: 0644]
resource/include/OutOfProcClientWrapper.h
resource/include/OutOfProcServerWrapper.h
resource/include/ResourceInitException.h
resource/include/StringConstants.h
resource/include/WrapperFactory.h
resource/makefile
resource/patches/cereal_gcc46.patch [new file with mode: 0644]
resource/src/InProcClientWrapper.cpp
resource/src/InProcServerWrapper.cpp
resource/src/OCPlatform_impl.cpp
resource/src/OCRepresentation.cpp [new file with mode: 0644]
resource/src/OCResource.cpp
resource/unittests/makefile

index 7583ff5..c8d1cf5 100644 (file)
@@ -20,3 +20,6 @@ csdk/stack/samples/linux/SimpleClientServer/debug/
 *.settings/
 *.cproject
 *.project
+
+# Ignore dependencies folder, which should be generated
+/dependencies
index 3700e30..f27f8a5 100644 (file)
@@ -18,7 +18,7 @@
 //
 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 
-/// The purpose of this server is to simulate a refridgerator that contains a device resource for
+/// The purpose of this server is to simulate a refrigerator that contains a device resource for
 /// its description, a light resource for the internal light, and 2 door resources for the purpose
 /// of representing the doors attached to this fridge.  This is used by the fridgeclient to
 /// demonstrate using std::bind to attach to instances of a class as well as using
@@ -88,7 +88,7 @@ class DeviceResource : public Resource
     private:
     OCRepresentation get()
     {
-        m_rep.setValue("device_name", std::string("Intel Powered 2 door, 1 light refridgerator"));
+        m_rep.setValue("device_name", std::string("Intel Powered 2 door, 1 light refrigerator"));
         return m_rep;
     }
 
index e033504..069b362 100644 (file)
@@ -104,7 +104,7 @@ public:
         // setting json string
         std::string json = "{\"num\":10,\"rno\":23.5,\"aoa\":[[1,2],[3]],\"str\":\"john\",\
 \"object\":{\"bl1\":false,\"ar\":[2,3]}, \"objects\":[{\"bl2\":true,\"nl\":null},{\"ar1\":[1,2]}]}";
-        m_garageRep.setValue("json", escapeString(json));
+        m_garageRep.setValue("json", json);
     }
 
     /* Note that this does not need to be a member function: for classes you do not have
index c97f2aa..dcae88e 100644 (file)
@@ -26,6 +26,9 @@ CXX         := g++
 #CXX     := clang
 OUT_DIR          := $(BUILD)
 
+DEPEND_DIR:= ../dependencies
+CEREAL_DIR:= $(DEPEND_DIR)/cereal
+
 CXX_FLAGS.debug     := -O0 -g3 -std=c++0x -Wall -pthread
 
 CXX_FLAGS.release   := -O3 -std=c++0x -Wall -pthread
@@ -37,6 +40,7 @@ CXX_INC         += -I../csdk/ocsocket/include
 CXX_INC          += -I../csdk/ocrandom/include
 CXX_INC          += -I../csdk/logger/include
 CXX_INC          += -I../csdk/libcoap
+CXX_INC   += -I$(CEREAL_DIR)/include
 
 LIB_OC_LOGGER := ../oc_logger/lib/oc_logger.a
 
index 0acf542..9b69e61 100644 (file)
@@ -41,7 +41,8 @@ CXX_INC=-I$(OCLIB)/include \
        -I../../csdk/stack/include \
        -I../../csdk/ocsocket/include \
        -I../../csdk/ocrandom/include \
-       -I../../csdk/logger/include
+       -I../../csdk/logger/include \
+       -I../../dependencies/cereal/include
 
 BOOST_LIBS=-lboost_program_options
 #BOOST_LIBS=-L/usr/local/boost/lib/ -lboost_program_options    # for boost libraries at the specified path
index d2edcfc..c3771bb 100644 (file)
 //
 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 
+// This contains the Boost MPL defines required for the boost_variant
+// serialization, so it must go before the boost/program_options
+#include "OCApi.h"
+
 #include <map>
 #include <string>
 #include <memory>
@@ -28,7 +32,6 @@
 
 #include <boost/program_options.hpp>
 
-#include "OCApi.h"
 #include "OCResource.h"
 #include "OCPlatform.h"
 
index 47830b0..d5ce578 100644 (file)
@@ -143,20 +143,23 @@ void resource_handle::onResourceGet(const OC::HeaderOptions& headerOptions,
         return;
   }
 
- std::cout << "input attributes:\n" << rep.getAttributeMap() << '\n';
+ std::cout << "input attributes:\n";
+ std::cout << "Attribute \"" << "state" << "\": "<< rep.getValue<bool>("state")<<"; ";
+ std::cout << "Attribute \"" << "power" << "\": "<< rep.getValue<int>("power")<<"; \n";
 
  // Now, make a change to the light representation (replacing, rather than parsing):
- OC::AttributeMap attrs {
-                         { "state", { "true" } },
-                         { "power", { "10" } }
-                        };
+ bool state = true;
+ int power = 10;
 
- std::cout << "output attributes:\n" << attrs << '\n';
+ std::cout << "output attributes:\n";
+ std::cout << "Attribute \"" << "state" << "\": "<< state<<"; ";
+ std::cout << "Attribute \"" << "power" << "\": "<< power<<"; \n";
 
  call_timer.mark("put_resource");
 
  OC::OCRepresentation out_rep;
- out_rep.setAttributeMap(attrs);
+ out_rep.setValue("state", state);
+ out_rep.setValue("power", power);
 
  resource->put(out_rep, OC::QueryParamsMap(),
                std::bind(&resource_handle::onResourcePut, this, std::placeholders::_1,
@@ -179,7 +182,9 @@ void resource_handle::onResourcePut(const OC::HeaderOptions& headerOptions,
         throw OC::OCException(os.str());
   }
 
- std::cout << "input attributes:\n" << rep.getAttributeMap() << '\n';
+ std::cout << "input attributes:\n";
+ std::cout << "Attribute \"" << "state" << "\": "<< rep.getValue<bool>("state")<<"; ";
+ std::cout << "Attribute \"" << "power" << "\": "<< rep.getValue<int>("power")<<"; \n";
 
  call_timer.mark("observe_resource");
 
@@ -204,7 +209,8 @@ void resource_handle::onObserve(const OC::HeaderOptions& headerOptions,
 
  call_timer.report_and_reset("observe_resource");
 
- std::cout << rep.getAttributeMap() << '\n';
+ std::cout << "Attribute \"" << "state" << "\": "<< rep.getValue<bool>("state")<<"; ";
+ std::cout << "Attribute \"" << "power" << "\": "<< rep.getValue<int>("power")<<"; \n";
 
  const auto oc = observe_count();
 
index 47b909c..65fca0e 100644 (file)
@@ -18,9 +18,9 @@
 //
 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 
-#include "exec.hpp"
 #include "utility.hpp"
 
+#include "exec.hpp"
 #include "light_resource.hpp"
 
 namespace Intel { namespace OCDemo {
index 6b92fd9..bc734d7 100644 (file)
 
 namespace Intel { namespace OCDemo {
 
-// Prettyprinter for AttributeMaps:
-inline std::ostream& operator<<(std::ostream& os, const OC::AttributeMap& attrs)
-{
- for(const auto& attr : attrs)
-  os << "Attribute \"" << attr.first << "\": " << attr.second << "; ";
-
- return os;
-}
-
 /* A static observation counter: */
 int observe_count();
 
 /* Helpers for measuring request times: */
-typedef std::pair< 
-                    std::chrono::time_point<std::chrono::high_resolution_clock>, 
-                    std::chrono::time_point<std::chrono::high_resolution_clock> 
+typedef std::pair<
+                    std::chrono::time_point<std::chrono::high_resolution_clock>,
+                    std::chrono::time_point<std::chrono::high_resolution_clock>
                  > clock_interval;
 
 struct call_times
@@ -64,7 +55,7 @@ struct call_times
  call_times(const bool& display_reports_)
   : display_reports(display_reports_)
  {}
+
  public:
  void reset(const std::string& entry);
  void mark(const std::string& name);
@@ -73,8 +64,8 @@ struct call_times
  void report_and_reset(const std::string& name);
 };
 
-extern call_times call_timer; 
+extern call_times call_timer;
+
 }} // namespace Intel::OCDemo
 
 #endif
index f9d3978..029ab3f 100644 (file)
@@ -221,16 +221,10 @@ public:
 
     OCRepresentation getRoomRepresentation(void)
     {
-        std::vector<OCRepresentation> children;
-
-        OCRepresentation light = getLightRepresentation();
-        children.push_back(light);
-
-        OCRepresentation fan = getFanRepresentation();
-        children.push_back(fan);
-
-        m_roomRep.setChildren(children);
+        m_roomRep.clearChildren();
 
+        m_roomRep.addChild(getLightRepresentation());
+        m_roomRep.addChild(getFanRepresentation());
         return m_roomRep;
     }
 
index 400591a..c2d4a48 100644 (file)
@@ -365,6 +365,8 @@ int main(int argc, char* argv[]) {
     OCPlatform::Configure(cfg);
     try
     {
+        // makes it so that all boolean values are printed as 'true/false' in this stream
+        std::cout.setf(std::ios::boolalpha);
         // Find all resources
         OCPlatform::findResource("", "coap://224.0.1.187/oc/core?rt=core.light", &foundResource);
         std::cout<< "Finding Resource... " <<std::endl;
diff --git a/resource/include/AttributeValue.h b/resource/include/AttributeValue.h
new file mode 100644 (file)
index 0000000..5a3264a
--- /dev/null
@@ -0,0 +1,83 @@
+
+//******************************************************************
+//
+// Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+/// @file AttributeValue.h
+
+/// @brief  This file contains the definition of the internally used
+// type AttributeValue
+
+#ifndef __ATTRIBUTEVALUE_H
+#define __ATTRIBUTEVALUE_H
+
+// These defines are required to get the boost::variant to hold more than 20 items.
+// documentation requires that you use a power of 10
+#define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS
+#define BOOST_MPL_LIMIT_LIST_SIZE 30
+#define BOOST_MPL_LIMIT_VECTOR_SIZE 30
+#include <boost/variant.hpp>
+#include <cereal/external/rapidjson/document.h>
+
+namespace OC
+{
+    class OCRepresentation;
+
+    struct NullType{};
+    // Since null needs to be encoded in a special fashion in JSON, the encoder
+    // needs to know the index of the NullType Sentinel  Any time the code does a special
+    // case for the NullType, we use the AttributeValueNullIndex.  This MUST be kept up to date
+    // with the variant's which() for NullType.
+    static const int AttributeValueNullIndex = 0;
+    typedef boost::variant<
+
+        // Base values:
+        NullType, // Note: this handles the null-type and must match the above static const
+        int,
+        double,
+        bool,
+        std::string,
+        OC::OCRepresentation,
+
+        // Sequences:
+        std::vector<int>,
+        std::vector<double>,
+        std::vector<bool>,
+        std::vector<std::string>,
+        std::vector<OC::OCRepresentation>,
+
+        // Nested sequences:
+        std::vector<std::vector<int>>,
+        std::vector<std::vector<std::vector<int>>>,
+
+        std::vector<std::vector<double>>,
+        std::vector<std::vector<std::vector<double>>>,
+
+        std::vector<std::vector<bool>>,
+        std::vector<std::vector<std::vector<bool>>>,
+
+        std::vector<std::vector<std::string>>,
+        std::vector<std::vector<std::vector<std::string>>>,
+
+        std::vector<std::vector<OC::OCRepresentation>>,
+        std::vector<std::vector<std::vector<OC::OCRepresentation>>>
+    > AttributeValue;
+
+}
+#endif // __ATTRIBUTEVALUE_H
index a03ae76..8ec23a5 100644 (file)
@@ -33,13 +33,11 @@ namespace OC
     class IClientWrapper : public std::enable_shared_from_this<IClientWrapper>
     {
     protected:
-        OCPlatform_impl& m_owner;
 
     public:
         typedef std::shared_ptr<IClientWrapper> Ptr;
 
-        IClientWrapper(OCPlatform_impl& owner)
-         : m_owner(owner)
+        IClientWrapper()
         {}
 
         virtual OCStackResult ListenForResource(const std::string& serviceUrl,
@@ -81,13 +79,6 @@ namespace OC
         virtual OCStackResult GetDefaultQos(QualityOfService& qos) = 0;
 
         virtual ~IClientWrapper(){}
-
-
-        // Note: this should never be called by anyone but the handler for the listen command.
-        // It is public becuase that needs to be a non-instance callback
-        virtual std::shared_ptr<OCResource> parseOCResource(IClientWrapper::Ptr clientWrapper,
-                        OCDevAddr& addr, const boost::property_tree::ptree resourceNode)=0;
-    private:
     };
 }
 
index 1796b02..a6a2d10 100644 (file)
@@ -34,13 +34,11 @@ namespace OC
     class IServerWrapper
     {
     protected:
-        OCPlatform_impl& m_owner;
 
     public:
         typedef std::shared_ptr<IServerWrapper> Ptr;
 
-        IServerWrapper(OCPlatform_impl& owner)
-         : m_owner(owner)
+        IServerWrapper()
         {}
 
         virtual ~IServerWrapper(){};
index 5fecf6d..39e1df4 100644 (file)
@@ -26,9 +26,6 @@
 #include <sstream>
 #include <iostream>
 
-#include <boost/property_tree/ptree.hpp>
-#include <boost/property_tree/json_parser.hpp>
-
 #include <OCApi.h>
 #include <ocstack.h>
 #include <IClientWrapper.h>
 
 namespace OC
 {
-    class InProcClientWrapper : public IClientWrapper
+    namespace ClientCallbackContext
     {
+        struct GetContext
+        {
+            GetCallback callback;
+        };
 
-    public:
-        enum OCSecureType
+        struct SetContext
+        {
+            PutCallback callback;
+        };
+
+        struct ListenContext
+        {
+            FindCallback callback;
+            IClientWrapper::Ptr clientWrapper;
+        };
+
+        struct SubscribePresenceContext
         {
-            IPV4Secure,
-            IPV4
+            SubscribeCallback callback;
         };
 
-        InProcClientWrapper(OC::OCPlatform_impl& owner, std::weak_ptr<std::recursive_mutex> csdkLock,
+        struct DeleteContext
+        {
+            DeleteCallback callback;
+        };
+
+        struct ObserveContext
+        {
+            ObserveCallback callback;
+        };
+    }
+
+    class InProcClientWrapper : public IClientWrapper
+    {
+
+    public:
+
+        InProcClientWrapper(std::weak_ptr<std::recursive_mutex> csdkLock,
                             PlatformConfig cfg);
         virtual ~InProcClientWrapper();
 
@@ -84,15 +110,8 @@ namespace OC
             const std::string& resourceType, SubscribeCallback& presenceHandler);
 
         virtual OCStackResult UnsubscribePresence(OCDoHandle handle);
-        // Note: this should never be called by anyone but the handler for the listen command.
-        // It is public becuase that needs to be a non-instance callback
-        virtual std::shared_ptr<OCResource> parseOCResource(IClientWrapper::Ptr clientWrapper,
-            OCDevAddr& addr, const boost::property_tree::ptree resourceNode);
-
         OCStackResult GetDefaultQos(QualityOfService& QoS);
     private:
-        std::string convertOCAddrToString(OCDevAddr& addr,
-        OCSecureType type, const std::string &portStr = std::string());
         void listeningFunc();
         std::string assembleSetResourceUri(std::string uri, const QueryParamsMap& queryParams);
         std::string assembleSetResourcePayload(const OCRepresentation& attributes);
@@ -103,7 +122,6 @@ namespace OC
         std::weak_ptr<std::recursive_mutex> m_csdkLock;
 
     private:
-        OC::OCPlatform_impl& m_owner;
         PlatformConfig  m_cfg;
     };
 }
index c74f838..dfed790 100644 (file)
@@ -32,7 +32,7 @@ namespace OC
     class InProcServerWrapper : public IServerWrapper
     {
     public:
-        InProcServerWrapper(OC::OCPlatform_impl& owner, std::weak_ptr<std::recursive_mutex> csdkLock,
+        InProcServerWrapper(std::weak_ptr<std::recursive_mutex> csdkLock,
             PlatformConfig cfg);
         virtual ~InProcServerWrapper();
 
index ec49526..94f997f 100644 (file)
 #include <memory>
 #include <iterator>
 
-#include <boost/property_tree/ptree.hpp>
-#include <boost/property_tree/json_parser.hpp>
-#include <boost/variant.hpp>
-
 #include "ocstack.h"
 #include "OCHeaderOption.h"
 #include <OCException.h>
 #include "StringConstants.h"
 #include "oc_logger.hpp"
 
+#include <OCRepresentation.h>
+
 namespace OC
 {
     class OCResource;
@@ -160,538 +158,7 @@ namespace OC
         Observe,
         ObserveAll
     };
-
-    // Helper function to escape character in a string.
-    std::string escapeString(const std::string& value);
-
-    typedef std::map<std::string, std::string> AttributeMap;
-
-    class OCRepresentation
-    {
-        private:
-        std::string m_uri;
-        AttributeMap m_attributeMap;
-        std::vector<std::string> m_resourceTypes;
-        std::vector<std::string> m_resourceInterfaces;
-        int errorCode;
-
-        std::vector<OCRepresentation> m_children;
-
-        public:
-        OCRepresentation() {}
-
-        bool erase(const std::string& str)
-        {
-            return m_attributeMap.erase(str) != 0;
-        }
-
-        std::string getUri(void) const
-        {
-            return m_uri;
-        }
-
-        template <typename T>
-        void setValue(const std::string& str, const T& val);
-
-        template <typename T>
-        bool getValue(const std::string& str, T& val) const;
-
-        template <typename T>
-        T getValue(const std::string& str) const;
-
-        bool hasAttribute(const std::string& str) const
-        {
-            return m_attributeMap.find(str) != m_attributeMap.end();
-        }
-
-        void setNULL(const std::string& str)
-        {
-            m_attributeMap[str] = "null";
-        }
-
-        bool isNULL(const std::string& str) const
-        {
-            auto x = m_attributeMap.find(str);
-
-            if(m_attributeMap.end() != x)
-            {
-                return x->second.compare("null") == 0;
-            }
-            else
-            {
-                std::ostringstream message;
-                message << "attribute: " << str << " doesn't exist\n";
-                throw OCException(message.str());
-            }
-
-            return false;
-        }
-
-        int numberOfAttributes() const
-        {
-            return m_attributeMap.size();
-        }
-
-        void setUri(std::string uri)
-        {
-            m_uri = uri;
-        }
-
-        std::vector<OCRepresentation> getChildren(void) const
-        {
-            return m_children;
-        }
-
-        void setChildren(const std::vector<OCRepresentation>& children)
-        {
-            m_children = children;
-        }
-
-        std::weak_ptr<OCResource> getResource() const
-        {
-            // TODO Needs to be implemented
-            std::weak_ptr<OCResource> wp;
-            return wp;
-        }
-
-        AttributeMap getAttributeMap() const
-        {
-            return m_attributeMap;
-        }
-
-        void setAttributeMap(const AttributeMap& map)
-        {
-            m_attributeMap = map;
-        }
-
-        std::string getJSONRepresentation(void) const
-        {
-            std::ostringstream json;
-
-            json << "{";
-
-            for(auto itr = m_attributeMap.begin(); itr!= m_attributeMap.end(); ++ itr)
-            {
-                if(itr != m_attributeMap.begin())
-                {
-                    json << ',';
-                }
-                json << "\""<<itr->first<<"\":"<< itr->second;
-            }
-            json << "}";
-
-            return json.str();
-        }
-
-        std::vector<std::string> getResourceTypes() const
-        {
-            return m_resourceTypes;
-        }
-
-        void setResourceTypes(const std::vector<std::string>& resourceTypes)
-        {
-            m_resourceTypes = resourceTypes;
-        }
-
-        std::vector<std::string> getResourceInterfaces(void) const
-        {
-            return m_resourceInterfaces;
-        }
-
-        void setResourceInterfaces(const std::vector<std::string>& resourceInterfaces)
-        {
-            m_resourceInterfaces = resourceInterfaces;
-        }
-    };
-
-    OCRepresentation parseJSONToRepresentation(const std::string& str);
-
-    inline OCRepresentation parseJSONToRepresentation(const std::string& str)
-    {
-        OCRepresentation rep;
-
-        AttributeMap attributeMap;
-
-        std::stringstream requestStream;
-        requestStream << str;
-        boost::property_tree::ptree payload;
-        try
-        {
-            boost::property_tree::read_json(requestStream, payload);
-        }
-        catch(boost::property_tree::json_parser::json_parser_error &e)
-        {
-            throw OCException(OC::Exception::GENERAL_JSON_PARSE_FAILED);
-        }
-
-        for(auto& item: payload)
-        {
-            std::string name = item.first.data();
-            std::string value = item.second.data();
-
-            attributeMap[name] = value;
-        }
-
-        rep.setAttributeMap(attributeMap);
-
-        return rep;
-    }
-
-    typedef boost::variant<
-                int,
-                double,
-                bool,
-                OCRepresentation,
-                std::string,
-                std::vector<int>,
-                std::vector<double>,
-                std::vector<bool>,
-                std::vector<std::string>,
-                std::vector<OCRepresentation>
-                > AttributeValue;
-
-    template <typename T>
-    inline std::string getJSONFromVector(const std::vector<T>& v)
-    {
-        std::ostringstream json;
-
-        json << "\"[";
-        if(v.size() != 0)
-        {
-            std::copy(v.begin(), v.end() - 1, std::ostream_iterator<T>(json, ","));
-            json << v.back();
-        }
-        json << "]\"";
-
-        return json.str();
-    }
-
-    class ComposeVisitor : public boost::static_visitor<std::string>
-    {
-        public:
-
-            // TODO different int sizes
-            std::string operator() (const int i) const
-            {
-                return std::to_string(i);
-            }
-
-            std::string operator() (const double d) const
-            {
-                return std::to_string(d);
-            }
-
-            std::string operator() (const std::string& str) const
-            {
-                std::ostringstream json;
-                json << "\"";
-                json << str;
-                json << "\"";
-
-                return json.str();
-            }
-
-            std::string operator() (const bool b) const
-            {
-                if(b)
-                {
-                    return "true";
-                }
-                else
-                {
-                    return "false";
-                }
-            }
-
-            std::string operator() (const std::vector<int>& numbers) const
-            {
-                return getJSONFromVector(numbers);
-            }
-
-            std::string operator() (const std::vector<double>& numbers) const
-            {
-                return getJSONFromVector(numbers);
-            }
-
-            std::string operator() (const std::vector<bool>& bools) const
-            {
-                std::ostringstream json;
-                int first = 1;
-
-                json << "\"[";
-                for(auto b: bools)
-                {
-                    if(first)
-                    {
-                        b ? json << "true" : json << "false";
-                        first = 0;
-                    }
-                    else
-                    {
-                        b ? json << ",true" : json << ",false";
-                    }
-                }
-                json << "]\"";
-
-                return json.str();
-            }
-
-            std::string operator() (const std::vector<std::string>& strings) const
-            {
-                return getJSONFromVector(strings);
-            }
-
-            std::string operator() (const OCRepresentation& rep) const
-            {
-                std::ostringstream json;
-
-                json << "\"";
-
-                json << escapeString(rep.getJSONRepresentation());
-
-                json << "\"";
-
-                return json.str();
-            }
-
-            std::string operator() (const std::vector<OCRepresentation>& reps) const
-            {
-                std::ostringstream json;
-                int first = 1;
-
-                json << "\"[";
-                for(auto rep: reps)
-                {
-                    if(first)
-                    {
-                        first = 0;
-                        json << escapeString(rep.getJSONRepresentation());
-                    }
-                    else
-                    {
-                        json << ",";
-                        json << escapeString(rep.getJSONRepresentation());
-                    }
-                }
-                json << "]\"";
-
-                return json.str();
-            }
-
-
-    };
-
-    inline void split(std::string input, char delimiter, std::vector<std::string>& tokens)
-    {
-        std::stringstream ss(input);
-        std::string item;
-
-        while(std::getline(ss, item, delimiter))
-        {
-            tokens.push_back(item);
-        }
-    }
-
-    class ParseVisitor : public boost::static_visitor<void>
-    {
-        public:
-
-            ParseVisitor(std::string str): m_str(str)
-            {
-            }
-
-            void operator() (int& i) const
-            {
-                i = std::stoi(m_str);
-            }
-
-            void operator() (double& d) const
-            {
-                d = std::stod(m_str);
-            }
-
-            void operator() (std::string& str) const
-            {
-                str = m_str;
-            }
-
-            void operator() (bool& b) const
-            {
-                b = m_str.compare("true") == 0;
-            }
-
-            void operator() (std::vector<int>& numbers) const
-            {
-                numbers.clear();
-
-                if(m_str.length() >= 2)
-                {
-                    std::string str = m_str.substr(1, m_str.length()-2);
-
-                    std::vector<std::string> tokens;
-                    split(str, ',', tokens);
-
-                    for(auto s: tokens)
-                    {
-                        numbers.push_back(std::stoi(s));
-                    }
-                }
-                else
-                {
-                    throw OCException(OC::Exception::INVALID_ARRAY);
-                }
-
-            }
-
-            void operator() (std::vector<double>& numbers) const
-            {
-                numbers.clear();
-
-                if(m_str.length() >= 2)
-                {
-                    std::string str = m_str.substr(1, m_str.length()-2);
-                    std::vector<std::string> tokens;
-                    split(str, ',', tokens);
-
-                    for(auto s: tokens)
-                    {
-                        numbers.push_back(std::stod(s));
-                    }
-                }
-                else
-                {
-                    throw OCException(OC::Exception::INVALID_ARRAY);
-                }
-            }
-
-            void operator() (std::vector<bool>& bools) const
-            {
-                bools.clear();
-
-                if(m_str.length() >= 2)
-                {
-                    std::string str = m_str.substr(2, m_str.length()-3);
-
-                    std::vector<std::string> tokens;
-                    split(str, ',', tokens);
-
-                    for(auto s: tokens)
-                    {
-                        bools.push_back(s.compare("true") == 0);
-                    }
-                }
-                else
-                {
-                    throw OCException(OC::Exception::INVALID_ARRAY);
-                }
-
-            }
-
-            void operator() (std::vector<std::string>& strings) const
-            {
-                strings.clear();
-
-                if(m_str.length() >= 2)
-                {
-                    std::string str = m_str.substr(1, m_str.length()-2);
-
-                    std::vector<std::string> tokens;
-                    split(str, ',', tokens);
-
-                    for(auto s: tokens)
-                    {
-                        strings.push_back(s);
-                    }
-                }
-                else
-                {
-                    throw OCException(OC::Exception::INVALID_ARRAY);
-                }
-            }
-
-            void operator() (std::vector<OCRepresentation>& reps) const
-            {
-                reps.clear();
-
-                if(m_str.length() >= 2)
-                {
-                    std::string str = m_str.substr(1, m_str.length()-2);
-
-                    std::vector<std::string> tokens;
-                    split(str, ',', tokens);
-
-                    for(auto s: tokens)
-                    {
-                        reps.push_back(parseJSONToRepresentation(s));
-                    }
-                }
-                else
-                {
-                    throw OCException(OC::Exception::INVALID_ARRAY);
-                }
-            }
-
-            void operator() (OCRepresentation& rep) const
-            {
-                rep = parseJSONToRepresentation(m_str);
-            }
-
-        private:
-            std::string m_str;
-    };
-
-
-    inline std::string getJSON(const AttributeValue& v)
-    {
-        return boost::apply_visitor(ComposeVisitor(), v);
-    }
-
-    inline void parseJSON(AttributeValue& v, std::string str)
-    {
-        boost::apply_visitor(ParseVisitor(str), v);
-    }
-
-    template <typename T>
-    void OCRepresentation::setValue(const std::string& str, const T& val)
-    {
-        m_attributeMap[str] = getJSON(val);
-    }
-
-    template <typename T>
-    T OCRepresentation::getValue(const std::string& str) const
-    {
-        T val = T();
-
-        auto x = m_attributeMap.find(str);
-
-        if(m_attributeMap.end() != x)
-        {
-            AttributeValue v = val;
-            parseJSON(v, x->second);
-            val = boost::get<T>(v);
-        }
-
-        return val;
-    }
-
-    template <typename T>
-    bool OCRepresentation::getValue(const std::string& str, T& val) const
-    {
-        auto x = m_attributeMap.find(str);
-
-        if(m_attributeMap.end() != x)
-        {
-            AttributeValue v = val;
-            parseJSON(v, x->second);
-            val = boost::get<T>(v);
-            return true;
-        }
-        else
-        {
-            return false;
-        }
-    }
-
+    //
     // Typedef for header option vector
     // OCHeaderOption class is in HeaderOption namespace
     typedef std::vector<HeaderOption::OCHeaderOption> HeaderOptions;
index 0a0ba16..c27d0c3 100644 (file)
 
 /// @file OCRepresentation.h
 
-/// @brief  This file contains the declaration of classes and its members 
+/// @brief  This file contains the declaration of classes and its members
 ///         related to OCRepresentation
 
 #ifndef __OCREPRESENTATION_H
 #define __OCREPRESENTATION_H
 
 
-#include <OCApi.h>
-#include <OCResource.h>
+#include <string>
+#include <sstream>
+#include <vector>
+#include <map>
 
+#include <AttributeValue.h>
+#include <StringConstants.h>
+
+// note: is there any way to move this later so that the implementers don't need to
+// reference them?
+#include <cereal/cereal.hpp>
+#include <cereal/types/map.hpp>
+#include <cereal/types/vector.hpp>
+#include <OicJsonSerializer.hpp>// Customized Cereal serializer, required for a few functions
+#include <cereal/types/utility.hpp>
+
+#include <OCException.h>
 namespace OC
 {
-    
+
+    enum class InterfaceType
+    {
+        None,
+        LinkParent,
+        BatchParent,
+        DefaultParent,
+        LinkChild,
+        BatchChild,
+        DefaultChild
+    };
+
+    // The consumer requires resource info to be printed in 2 different ways, both with the "oc":[]
+    // and without.  This enum is used to differentiate between the two situations.  When the
+    // serialize is called with Include OC, we encode OC, otherwise we skip it and return just the
+    // contents of the array.
+    enum class OCInfoFormat
+    {
+        IncludeOC,
+        ExcludeOC
+    };
+
+    class MessageContainer
+    {
+        public:
+            void setJSONRepresentation(const std::string& payload);
+
+            void setJSONRepresentation(const unsigned char* payload);
+
+            std::string getJSONRepresentation(OCInfoFormat f) const;
+
+            const std::vector<OCRepresentation>& representations() const;
+
+            void addRepresentation(const OCRepresentation& rep);
+
+            const OCRepresentation& operator[](int index) const
+            {
+                return m_reps[index];
+            }
+
+            const OCRepresentation& back() const
+            {
+                return m_reps.back();
+            }
+        private:
+            std::vector<OCRepresentation> m_reps;
+    };
+    class OCRepresentation
+    {
+        public:
+            OCRepresentation();
+            std::string getJSONRepresentation() const;
+
+            void addChild(const OCRepresentation&);
+
+            void clearChildren();
+
+            const std::vector<OCRepresentation>& getChildren() const;
+
+            void setChildren(const std::vector<OCRepresentation>& children);
+
+            void setUri(const std::string& uri);
+
+            std::string getUri() const;
+
+            const std::vector<std::string>& getResourceTypes() const;
+
+            void setResourceTypes(const std::vector<std::string>& resourceTypes);
+
+            const std::vector<std::string>& getResourceInterfaces() const;
+
+            void setResourceInterfaces(const std::vector<std::string>& resourceInterfaces);
+
+            bool empty() const;
+
+            int numberOfAttributes() const;
+
+            bool erase(const std::string& str);
+
+            template <typename T>
+            void setValue(const std::string& str, const T& val)
+            {
+                m_values[str] = val;
+            }
+
+            template <typename T>
+            bool getValue(const std::string& str, T& val) const
+            {
+                auto x = m_values.find(str);
+
+                if(x!= m_values.end())
+                {
+                    val = boost::get<T>(x->second);
+                    return true;
+                }
+                else
+                {
+                    val = T();
+                    return false;
+                }
+            }
+
+            template <typename T>
+            T getValue(const std::string& str) const
+            {
+                T val = T();
+                auto x = m_values.find(str);
+                if(x != m_values.end())
+                {
+                    val = boost::get<T>(x->second);
+                }
+                return val;
+            }
+
+            bool hasAttribute(const std::string& str) const;
+
+            void setNULL(const std::string& str);
+
+            bool isNULL(const std::string& str) const;
+        private:
+            friend class OCResourceResponse;
+            friend class cereal::access;
+
+            // the root node has a slightly different JSON version
+            // based on the interface type configured in ResourceResponse.
+            // This allows ResourceResponse to set it, so that the save function
+            // doesn't serialize things that it isn't supposed to serialize.
+            void setInterfaceType(InterfaceType ift)
+            {
+                m_interfaceType = ift;
+            }
+
+            // class used to wrap the 'prop' feature of the save/load
+            class Prop
+            {
+                public:
+                    Prop(std::vector<std::string>& resourceTypes,
+                            std::vector<std::string>& interfaces)
+                    : m_types(resourceTypes), m_interfaces(interfaces)
+                    {}
+
+                 /*   Prop(const std::vector<std::string>& resourceTypes,
+                            const std::vector<std::string>& interfaces)
+                    :m_types(resourceTypes),
+                    m_interfaces(interfaces)
+                    {}*/
+                private:
+                    friend class cereal::access;
+                    template <class Archive>
+                    void save(Archive& ar) const
+                    {
+                        if(m_types.size() > 0)
+                        {
+                            ar(cereal::make_nvp(Key::RESOURCETYPESKEY, m_types));
+                        }
+
+                        if(m_interfaces.size()>0)
+                        {
+                            ar(cereal::make_nvp(Key::INTERFACESKEY, m_interfaces));
+                        }
+                    }
+
+                    template<class Archive>
+                    void load(Archive& ar)
+                    {
+                        optional_load(ar, cereal::make_nvp(Key::RESOURCETYPESKEY, m_types));
+                        optional_load(ar, cereal::make_nvp(Key::INTERFACESKEY, m_interfaces));
+                    }
+
+                    std::vector<std::string>& m_types;
+                    std::vector<std::string>& m_interfaces;
+            };
+            template<class Archive, class Val>
+            static void optional_load(Archive& ar, Val&& v)
+            {
+                try
+                {
+                    ar(v);
+                }
+                catch(cereal::Exception& e)
+                {
+                    ar.setNextName(nullptr);
+                    // Loading a key that doesn't exist results in an exception
+                    // Since "Not Found" is a valid condition for us, we swallow
+                    // this exception and the archive will not load anything
+                }
+            }
+            template<class Archive>
+            void save(Archive& ar) const
+            {
+                // printed for all interface types
+                if(!m_uri.empty())
+                {
+                    ar(cereal::make_nvp(Key::URIKEY, m_uri));
+                }
+
+                if((m_interfaceType == InterfaceType::None
+                            || m_interfaceType==InterfaceType::DefaultChild
+                            || m_interfaceType==InterfaceType::LinkChild)
+                        && (m_resourceTypes.size()>0 || m_interfaces.size()>0))
+                {
+                    // The Prop object requires that it refer to non-const vectors
+                    // so that it can alter them in the 'load' case.  In the save case
+                    // (initiated here) it will not modify the object.  So, to keep the
+                    // compiler happy, removing the 'const' context here is necessary.
+                    const std::vector<std::string>& rt(m_resourceTypes);
+                    const std::vector<std::string>& intf(m_interfaces);
+                    Prop temp(const_cast<std::vector<std::string>&>(rt),
+                            const_cast<std::vector<std::string>&>(intf));
+                    ar(cereal::make_nvp(Key::PROPERTYKEY, temp));
+                }
+
+                // printed only for BatchChildren and DefaultParent
+                if((m_interfaceType == InterfaceType::None
+                            || m_interfaceType == InterfaceType::BatchChild
+                            || m_interfaceType == InterfaceType::DefaultParent)
+                        && m_values.size()>0)
+                {
+                    ar(cereal::make_nvp(Key::REPKEY, m_values));
+                }
+            }
+
+            template<class Archive>
+            void load(Archive& ar)
+            {
+                optional_load(ar, cereal::make_nvp(Key::URIKEY, m_uri));
+                {
+                    Prop temp(m_resourceTypes, m_interfaces);
+                    optional_load(ar, cereal::make_nvp(Key::PROPERTYKEY, temp));
+                }
+                optional_load(ar, cereal::make_nvp(Key::REPKEY, m_values));
+            }
+
+        private:
+            std::string m_uri;
+            std::vector<OCRepresentation> m_children;
+            std::map<std::string, AttributeValue> m_values;
+            std::vector<std::string> m_resourceTypes;
+            std::vector<std::string> m_interfaces;
+
+            InterfaceType m_interfaceType;
+    };
 } // namespace OC
 
+// code needed to serialize a string::Attribute value map
+namespace OC
+{
+    namespace detail
+    {
+        template<class Archive>
+        class WriteAttributeValue : public boost::static_visitor<>
+        {
+            public:
+                WriteAttributeValue(const std::string& name, Archive& ar)
+                    :m_name(name), m_archive(ar)
+                {}
+
+                template<class T>
+                void operator()(const T& value) const
+                {
+                    m_archive(cereal::make_nvp(m_name, value));
+                }
+            private:
+                std::string m_name;
+                Archive& m_archive;
+        };
+    }
+}
+
+namespace cereal
+{
+    // take no action when serializing the null type, because the 'save' below
+    // doesn't use the visitor for this type.
+    template <class Archive>
+    void serialize(Archive&, OC::NullType t)
+    {}
+
+    template<class Archive>
+    void save(Archive& ar, const std::map<std::string, OC::AttributeValue>& vals)
+    {
+        for(const auto& kv : vals)
+        {
+            const auto& k = kv.first;
+            const auto& v = kv.second;
+
+            if(v.which() != OC::AttributeValueNullIndex)
+            {
+                OC::detail::WriteAttributeValue<Archive> writer(k,ar);
+                boost::apply_visitor(writer, v);
+            }
+            else
+            {
+                ar.setNextName(k.c_str());
+                ar.writeName();
+                ar.saveValue();
+            }
+        }
+    }
+
+    template<class Archive>
+    void load(Archive& ar, std::map<std::string, OC::AttributeValue>& vals)
+    {
+        ar.loadAttributeValues(vals);
+    }
+}
+
 #endif //__OCREPRESENTATION_H
index 5d5802c..63c4253 100644 (file)
@@ -30,9 +30,6 @@
 #include <random>
 #include <algorithm>
 
-#include <boost/property_tree/ptree.hpp>
-#include <boost/property_tree/json_parser.hpp>
-
 #include <OCApi.h>
 #include <ResourceInitException.h>
 #include <IClientWrapper.h>
@@ -52,8 +49,7 @@ namespace OC
     class OCResource
     {
     friend class OCPlatform_impl;
-    friend class InProcClientWrapper;
-
+    friend class ListenOCContainer;
     public:
         typedef std::shared_ptr<OCResource> Ptr;
         /**
index 890a4a7..5b7e206 100644 (file)
 #ifndef __OCRESOURCEREQUEST_H
 #define __OCRESOURCEREQUEST_H
 
-#include <boost/property_tree/ptree.hpp>
-#include <boost/property_tree/json_parser.hpp>
-
 #include "OCApi.h"
 #include "OCRepresentation.h"
 
+void formResourceRequest(OCEntityHandlerFlag,
+                         OCEntityHandlerRequest*,
+                         std::shared_ptr<OC::OCResourceRequest>);
+
+
 namespace OC
 {
     /**
@@ -118,74 +120,53 @@ namespace OC
         ObservationInfo m_observationInfo;
         HeaderOptions m_headerOptions;
 
-    public:
-        // TODO: This is not a public API for app developers.
-        // This function will not be exposed in future
+    private:
+        friend void (::formResourceRequest)(OCEntityHandlerFlag, OCEntityHandlerRequest*,
+            std::shared_ptr<OC::OCResourceRequest>);
         void setRequestType(const std::string& requestType)
         {
             m_requestType = requestType;
         }
 
-        // TODO: This is not a public API for app developers.
-        // This function will not be exposed in future
         void setPayload(const std::string& requestPayload)
         {
-            AttributeMap attributeMap;
-            // TODO: The following JSON Parse implementation should be seperated into utitilites
-            // and used wherever required.
-            // e.g. parse(std::string& payload, Attributemap& attributeMap)
-
-            std::stringstream requestStream;
-            requestStream << requestPayload;
-            boost::property_tree::ptree root;
-            try
-            {
-                boost::property_tree::read_json(requestStream, root);
-            }
-            catch(boost::property_tree::json_parser::json_parser_error &e)
+            MessageContainer info;
+            info.setJSONRepresentation(requestPayload);
+
+            const std::vector<OCRepresentation>& reps = info.representations();
+            if(reps.size() >0)
             {
-                //TOD: log this
-                return;
+                std::vector<OCRepresentation>::const_iterator itr = reps.begin();
+                std::vector<OCRepresentation>::const_iterator back = reps.end();
+                m_representation = *itr;
+                ++itr;
+
+                for(;itr != back; ++itr)
+                {
+                    m_representation.addChild(*itr);
+                }
             }
-
-            // TODO this expects the representation oc:{} and not oc:[{}]
-            //      this representation is fine when setting for simple resource.
-            boost::property_tree::ptree payload = root.get_child(OC::Key::OCKEY, boost::property_tree::ptree());
-
-            for(auto& item: payload)
+            else
             {
-                std::string name = item.first.data();
-                std::string value = item.second.data();
-
-                attributeMap[name] = value;
+                throw OCException(OC::Exception::INVALID_REPRESENTATION);
             }
-
-            m_representation.setAttributeMap(attributeMap);
         }
 
-        // TODO: This is not a public API for app developers.
-        // This function will not be exposed in future
         void setQueryParams(QueryParamsMap& queryParams)
         {
             m_queryParameters = queryParams;
         }
 
-        // TODO: This is not a public API for app developers.
-        // This function will not be exposed in future
         void setRequestHandlerFlag(int requestHandlerFlag)
         {
             m_requestHandlerFlag = requestHandlerFlag;
         }
 
-        // TODO: This is not a public API for app developers.
-        // This function will not be exposed in future
         void setObservationInfo(const ObservationInfo& observationInfo)
         {
             m_observationInfo = observationInfo;
         }
 
-        // TODO: This is not a public API for app developers.
-        // This function will not be exposed in future
         void setHeaderOptions(const HeaderOptions& headerOptions)
         {
             m_headerOptions = headerOptions;
index 4cd371f..ee660e3 100644 (file)
 
 using namespace std;
 
+
+void (processResourceResponse)(OCEntityHandlerFlag,
+                                 OCEntityHandlerRequest*,
+                                 std::shared_ptr<OC::OCResourceResponse> pResponse);
+
+
 namespace OC
 {
     /**
@@ -43,14 +49,9 @@ namespace OC
     public:
         typedef std::shared_ptr<OCResourceResponse> Ptr;
 
-        /**
-        *  Default destructor
-        */
-        OCResourceResponse() {}
+        OCResourceResponse()
+        {}
 
-        /**
-        *  Virtual destructor
-        */
         virtual ~OCResourceResponse(void) {}
 
         /**
@@ -93,19 +94,8 @@ namespace OC
         *  @param interface specifies the interface
         */
         void setResourceRepresentation(OCRepresentation& rep, std::string interface) {
-            if(!interface.compare(LINK_INTERFACE))
-            {
-                setResourceRepresentationLL(rep);
-            }
-            else if(!interface.compare(BATCH_INTERFACE))
-            {
-                setResourceRepresentationBatch(rep);
-            }
-            else
-            {
-                setResourceRepresentationDefault(rep);
-            }
-            // TODO other interfaces
+            m_interface = interface;
+            m_representation = rep;
         }
 
         /**
@@ -125,7 +115,8 @@ namespace OC
         */
         void setResourceRepresentation(OCRepresentation& rep) {
             // Call the default
-            setResourceRepresentationDefault(rep);
+            m_interface = DEFAULT_INTERFACE;
+            m_representation = rep;
         }
 
         /**
@@ -137,187 +128,59 @@ namespace OC
             // Call the above function
             setResourceRepresentation(rep);
         }
+    private:
+        std::string m_newResourceUri;
+        int m_errorCode;
+        HeaderOptions m_headerOptions;
+        std::string m_interface;
+        OCRepresentation m_representation;
+    private:
+        friend void (::processResourceResponse)(OCEntityHandlerFlag,
+                            OCEntityHandlerRequest*,
+                            std::shared_ptr<OC::OCResourceResponse> pResponse);
+        std::string getPayload() const
+        {
+            MessageContainer inf;
+            OCRepresentation first(m_representation);
 
-        /**
-        *  API to set the entire resource attribute representation (Linked List Interface))
-        *  @param attributeMap reference containing the name value pairs representing the resource's
-        *  attributes
-        */
-        void setResourceRepresentationLL(OCRepresentation& rep) {
-
-            // Default Set
-
-            ostringstream payload;
-
-            // Parent
-            payload << "{";
-            payload << "\"href\":";
-            payload << "\"" ;
-            payload << rep.getUri();
-            payload << "\"" ;
-            payload << "}";
-
-            // Children stuff
-            std::vector<OCRepresentation> children = rep.getChildren();
-
-            for(auto oitr = children.begin(); oitr != children.end(); ++oitr)
+            if(m_interface==LINK_INTERFACE)
             {
-                payload << ",{\"href\":";
-
-                payload << "\"" ;
-                payload << oitr->getUri();
-                payload << "\"" ;
-
-                payload << ",\"prop\":{";
-
-                payload << "\"rt\":[";
-                std::vector<std::string> types = oitr->getResourceTypes();
-                for(auto itr = types.begin(); itr != types.end(); ++itr)
-                {
-                    if(itr != types.begin())
-                    {
-                        payload << ',';
-                    }
-
-                    payload << *itr;
-                }
-                payload << "],";
-
-                payload << "\"if\":[";
-                std::vector<std::string> interfaces = oitr->getResourceInterfaces();
-                for(auto itr = interfaces.begin(); itr != interfaces.end(); ++itr)
-                {
-                    if(itr != interfaces.begin())
-                    {
-                        payload << ',';
-                    }
-
-                    payload << "\"" << *itr << "\"";
-                }
-                payload << "]";
-
-                payload << "}}";
+                first.setInterfaceType(InterfaceType::LinkParent);
             }
-
-            m_payload = payload.str();
-        }
-
-        /**
-        *  API to set the entire resource attribute representation (Default))
-        *  @param attributeMap reference containing the name value pairs representing the resource's
-        *  attributes
-        */
-        void setResourceRepresentationDefault(OCRepresentation& rep) {
-
-            // Default Set
-
-            ostringstream payload;
-
-            // Parent
-            payload << "{";
-            payload << "\"href\":";
-            payload << "\"" ;
-            payload << rep.getUri();
-            payload << "\"" ;
-
-            payload << ",\"rep\":";
-
-            payload << rep.getJSONRepresentation();
-
-            payload << "}";
-
-            // Children stuff
-            std::vector<OCRepresentation> children = rep.getChildren();
-
-            for(auto oitr = children.begin(); oitr != children.end(); ++oitr)
+            else if(m_interface==BATCH_INTERFACE)
             {
-                payload << ",{\"href\":";
+                first.setInterfaceType(InterfaceType::BatchParent);
+            }
+            else
+            {
+                first.setInterfaceType(InterfaceType::DefaultParent);
+            }
 
-                payload << "\"" ;
-                payload << oitr->getUri();
-                payload << "\"" ;
+            inf.addRepresentation(first);
 
-                payload << ",\"prop\":{";
+            for(const OCRepresentation& rep : m_representation.getChildren())
+            {
+                OCRepresentation cur(rep);
 
-                payload << "\"rt\":[";
-                std::vector<std::string> types = oitr->getResourceTypes();
-                for(auto itr = types.begin(); itr != types.end(); ++itr)
+                if(m_interface==LINK_INTERFACE)
                 {
-                    if(itr != types.begin())
-                    {
-                        payload << ',';
-                    }
-
-                    payload << "\"" << *itr << "\"";
+                    cur.setInterfaceType(InterfaceType::LinkChild);
                 }
-                payload << "],";
-
-                payload << "\"if\":[";
-                std::vector<std::string> interfaces = oitr->getResourceInterfaces();
-                for(auto itr = interfaces.begin(); itr != interfaces.end(); ++itr)
+                else if(m_interface==BATCH_INTERFACE)
                 {
-                    if(itr != interfaces.begin())
-                    {
-                        payload << ',';
-                    }
-
-                    payload << "\"" << *itr << "\"";
+                    cur.setInterfaceType(InterfaceType::BatchChild);
+                }
+                else
+                {
+                    cur.setInterfaceType(InterfaceType::DefaultChild);
                 }
-                payload << "]";
-
-                payload << "}}";
-            }
-
-            m_payload = payload.str();
-        }
-
-        /**
-        *  API to set the entire resource attribute representation (BATCH)
-        *  @param attributeMap reference containing the name value pairs representing the resource's
-        *  attributes
-        */
-        void setResourceRepresentationBatch(OCRepresentation& rep) {
-            ostringstream payload;
-
-            // Parent
-            payload << "{";
-            payload << "\"href\":";
-            payload << "\"" ;
-            payload << rep.getUri();
-            payload << "\"" ;
-            payload << "}";
-
-            std::vector<OCRepresentation> children = rep.getChildren();
-
-            for(auto oitr = children.begin(); oitr != children.end(); ++oitr)
-            {
-                payload << ',';
-
-                payload << "{";
-
-                payload << "\"href\":";
-
-                payload << "\"" ;
-                payload << oitr->getUri();
-                payload << "\"" ;
-
-                payload << ",\"rep\":";
 
-                payload << oitr->getJSONRepresentation();
+                inf.addRepresentation(cur);
 
-                payload << "}";
             }
 
-            m_payload = payload.str();
+            return inf.getJSONRepresentation(OCInfoFormat::ExcludeOC);
         }
-
-    private:
-        std::string m_newResourceUri;
-        std::string m_payload;
-        int m_errorCode;
-        HeaderOptions m_headerOptions;
-
-    // TODO only stack should have visibility and apps should not
     public:
 
         /**
@@ -326,22 +189,18 @@ namespace OC
         int getErrorCode() const;
 
         /**
-        * This API allows to retrieve headerOptions from a response
-        */
-        const HeaderOptions& getHeaderOptions() const
+         * Get the Response Representation
+         */
+        const OCRepresentation& getResourceRepresentation() const
         {
-            return m_headerOptions;
+            return m_representation;
         }
-
         /**
-        * Get the resource attribute representation
+        * This API allows to retrieve headerOptions from a response
         */
-        AttributeMap& getResourceRepresentation() const;
-
-        // TODO This should go away & just use getResourceRepresentation
-        std::string getPayload()
+        const HeaderOptions& getHeaderOptions() const
         {
-            return m_payload;
+            return m_headerOptions;
         }
     };
 
diff --git a/resource/include/OCSerialization.h b/resource/include/OCSerialization.h
new file mode 100644 (file)
index 0000000..bbdd200
--- /dev/null
@@ -0,0 +1,275 @@
+//******************************************************************
+//
+// Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+#include <cereal/cereal.hpp>
+#include <cereal/types/memory.hpp>
+#include <cereal/types/vector.hpp>
+#include <cereal/archives/json.hpp>
+
+#include <StringConstants.h>
+
+namespace OC
+{
+    class ListenOCContainer
+    {
+        private:
+        enum class OCSecureType
+        {
+            IPv4Secure,
+            IPv4
+        };
+
+        class ListenResourceContainer
+        {
+            class ListenResourcePropertiesContainer
+            {
+                friend class cereal::access;
+                friend class ListenResourceContainer;
+
+                template<class Archive>
+                void serialize(Archive& ar)
+                {
+                    try
+                    {
+                        m_observable=false;
+                        int obsTemp;
+                        ar(cereal::make_nvp(OC::Key::OBSERVABLEKEY, obsTemp));
+                        m_observable = obsTemp != 0;
+                    }
+                    catch(cereal::Exception&)
+                    {
+                        // we swallow this exception, since it means the key
+                        // doesn't exist, allowing these to be optional
+                    }
+
+                    try
+                    {
+                        m_secure = false;
+                        int secureTemp;
+                        ar(cereal::make_nvp(OC::Key::SECUREKEY, secureTemp));
+                        m_secure = secureTemp != 0;
+
+                        m_port = -1;
+                        ar(cereal::make_nvp(OC::Key::PORTKEY, m_port));
+                    }
+                    catch(cereal::Exception&)
+                    {}
+
+                    try
+                    {
+                        ar(cereal::make_nvp(OC::Key::RESOURCETYPESKEY,m_resourceTypes));
+                    }
+                    catch(cereal::Exception&)
+                    {}
+                    try
+                    {
+                        ar(cereal::make_nvp(OC::Key::INTERFACESKEY, m_interfaces));
+                    }
+                    catch(cereal::Exception&)
+                    {}
+                }
+
+                bool m_observable;
+                std::vector<std::string> m_resourceTypes;
+                std::vector<std::string> m_interfaces;
+                bool m_secure;
+                int m_port;
+            };
+
+            public:
+            ListenResourceContainer() : m_loaded(false)
+            {}
+
+            private:
+            friend class cereal::access;
+            friend class ListenOCContainer;
+
+            template <class Archive>
+            void serialize(Archive& ar)
+            {
+                try
+                {
+                    ar(cereal::make_nvp(OC::Key::URIKEY, m_uri));
+                    m_loaded=true;
+                }
+                catch(cereal::Exception&)
+                {}
+                try
+                {
+                    ar(cereal::make_nvp(OC::Key::PROPERTYKEY, m_props));
+                    m_loaded=true;
+                }
+                catch(cereal::Exception&)
+                {}
+            }
+
+
+            std::string m_uri;
+            bool m_loaded;
+            ListenResourcePropertiesContainer m_props;
+
+            bool loaded() const
+            {
+                return m_loaded;
+            }
+
+            bool observable() const
+            {
+                return m_props.m_observable;
+            }
+
+            OCSecureType secureType() const
+            {
+                return m_props.m_secure?OCSecureType::IPv4Secure :OCSecureType::IPv4;
+            }
+
+            int port() const
+            {
+                return m_props.m_port;
+            }
+
+            std::vector<std::string> resourceTypes() const
+            {
+                return m_props.m_resourceTypes;
+            }
+
+            std::vector<std::string> interfaces() const
+            {
+                return m_props.m_interfaces;
+            }
+        };
+
+        private:
+            friend class cereal::access;
+            template <class Archive>
+            void serialize(Archive& ar)
+            {
+                std::vector<ListenResourceContainer> resources;
+                ar(resources);
+            }
+        public:
+            ListenOCContainer(std::weak_ptr<IClientWrapper> cw, const OCDevAddr& address,
+                    std::stringstream& json):
+                m_clientWrapper(cw), m_address(address)
+            {
+                LoadFromJson(json);
+            }
+
+            const std::vector<std::shared_ptr<OCResource>>& Resources() const
+            {
+                return m_resources;
+            }
+
+        private:
+            std::string ConvertOCAddrToString(OCSecureType sec, int secureport)
+            {
+                uint8_t addr1;
+                uint8_t addr2;
+                uint8_t addr3;
+                uint8_t addr4;
+                uint16_t port;
+
+                ostringstream os;
+
+                if(sec== OCSecureType::IPv4)
+                {
+                    os<<"coap://";
+                }
+                else if(sec == OCSecureType::IPv4Secure)
+                {
+                    os<<"coaps://";
+                }
+                else
+                {
+                    oclog() << "ConvertOCAddrToString():  invalid SecureType"<<std::flush;
+                    throw ResourceInitException(false, false, false, false, false, true);
+                }
+
+                if(0== OCDevAddrToIPv4Addr(&m_address, &addr1, &addr2, &addr3, &addr4))
+                {
+                    // nothing to do, successful case.
+                }
+                else
+                {
+                    oclog() << "ConvertOCAddrToString(): Invalid Ip"
+                        << std::flush;
+                    throw ResourceInitException(false, false, false, false, false, true);
+                }
+
+                os<<static_cast<int>(addr1)<<'.'
+                    <<static_cast<int>(addr2)<<'.'
+                    <<static_cast<int>(addr3)<<'.'
+                    <<static_cast<int>(addr4);
+
+                if(sec == OCSecureType::IPv4Secure && secureport>0 && secureport<=65535)
+                {
+                    port = static_cast<uint16_t>(secureport);
+                }
+                else if(sec == OCSecureType::IPv4 && 0==OCDevAddrToPort(&m_address, &port))
+                {
+                    // nothing to do, this is a successful case
+                }
+                else
+                {
+                    oclog() << "ConvertOCAddrToString() : Invalid Port"
+                            <<std::flush;
+                    throw ResourceInitException(false, false, false, false, true, false);
+                }
+
+                os <<":"<< static_cast<int>(port);
+
+                return os.str();
+            }
+
+            void LoadFromJson(std::stringstream& json)
+            {
+                cereal::JSONInputArchive archive(json);
+
+                std::vector<ListenResourceContainer> resources;
+                archive(cereal::make_nvp(OC::Key::OCKEY, resources));
+
+                m_resources.clear();
+
+                for(const auto& res : resources)
+                {
+                    try
+                    {
+                        if(res.loaded())
+                        {
+                            m_resources.push_back(std::shared_ptr<OCResource>(
+                                new OCResource(m_clientWrapper,
+                                    ConvertOCAddrToString(res.secureType(),res.port()),
+                                    res.m_uri, res.observable(), res.resourceTypes(),
+                                    res.interfaces())));
+                        }
+
+                    }
+                    catch(ResourceInitException& e)
+                    {
+                        oclog() << "listenCallback(): failed to create resource: " << e.what()
+                                << std::flush;
+                    }
+                }
+            }
+            std::vector<std::shared_ptr<OC::OCResource>> m_resources;
+            std::weak_ptr<IClientWrapper> m_clientWrapper;
+            OCDevAddr m_address;
+    };
+}
diff --git a/resource/include/OicJsonSerializer.hpp b/resource/include/OicJsonSerializer.hpp
new file mode 100644 (file)
index 0000000..ed07b9d
--- /dev/null
@@ -0,0 +1,862 @@
+/*! \file OicJsonSerializer.hpp
+    \brief JSON input and output archives.
+Note: this has been customized by Intel(R) for usage in the OIC project.
+Nearly the entire file is from Cereal (see copyright notice below) other than specified
+below
+Added:
+#include of AttributeValue Type
+JSONOutputArchive::saveValue() to add JSON null value
+loadAttributeValues to get attribute values out of a map (implemented in OCRepresentation)
+
+*/
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CEREAL_ARCHIVES_JSON_HPP_
+#define CEREAL_ARCHIVES_JSON_HPP_
+
+#include <AttributeValue.h>
+#include <cereal/cereal.hpp>
+#include <cereal/details/util.hpp>
+namespace cereal
+{
+  //! An exception thrown when rapidjson fails an internal assertion
+  /*! @ingroup Utility */
+  struct RapidJSONException : Exception
+  { RapidJSONException( const char * what_ ) : Exception( what_ ) {} };
+}
+
+// Override rapidjson assertions to throw exceptions by default
+#ifndef RAPIDJSON_ASSERT
+#define RAPIDJSON_ASSERT(x) if(!(x)){ \
+  throw ::cereal::RapidJSONException("rapidjson internal assertion failure: " #x); }
+#endif // RAPIDJSON_ASSERT
+
+#include <cereal/external/rapidjson/writer.h>
+#include <cereal/external/rapidjson/genericstream.h>
+#include <cereal/external/rapidjson/reader.h>
+#include <cereal/external/rapidjson/document.h>
+#include <cereal/external/base64.hpp>
+
+#include <limits>
+#include <sstream>
+#include <stack>
+#include <vector>
+#include <string>
+
+namespace cereal
+{
+  // ######################################################################
+  //! An output archive designed to save data to JSON
+  /*! This archive uses RapidJSON to build serialie data to JSON.
+
+      JSON archives provides a human readable output but at decreased
+      performance (both in time and space) compared to binary archives.
+
+      JSON benefits greatly from name-value pairs, which if present, will
+      name the nodes in the output.  If these are not present, each level
+      of the output will be given an automatically generated delimited name.
+
+      The precision of the output archive controls the number of decimals output
+      for floating point numbers and should be sufficiently large (i.e. at least 20)
+      if there is a desire to have binary equality between the numbers output and
+      those read in.  In general you should expect a loss of precision when going
+      from floating point to text and back.
+
+      JSON archives do not output the size information for any dynamically sized structure
+      and instead infer it from the number of children for a node.  This means that data
+      can be hand edited for dynamic sized structures and will still be readable.  This
+      is accomplished through the cereal::SizeTag object, which will cause the archive
+      to output the data as a JSON array (e.g. marked by [] instead of {}), which indicates
+      that the container is variable sized and may be edited.
+
+      \ingroup Archives */
+  class JSONOutputArchive : public OutputArchive<JSONOutputArchive>
+  {
+    enum class NodeType { StartObject, InObject, StartArray, InArray };
+
+    typedef rapidjson::GenericWriteStream WriteStream;
+    typedef rapidjson::Writer<WriteStream> JSONWriter;
+
+    public:
+      /*! @name Common Functionality
+          Common use cases for directly interacting with an JSONOutputArchive */
+      //! @{
+
+      //! A class containing various advanced options for the JSON archive
+      class Options
+      {
+        public:
+          //! Default options
+          static Options Default(){ return Options(); }
+
+          //! Specify specific options for the JSONOutputArchive
+          /*! @param precision The precision used for floating point numbers*/
+          explicit Options( int precision = std::numeric_limits<double>::max_digits10) :
+            itsPrecision( precision ) { }
+
+        private:
+          friend class JSONOutputArchive;
+          int itsPrecision;
+      };
+
+      //! Construct, outputting to the provided stream
+      /*! @param stream The stream to output to.
+          @param options The JSON specific options to use.  See the Options struct
+                         for the values of default parameters */
+      JSONOutputArchive(std::ostream & stream, Options const & options = Options::Default() ) :
+        OutputArchive<JSONOutputArchive>(this),
+        itsWriteStream(stream),
+        itsWriter(itsWriteStream, options.itsPrecision),
+        itsNextName(nullptr)
+      {
+        itsNameCounter.push(0);
+        itsNodeStack.push(NodeType::StartObject);
+      }
+
+      //! Destructor, flushes the JSON
+      ~JSONOutputArchive()
+      {
+        itsWriter.EndObject();
+      }
+
+      //! Saves some binary data, encoded as a base64 string, with an optional name
+      /*! This will create a new node, optionally named, and insert a value that consists of
+          the data encoded as a base64 string */
+      void saveBinaryValue( const void * data, size_t size, const char * name = nullptr )
+      {
+        setNextName( name );
+        writeName();
+
+        auto base64string = base64::encode( reinterpret_cast<const unsigned char *>( data ), size );
+        saveValue( base64string );
+      };
+
+      //! @}
+      /*! @name Internal Functionality
+          Functionality designed for use by those requiring control over the inner mechanisms of
+          the JSONOutputArchive */
+      //! @{
+
+      //! Starts a new node in the JSON output
+      /*! The node can optionally be given a name by calling setNextName prior
+          to creating the node
+
+          Nodes only need to be started for types that are themselves objects or arrays */
+      void startNode()
+      {
+        writeName();
+        itsNodeStack.push(NodeType::StartObject);
+        itsNameCounter.push(0);
+      }
+
+      //! Designates the most recently added node as finished
+      void finishNode()
+      {
+        // if we ended up serializing an empty object or array, writeName
+        // will never have been called - so start and then immediately end
+        // the object/array.
+        //
+        // We'll also end any object/arrays we happen to be in
+        switch(itsNodeStack.top())
+        {
+          case NodeType::StartArray:
+            itsWriter.StartArray();
+          case NodeType::InArray:
+            itsWriter.EndArray();
+            break;
+          case NodeType::StartObject:
+            itsWriter.StartObject();
+          case NodeType::InObject:
+            itsWriter.EndObject();
+            break;
+        }
+
+        itsNodeStack.pop();
+        itsNameCounter.pop();
+      }
+
+      //! Sets the name for the next node created with startNode
+      void setNextName( const char * name )
+      {
+        itsNextName = name;
+      }
+
+      //! Saves a null to the current node, added by Intel
+      void saveValue()                      { itsWriter.Null_();                                                         }
+      //! Saves a bool to the current node
+      void saveValue(bool b)                { itsWriter.Bool_(b);                                                         }
+      //! Saves an int to the current node
+      void saveValue(int i)                 { itsWriter.Int(i);                                                          }
+      //! Saves a uint to the current node
+      void saveValue(unsigned u)            { itsWriter.Uint(u);                                                         }
+      //! Saves an int64 to the current node
+      void saveValue(int64_t i64)           { itsWriter.Int64(i64);                                                      }
+      //! Saves a uint64 to the current node
+      void saveValue(uint64_t u64)          { itsWriter.Uint64(u64);                                                     }
+      //! Saves a double to the current node
+      void saveValue(double d)              { itsWriter.Double(d);                                                       }
+      //! Saves a string to the current node
+      void saveValue(std::string const & s) { itsWriter.String(s.c_str(), static_cast<rapidjson::SizeType>( s.size() )); }
+      //! Saves a const char * to the current node
+      void saveValue(char const * s)        { itsWriter.String(s);                                                       }
+
+    private:
+      // Some compilers/OS have difficulty disambiguating the above for various flavors of longs, so we provide
+      // special overloads to handle these cases.
+
+      //! 32 bit signed long saving to current node
+      template <class T> inline
+      typename std::enable_if<sizeof(T) == sizeof(std::int32_t) && std::is_signed<T>::value, void>::type
+      saveLong(T l){ saveValue( static_cast<std::int32_t>( l ) ); }
+
+      //! non 32 bit signed long saving to current node
+      template <class T> inline
+      typename std::enable_if<sizeof(T) != sizeof(std::int32_t) && std::is_signed<T>::value, void>::type
+      saveLong(T l){ saveValue( static_cast<std::int64_t>( l ) ); }
+
+      //! 32 bit unsigned long saving to current node
+      template <class T> inline
+      typename std::enable_if<sizeof(T) == sizeof(std::uint32_t) && !std::is_signed<T>::value, void>::type
+      saveLong(T lu){ saveValue( static_cast<std::uint32_t>( lu ) ); }
+
+      //! non 32 bit unsigned long saving to current node
+      template <class T> inline
+      typename std::enable_if<sizeof(T) != sizeof(std::uint32_t) && !std::is_signed<T>::value, void>::type
+      saveLong(T lu){ saveValue( static_cast<std::uint64_t>( lu ) ); }
+
+    public:
+#ifdef _MSC_VER
+      //! MSVC only long overload to current node
+      void saveValue( unsigned long lu ){ saveLong( lu ); };
+#else // _MSC_VER
+      //! Serialize a long if it would not be caught otherwise
+      template <class T> inline
+      typename std::enable_if<std::is_same<T, long>::value &&
+                              !std::is_same<T, std::int32_t>::value &&
+                              !std::is_same<T, std::int64_t>::value, void>::type
+      saveValue( T t ){ saveLong( t ); }
+
+      //! Serialize an unsigned long if it would not be caught otherwise
+      template <class T> inline
+      typename std::enable_if<std::is_same<T, unsigned long>::value &&
+                              !std::is_same<T, std::uint32_t>::value &&
+                              !std::is_same<T, std::uint64_t>::value, void>::type
+      saveValue( T t ){ saveLong( t ); }
+#endif // _MSC_VER
+
+      //! Save exotic arithmetic as strings to current node
+      /*! Handles long long (if distinct from other types), unsigned long (if distinct), and long double */
+      template<class T> inline
+      typename std::enable_if<std::is_arithmetic<T>::value &&
+                              !std::is_same<T, long>::value &&
+                              !std::is_same<T, unsigned long>::value &&
+                              !std::is_same<T, std::int64_t>::value &&
+                              !std::is_same<T, std::uint64_t>::value &&
+                              (sizeof(T) >= sizeof(long double) || sizeof(T) >= sizeof(long long)), void>::type
+      saveValue(T const & t)
+      {
+        std::stringstream ss; ss.precision( std::numeric_limits<long double>::max_digits10 );
+        ss << t;
+        saveValue( ss.str() );
+      }
+
+      //! Write the name of the upcoming node and prepare object/array state
+      /*! Since writeName is called for every value that is output, regardless of
+          whether it has a name or not, it is the place where we will do a deferred
+          check of our node state and decide whether we are in an array or an object.
+
+          The general workflow of saving to the JSON archive is:
+
+            1. (optional) Set the name for the next node to be created, usually done by an NVP
+            2. Start the node
+            3. (if there is data to save) Write the name of the node (this function)
+            4. (if there is data to save) Save the data (with saveValue)
+            5. Finish the node
+          */
+      void writeName()
+      {
+        NodeType const & nodeType = itsNodeStack.top();
+
+        // Start up either an object or an array, depending on state
+        if(nodeType == NodeType::StartArray)
+        {
+          itsWriter.StartArray();
+          itsNodeStack.top() = NodeType::InArray;
+        }
+        else if(nodeType == NodeType::StartObject)
+        {
+          itsNodeStack.top() = NodeType::InObject;
+          itsWriter.StartObject();
+        }
+
+        // Array types do not output names
+        if(nodeType == NodeType::InArray) return;
+
+        if(itsNextName == nullptr)
+        {
+          std::string name = "value" + std::to_string( itsNameCounter.top()++ ) + "\0";
+          saveValue(name);
+        }
+        else
+        {
+          saveValue(itsNextName);
+          itsNextName = nullptr;
+        }
+      }
+
+      //! Designates that the current node should be output as an array, not an object
+      void makeArray()
+      {
+        itsNodeStack.top() = NodeType::StartArray;
+      }
+
+      //! @}
+
+    private:
+      WriteStream itsWriteStream;          //!< Rapidjson write stream
+      JSONWriter itsWriter;                //!< Rapidjson writer
+      char const * itsNextName;            //!< The next name
+      std::stack<uint32_t> itsNameCounter; //!< Counter for creating unique names for unnamed nodes
+      std::stack<NodeType> itsNodeStack;
+  }; // JSONOutputArchive
+
+  // ######################################################################
+  //! An input archive designed to load data from JSON
+  /*! This archive uses RapidJSON to read in a JSON archive.
+
+      Input JSON should have been produced by the JSONOutputArchive.  Data can
+      only be added to dynamically sized containers (marked by JSON arrays) -
+      the input archive will determine their size by looking at the number of child nodes.
+      Only JSON originating from a JSONOutputArchive is officially supported, but data
+      from other sources may work if properly formatted.
+
+      The JSONInputArchive does not require that nodes are loaded in the same
+      order they were saved by JSONOutputArchive.  Using name value pairs (NVPs),
+      it is possible to load in an out of order fashion or otherwise skip/select
+      specific nodes to load.
+
+      The default behavior of the input archive is to read sequentially starting
+      with the first node and exploring its children.  When a given NVP does
+      not match the read in name for a node, the archive will search for that
+      node at the current level and load it if it exists.  After loading an out of
+      order node, the archive will then proceed back to loading sequentially from
+      its new position.
+
+      Consider this simple example where loading of some data is skipped:
+
+      @code{cpp}
+      // imagine the input file has someData(1-9) saved in order at the top level node
+      ar( someData1, someData2, someData3 );        // XML loads in the order it sees in the file
+      ar( cereal::make_nvp( "hello", someData6 ) ); // NVP given does not
+                                                    // match expected NVP name, so we search
+                                                    // for the given NVP and load that value
+      ar( someData7, someData8, someData9 );        // with no NVP given, loading resumes at its
+                                                    // current location, proceeding sequentially
+      @endcode
+
+      \ingroup Archives */
+  class JSONInputArchive : public InputArchive<JSONInputArchive>
+  {
+    private:
+      typedef rapidjson::GenericReadStream ReadStream;
+      typedef rapidjson::GenericValue<rapidjson::UTF8<>> JSONValue;
+      typedef JSONValue::ConstMemberIterator MemberIterator;
+      typedef JSONValue::ConstValueIterator ValueIterator;
+      typedef rapidjson::Document::GenericValue GenericValue;
+
+    public:
+      /*! @name Common Functionality
+          Common use cases for directly interacting with an JSONInputArchive */
+      //! @{
+
+      //! Construct, reading from the provided stream
+      /*! @param stream The stream to read from */
+      JSONInputArchive(std::istream & stream) :
+        InputArchive<JSONInputArchive>(this),
+        itsNextName( nullptr ),
+        itsReadStream(stream)
+      {
+        itsDocument.ParseStream<0>(itsReadStream);
+        itsIteratorStack.emplace_back(itsDocument.MemberBegin(), itsDocument.MemberEnd());
+      }
+
+      //! Loads some binary data, encoded as a base64 string
+      /*! This will automatically start and finish a node to load the data, and can be called directly by
+          users.
+
+          Note that this follows the same ordering rules specified in the class description in regards
+          to loading in/out of order */
+      void loadBinaryValue( void * data, size_t size, const char * name = nullptr )
+      {
+        itsNextName = name;
+
+        std::string encoded;
+        loadValue( encoded );
+        auto decoded = base64::decode( encoded );
+
+        if( size != decoded.size() )
+          throw Exception("Decoded binary data size does not match specified size");
+
+        std::memcpy( data, decoded.data(), decoded.size() );
+        itsNextName = nullptr;
+      };
+
+      // Intel Added this as a custom parsing hook for the AttributeValue map
+      void loadAttributeValues(std::map<std::string, OC::AttributeValue>& map);
+
+    private:
+      //! @}
+      /*! @name Internal Functionality
+          Functionality designed for use by those requiring control over the inner mechanisms of
+          the JSONInputArchive */
+      //! @{
+
+      //! An internal iterator that handles both array and object types
+      /*! This class is a variant and holds both types of iterators that
+          rapidJSON supports - one for arrays and one for objects. */
+      class Iterator
+      {
+        public:
+          friend class cereal::JSONInputArchive;
+          Iterator() : itsIndex( 0 ), itsType(Null_) {}
+
+          Iterator(MemberIterator begin, MemberIterator end) :
+            itsMemberItBegin(begin), itsMemberItEnd(end), itsIndex(0), itsType(Member)
+          { }
+
+          Iterator(ValueIterator begin, ValueIterator end) :
+            itsValueItBegin(begin), itsValueItEnd(end), itsIndex(0), itsType(Value)
+          { }
+
+          //! Advance to the next node
+          Iterator & operator++()
+          {
+            ++itsIndex;
+            return *this;
+          }
+
+          //! Get the value of the current node
+          GenericValue const & value()
+          {
+            switch(itsType)
+            {
+              case Value : return itsValueItBegin[itsIndex];
+              case Member: return itsMemberItBegin[itsIndex].value;
+              default: throw cereal::Exception("Invalid Iterator Type!");
+            }
+          }
+
+          //! Get the name of the current node, or nullptr if it has no name
+          const char * name() const
+          {
+            if( itsType == Member && (itsMemberItBegin + itsIndex) != itsMemberItEnd )
+              return itsMemberItBegin[itsIndex].name.GetString();
+            else
+              return nullptr;
+          }
+
+          //! Adjust our position such that we are at the node with the given name
+          /*! @throws Exception if no such named node exists */
+          inline void search( const char * searchName )
+          {
+            const auto len = std::strlen( searchName );
+            size_t index = 0;
+            for( auto it = itsMemberItBegin; it != itsMemberItEnd; ++it, ++index )
+              if( std::strncmp( searchName, it->name.GetString(), len ) == 0 )
+              {
+                itsIndex = index;
+                return;
+              }
+
+            throw Exception("JSON Parsing failed - provided NVP not found");
+          }
+
+        private:
+          MemberIterator itsMemberItBegin, itsMemberItEnd; //!< The member iterator (object)
+          ValueIterator itsValueItBegin, itsValueItEnd;    //!< The value iterator (array)
+          size_t itsIndex;                                 //!< The current index of this iterator
+          enum Type {Value, Member, Null_} itsType;    //!< Whether this holds values (array) or members (objects) or nothing
+      };
+
+      //! Searches for the expectedName node if it doesn't match the actualName
+      /*! This needs to be called before every load or node start occurs.  This function will
+          check to see if an NVP has been provided (with setNextName) and if so, see if that name matches the actual
+          next name given.  If the names do not match, it will search in the current level of the JSON for that name.
+          If the name is not found, an exception will be thrown.
+
+          Resets the NVP name after called.
+
+          @throws Exception if an expectedName is given and not found */
+      inline void search()
+      {
+        // The name an NVP provided with setNextName()
+        if( itsNextName )
+        {
+          // The actual name of the current node
+          auto const actualName = itsIteratorStack.back().name();
+
+          // Do a search if we don't see a name coming up, or if the names don't match
+          if( !actualName || std::strcmp( itsNextName, actualName ) != 0 )
+            itsIteratorStack.back().search( itsNextName );
+        }
+
+        itsNextName = nullptr;
+      }
+
+    public:
+      //! Starts a new node, going into its proper iterator
+      /*! This places an iterator for the next node to be parsed onto the iterator stack.  If the next
+          node is an array, this will be a value iterator, otherwise it will be a member iterator.
+
+          By default our strategy is to start with the document root node and then recursively iterate through
+          all children in the order they show up in the document.
+          We don't need to know NVPs to do this; we'll just blindly load in the order things appear in.
+
+          If we were given an NVP, we will search for it if it does not match our the name of the next node
+          that would normally be loaded.  This functionality is provided by search(). */
+      void startNode()
+      {
+        search();
+
+        if(itsIteratorStack.back().value().IsArray())
+          itsIteratorStack.emplace_back(itsIteratorStack.back().value().Begin(), itsIteratorStack.back().value().End());
+        else
+          itsIteratorStack.emplace_back(itsIteratorStack.back().value().MemberBegin(), itsIteratorStack.back().value().MemberEnd());
+      }
+
+      //! Finishes the most recently started node
+      void finishNode()
+      {
+        itsIteratorStack.pop_back();
+        ++itsIteratorStack.back();
+      }
+
+      //! Sets the name for the next node created with startNode
+      void setNextName( const char * name )
+      {
+        itsNextName = name;
+      }
+
+      //! Loads a value from the current node - small signed overload
+      template<class T> inline
+      typename std::enable_if<std::is_signed<T>::value && sizeof(T) < sizeof(int64_t), void>::type
+      loadValue(T & val)
+      {
+        search();
+
+        val = itsIteratorStack.back().value().GetInt();
+        ++itsIteratorStack.back();
+      }
+
+      //! Loads a value from the current node - small unsigned overload
+      template<class T> inline
+      typename std::enable_if<(std::is_unsigned<T>::value && sizeof(T) < sizeof(uint64_t)) &&
+                              !std::is_same<bool, T>::value, void>::type
+      loadValue(T & val)
+      {
+        search();
+
+        val = itsIteratorStack.back().value().GetUint();
+        ++itsIteratorStack.back();
+      }
+
+      //! Loads a value from the current node - bool overload
+      void loadValue(bool & val)        { search(); val = itsIteratorStack.back().value().GetBool_();   ++itsIteratorStack.back(); }
+      //! Loads a value from the current node - int64 overload
+      void loadValue(int64_t & val)     { search(); val = itsIteratorStack.back().value().GetInt64();  ++itsIteratorStack.back(); }
+      //! Loads a value from the current node - uint64 overload
+      void loadValue(uint64_t & val)    { search(); val = itsIteratorStack.back().value().GetUint64(); ++itsIteratorStack.back(); }
+      //! Loads a value from the current node - float overload
+      void loadValue(float & val)       { search(); val = static_cast<float>(itsIteratorStack.back().value().GetDouble()); ++itsIteratorStack.back(); }
+      //! Loads a value from the current node - double overload
+      void loadValue(double & val)      { search(); val = itsIteratorStack.back().value().GetDouble(); ++itsIteratorStack.back(); }
+      //! Loads a value from the current node - string overload
+      void loadValue(std::string & val) { search(); val = itsIteratorStack.back().value().GetString(); ++itsIteratorStack.back(); }
+
+    private:
+      //! Convert a string to a long long
+      void stringToNumber( std::string const & str, long long & val ) { val = std::stoll( str ); }
+      //! Convert a string to an unsigned long long
+      void stringToNumber( std::string const & str, unsigned long long & val ) { val = std::stoull( str ); }
+      //! Convert a string to a long double
+      void stringToNumber( std::string const & str, long double & val ) { val = std::stold( str ); }
+
+    public:
+      //! Loads a value from the current node - long double and long long overloads
+      template<class T> inline
+      typename std::enable_if<std::is_arithmetic<T>::value &&
+                              !std::is_same<T, long>::value &&
+                              !std::is_same<T, unsigned long>::value &&
+                              !std::is_same<T, std::int64_t>::value &&
+                              !std::is_same<T, std::uint64_t>::value &&
+                              (sizeof(T) >= sizeof(long double) || sizeof(T) >= sizeof(long long)), void>::type
+      loadValue(T & val)
+      {
+        std::string encoded;
+        loadValue( encoded );
+        stringToNumber( encoded, val );
+      }
+
+      //! Loads the size for a SizeTag
+      void loadSize(size_type & size)
+      {
+        size = (itsIteratorStack.rbegin() + 1)->value().Size();
+      }
+
+      //! @}
+
+    private:
+      const char * itsNextName;               //!< Next name set by NVP
+      ReadStream itsReadStream;               //!< Rapidjson write stream
+      std::vector<Iterator> itsIteratorStack; //!< 'Stack' of rapidJSON iterators
+      rapidjson::Document itsDocument;        //!< Rapidjson document
+  };
+
+  // ######################################################################
+  // JSONArchive prologue and epilogue functions
+  // ######################################################################
+
+  // ######################################################################
+  //! Prologue for NVPs for JSON archives
+  /*! NVPs do not start or finish nodes - they just set up the names */
+  template <class T> inline
+  void prologue( JSONOutputArchive &, NameValuePair<T> const & )
+  { }
+
+  //! Prologue for NVPs for JSON archives
+  template <class T> inline
+  void prologue( JSONInputArchive &, NameValuePair<T> const & )
+  { }
+
+  // ######################################################################
+  //! Epilogue for NVPs for JSON archives
+  /*! NVPs do not start or finish nodes - they just set up the names */
+  template <class T> inline
+  void epilogue( JSONOutputArchive &, NameValuePair<T> const & )
+  { }
+
+  //! Epilogue for NVPs for JSON archives
+  /*! NVPs do not start or finish nodes - they just set up the names */
+  template <class T> inline
+  void epilogue( JSONInputArchive &, NameValuePair<T> const & )
+  { }
+
+  // ######################################################################
+  //! Prologue for SizeTags for JSON archives
+  /*! SizeTags are strictly ignored for JSON, they just indicate
+      that the current node should be made into an array */
+  template <class T> inline
+  void prologue( JSONOutputArchive & ar, SizeTag<T> const & )
+  {
+    ar.makeArray();
+  }
+
+  //! Prologue for SizeTags for JSON archives
+  template <class T> inline
+  void prologue( JSONInputArchive &, SizeTag<T> const & )
+  { }
+
+  // ######################################################################
+  //! Epilogue for SizeTags for JSON archives
+  /*! SizeTags are strictly ignored for JSON */
+  template <class T> inline
+  void epilogue( JSONOutputArchive &, SizeTag<T> const & )
+  { }
+
+  //! Epilogue for SizeTags for JSON archives
+  template <class T> inline
+  void epilogue( JSONInputArchive &, SizeTag<T> const & )
+  { }
+
+  // ######################################################################
+  //! Prologue for all other types for JSON archives (except minimal types)
+  /*! Starts a new node, named either automatically or by some NVP,
+      that may be given data by the type about to be archived
+
+      Minimal types do not start or finish nodes */
+  template <class T> inline
+  typename std::enable_if<!std::is_arithmetic<T>::value &&
+                          !traits::has_minimal_output_serialization<T, JSONOutputArchive>::value, void>::type
+  prologue( JSONOutputArchive & ar, T const & )
+  {
+    ar.startNode();
+  }
+
+  //! Prologue for all other types for JSON archives
+  template <class T> inline
+  typename std::enable_if<!std::is_arithmetic<T>::value &&
+                          !traits::has_minimal_input_serialization<T, JSONOutputArchive>::value, void>::type
+  prologue( JSONInputArchive & ar, T const & )
+  {
+    ar.startNode();
+  }
+
+  // ######################################################################
+  //! Epilogue for all other types other for JSON archives (except minimal types
+  /*! Finishes the node created in the prologue
+
+      Minimal types do not start or finish nodes */
+  template <class T> inline
+  typename std::enable_if<!std::is_arithmetic<T>::value &&
+                          !traits::has_minimal_output_serialization<T, JSONOutputArchive>::value, void>::type
+  epilogue( JSONOutputArchive & ar, T const & )
+  {
+    ar.finishNode();
+  }
+
+  //! Epilogue for all other types other for JSON archives
+  template <class T> inline
+  typename std::enable_if<!std::is_arithmetic<T>::value &&
+                          !traits::has_minimal_input_serialization<T, JSONOutputArchive>::value, void>::type
+  epilogue( JSONInputArchive & ar, T const & )
+  {
+    ar.finishNode();
+  }
+
+  // ######################################################################
+  //! Prologue for arithmetic types for JSON archives
+  template <class T> inline
+  typename std::enable_if<std::is_arithmetic<T>::value, void>::type
+  prologue( JSONOutputArchive & ar, T const & )
+  {
+    ar.writeName();
+  }
+
+  //! Prologue for arithmetic types for JSON archives
+  template <class T> inline
+  typename std::enable_if<std::is_arithmetic<T>::value, void>::type
+  prologue( JSONInputArchive &, T const & )
+  { }
+
+  // ######################################################################
+  //! Epilogue for arithmetic types for JSON archives
+  template <class T> inline
+  typename std::enable_if<std::is_arithmetic<T>::value, void>::type
+  epilogue( JSONOutputArchive &, T const & )
+  { }
+
+  //! Epilogue for arithmetic types for JSON archives
+  template <class T> inline
+  typename std::enable_if<std::is_arithmetic<T>::value, void>::type
+  epilogue( JSONInputArchive &, T const & )
+  { }
+
+  // ######################################################################
+  //! Prologue for strings for JSON archives
+  template<class CharT, class Traits, class Alloc> inline
+  void prologue(JSONOutputArchive & ar, std::basic_string<CharT, Traits, Alloc> const &)
+  {
+    ar.writeName();
+  }
+
+  //! Prologue for strings for JSON archives
+  template<class CharT, class Traits, class Alloc> inline
+  void prologue(JSONInputArchive &, std::basic_string<CharT, Traits, Alloc> const &)
+  { }
+
+  // ######################################################################
+  //! Epilogue for strings for JSON archives
+  template<class CharT, class Traits, class Alloc> inline
+  void epilogue(JSONOutputArchive &, std::basic_string<CharT, Traits, Alloc> const &)
+  { }
+
+  //! Epilogue for strings for JSON archives
+  template<class CharT, class Traits, class Alloc> inline
+  void epilogue(JSONInputArchive &, std::basic_string<CharT, Traits, Alloc> const &)
+  { }
+
+  // ######################################################################
+  // Common JSONArchive serialization functions
+  // ######################################################################
+
+  //! Serializing NVP types to JSON
+  template <class T> inline
+  void save( JSONOutputArchive & ar, NameValuePair<T> const & t )
+  {
+    ar.setNextName( t.name );
+    ar( t.value );
+  }
+
+  template <class T> inline
+  void load( JSONInputArchive & ar, NameValuePair<T> & t )
+  {
+    ar.setNextName( t.name );
+    ar( t.value );
+  }
+
+  //! Saving for arithmetic to JSON
+  template<class T> inline
+  typename std::enable_if<std::is_arithmetic<T>::value, void>::type
+  save(JSONOutputArchive & ar, T const & t)
+  {
+    ar.saveValue( t );
+  }
+
+  //! Loading arithmetic from JSON
+  template<class T> inline
+  typename std::enable_if<std::is_arithmetic<T>::value, void>::type
+  load(JSONInputArchive & ar, T & t)
+  {
+    ar.loadValue( t );
+  }
+
+  //! saving string to JSON
+  template<class CharT, class Traits, class Alloc> inline
+  void save(JSONOutputArchive & ar, std::basic_string<CharT, Traits, Alloc> const & str)
+  {
+    ar.saveValue( str );
+  }
+
+  //! loading string from JSON
+  template<class CharT, class Traits, class Alloc> inline
+  void load(JSONInputArchive & ar, std::basic_string<CharT, Traits, Alloc> & str)
+  {
+    ar.loadValue( str );
+  }
+
+  // ######################################################################
+  //! Saving SizeTags to JSON
+  template <class T> inline
+  void save( JSONOutputArchive &, SizeTag<T> const & )
+  {
+    // nothing to do here, we don't explicitly save the size
+  }
+
+  //! Loading SizeTags from JSON
+  template <class T> inline
+  void load( JSONInputArchive & ar, SizeTag<T> & st )
+  {
+    ar.loadSize( st.size );
+  }
+} // namespace cereal
+
+// register archives for polymorphic support
+CEREAL_REGISTER_ARCHIVE(cereal::JSONInputArchive)
+CEREAL_REGISTER_ARCHIVE(cereal::JSONOutputArchive)
+
+#endif // CEREAL_ARCHIVES_JSON_HPP_
index 07f5c6a..dfae653 100644 (file)
@@ -28,9 +28,8 @@ namespace OC
     class OutOfProcClientWrapper : public IClientWrapper
     {
     public:
-        OutOfProcClientWrapper(OC::OCPlatform_impl& owner, std::weak_ptr<std::recursive_mutex> csdkLock,
+        OutOfProcClientWrapper(std::weak_ptr<std::recursive_mutex> csdkLock,
                                 PlatformConfig cfg)
-         : IClientWrapper(owner)
         {}
 
         virtual OCStackResult ListenForResource(const std::string& serviceUrl,
@@ -69,12 +68,6 @@ namespace OC
             const std::string& uri,
             const HeaderOptions& headerOptions, QualityOfService QoS){return OC_STACK_NOTIMPL;}
 
-        virtual std::shared_ptr<OCResource> parseOCResource(IClientWrapper::Ptr clientWrapper,
-            OCDevAddr& addr, const boost::property_tree::ptree resourceNode)
-        {
-            return nullptr;
-        }
-
         virtual OCStackResult SubscribePresence(OCDoHandle* handle, const std::string& host,
             const std::string& resourceType, SubscribeCallback& presenceHandler)
         {return OC_STACK_NOTIMPL;}
index 9f3b09c..a38e83c 100644 (file)
@@ -28,9 +28,8 @@ namespace OC
     class OutOfProcServerWrapper : public IServerWrapper
     {
     public:
-        OutOfProcServerWrapper(OC::OCPlatform_impl& owner, PlatformConfig cfg)
-         : IServerWrapper(owner)
-        {};
+        OutOfProcServerWrapper(PlatformConfig cfg)
+        {}
 
         virtual OCStackResult registerResource(
                     OCResourceHandle& resourceHandle,
index a3ebea6..c045b6c 100644 (file)
@@ -30,11 +30,32 @@ namespace OC
     class ResourceInitException : public std::exception
     {
     public:
-        ResourceInitException(bool missingUri, bool missingType, bool missingInterface, bool missingClientWrapper)
-        : m_missingUri(missingUri), m_missingType(missingType), m_missingInterface(missingInterface), m_missingClientWrapper(missingClientWrapper)
+        ResourceInitException(
+                bool missingUri,
+                bool missingType,
+                bool missingInterface,
+                bool missingClientWrapper,
+                bool invalidPort,
+                bool invalidIp)
+        : m_missingUri(missingUri),
+          m_missingType(missingType),
+          m_missingInterface(missingInterface),
+          m_missingClientWrapper(missingClientWrapper),
+          m_invalidPort(invalidPort),
+          m_invalidIp(invalidIp)
         {
         }
 
+        bool isInvalidPort() const
+        {
+            return m_invalidPort;
+        }
+
+        bool isInvalidIp() const
+        {
+            return m_invalidIp;
+        }
+
         bool isClientWrapperMissing() const
         {
             return m_missingClientWrapper;
@@ -79,6 +100,16 @@ namespace OC
                 ret += OC::InitException::MISSING_CLIENT_WRAPPER;
             }
 
+            if(isInvalidPort())
+            {
+                ret += OC::InitException::INVALID_PORT;
+            }
+
+            if(isInvalidIp())
+            {
+                ret += OC::InitException::INVALID_IP;
+            }
+
             return ret.c_str();
         }
 
@@ -88,6 +119,8 @@ namespace OC
         bool m_missingType;
         bool m_missingInterface;
         bool m_missingClientWrapper;
+        bool m_invalidPort;
+        bool m_invalidIp;
     };
 }
 
index e8b4b5a..b169726 100644 (file)
@@ -92,7 +92,12 @@ namespace OC
         static const std::string GENERAL_FAULT              = "General Fault";
         static const std::string MALFORMED_STACK_RESPONSE   = "Response from OC_STACK is malformed";
         static const std::string UNKNOWN_ERROR              = "Unknown Error";
-
+        static const std::string INVALID_REPRESENTATION     = "Invalid Payload JSON";
+        static const std::string INVALID_JSON_TYPE          = "Unrecognized JSON Type ";
+        static const std::string INVALID_JSON_NUMERIC       = "Unrecognized JSON Numeric ";
+        static const std::string INVALID_JSON_ARRAY_DEPTH   = "Max JSON Array Depth exceeded";
+        static const std::string INVALID_JSON_TYPE_TAG      = "Invalid JSON Type Tag";
+        static const std::string INVALID_ATTRIBUTE          = "Invalid Attribute: ";
     }
 
     namespace Error
index 5aa23a2..2f15b80 100644 (file)
@@ -39,9 +39,9 @@ namespace OC
     public:
         typedef std::shared_ptr<IWrapperFactory> Ptr;
 
-        virtual IClientWrapper::Ptr CreateClientWrapper(OC::OCPlatform_impl& owner,
+        virtual IClientWrapper::Ptr CreateClientWrapper(
             std::weak_ptr<std::recursive_mutex> csdkLock, PlatformConfig cfg) =0;
-        virtual IServerWrapper::Ptr CreateServerWrapper(OC::OCPlatform_impl& owner,
+        virtual IServerWrapper::Ptr CreateServerWrapper(
             std::weak_ptr<std::recursive_mutex> csdkLock, PlatformConfig cfg) =0;
         virtual ~IWrapperFactory(){}
     };
@@ -52,28 +52,28 @@ namespace OC
     public:
         WrapperFactory(){}
 
-        virtual IClientWrapper::Ptr CreateClientWrapper(OC::OCPlatform_impl& owner,
+        virtual IClientWrapper::Ptr CreateClientWrapper(
             std::weak_ptr<std::recursive_mutex> csdkLock, PlatformConfig cfg)
         {
             switch(cfg.serviceType)
             {
             case ServiceType::InProc:
-                return std::make_shared<InProcClientWrapper>(owner, csdkLock, cfg);
+                return std::make_shared<InProcClientWrapper>(csdkLock, cfg);
                 break;
             case ServiceType::OutOfProc:
-                return std::make_shared<OutOfProcClientWrapper>(owner, csdkLock, cfg);
+                return std::make_shared<OutOfProcClientWrapper>(csdkLock, cfg);
                 break;
             }
                        return nullptr;
         }
 
-        virtual IServerWrapper::Ptr CreateServerWrapper(OC::OCPlatform_impl& owner,
+        virtual IServerWrapper::Ptr CreateServerWrapper(
             std::weak_ptr<std::recursive_mutex> csdkLock, PlatformConfig cfg)
         {
             switch(cfg.serviceType)
             {
             case ServiceType::InProc:
-                return std::make_shared<InProcServerWrapper>(owner, csdkLock, cfg);
+                return std::make_shared<InProcServerWrapper>(csdkLock, cfg);
                 break;
             case ServiceType::OutOfProc:
                 throw OC::OCException(OC::Exception::SVCTYPE_OUTOFPROC, OC_STACK_NOTIMPL);
index 3d3d3bd..a710781 100644 (file)
@@ -31,6 +31,9 @@ ifeq ($(PLATFORM), )
        PLATFORM := "linux"
 endif
 
+DEPEND_DIR:= $(ROOT_DIR)/dependencies
+CEREAL_DIR:= $(DEPEND_DIR)/cereal
+
 OUT_DIR          := $(ROOT_DIR)/$(BUILD)
 OBJ_DIR          := $(OUT_DIR)/obj
 
@@ -45,20 +48,34 @@ CXX_INC       += -I./csdk/ocsocket/include
 CXX_INC          += -I./csdk/ocrandom/include
 CXX_INC          += -I./csdk/logger/include
 CXX_INC          += -I./csdk/libcoap
-
+CXX_INC   += -I$(CEREAL_DIR)/include
 # Force metatargets to build:
-all.PHONY: prep_dirs c_sdk oc_logger_target liboc.a examples
+all.PHONY: applyDepPatches prep_dirs c_sdk oc_logger_target liboc.a examples
 
-buildScript_all.PHONY: prep_dirs oc_logger_target liboc.a
+buildScript_all.PHONY: applyDepPatches prep_dirs oc_logger_target liboc.a
 
 all:   all.PHONY
 
 buildScript_all:  buildScript_all.PHONY
 
-prep_dirs:
+prep_dirs: deps
        -mkdir -p $(OUT_DIR)
        -mkdir -p $(OBJ_DIR)
 
+# used to fetch all dependencies
+deps:
+       -mkdir -p $(DEPEND_DIR)
+#cereal fetch
+       if [ ! -d "$(CEREAL_DIR)" ]; then\
+               cd $(DEPEND_DIR) && git clone https://github.com/USCiLab/cereal.git;\
+               cd $(CEREAL_DIR) && git checkout 7121e91e6ab8c3e6a6516d9d9c3e6804e6f65245;\
+       fi
+
+applyDepPatches: deps
+#reset git to the 'base version', so we can apply our patch without issues
+       cd $(CEREAL_DIR) && git reset --hard 7121e91e6ab8c3e6a6516d9d9c3e6804e6f65245;
+       cd $(CEREAL_DIR) && git apply $(ROOT_DIR)/patches/cereal_gcc46.patch
+
 c_sdk:
        cd csdk && $(MAKE) "BUILD=$(BUILD)" "PLATFORM=$(PLATFORM)"
 
@@ -70,8 +87,8 @@ cpp_sdk: prep_dirs c_sdk liboc.a
 examples: liboc.a
        cd examples && $(MAKE) apps "BUILD=$(BUILD)"
 
-liboc.a: OCPlatform_impl.o OCPlatform.o OCResource.o OCException.o OCUtilities.o InProcServerWrapper.o InProcClientWrapper.o
-       ar -cvq $(OBJ_DIR)/liboc.a $(OBJ_DIR)/OCPlatform_impl.o $(OBJ_DIR)/OCPlatform.o $(OBJ_DIR)/OCResource.o $(OBJ_DIR)/OCException.o $(OBJ_DIR)/OCUtilities.o $(OBJ_DIR)/InProcServerWrapper.o $(OBJ_DIR)/InProcClientWrapper.o
+liboc.a: OCPlatform_impl.o OCPlatform.o OCResource.o OCException.o OCUtilities.o InProcServerWrapper.o InProcClientWrapper.o OCRepresentation.o
+       ar -cvq $(OBJ_DIR)/liboc.a $(OBJ_DIR)/OCPlatform_impl.o $(OBJ_DIR)/OCPlatform.o $(OBJ_DIR)/OCResource.o $(OBJ_DIR)/OCException.o $(OBJ_DIR)/OCUtilities.o $(OBJ_DIR)/InProcServerWrapper.o $(OBJ_DIR)/InProcClientWrapper.o $(OBJ_DIR)/OCRepresentation.o
 
 OCPlatform_impl.o: src/OCPlatform_impl.cpp
        $(CXX) $(CXX_FLAGS.$(BUILD)) -o $(OBJ_DIR)/$@ -c src/OCPlatform_impl.cpp $(CXX_INC)
@@ -79,6 +96,9 @@ OCPlatform_impl.o: src/OCPlatform_impl.cpp
 OCPlatform.o: src/OCPlatform.cpp
        $(CXX) $(CXX_FLAGS.$(BUILD)) -o $(OBJ_DIR)/$@ -c src/OCPlatform.cpp $(CXX_INC)
 
+OCRepresentation.o: src/OCRepresentation.cpp
+       $(CXX) $(CXX_FLAGS.$(BUILD)) -o $(OBJ_DIR)/$@ -c src/OCRepresentation.cpp $(CXX_INC)
+
 OCResource.o: src/OCResource.cpp
        $(CXX) $(CXX_FLAGS.$(BUILD)) -o $(OBJ_DIR)/$@ -c src/OCResource.cpp $(CXX_INC)
 
diff --git a/resource/patches/cereal_gcc46.patch b/resource/patches/cereal_gcc46.patch
new file mode 100644 (file)
index 0000000..c4da84f
--- /dev/null
@@ -0,0 +1,485 @@
+From 17300ee96e42f8848d27db6fc97f04de293662d8 Mon Sep 17 00:00:00 2001
+From: Erich Keane <erich.keane@intel.com>
+Date: Thu, 6 Nov 2014 14:37:00 -0800
+Subject: [PATCH] Get this to work on g++4.6.3
+
+---
+ include/cereal/cereal.hpp                  |  2 +-
+ include/cereal/details/helpers.hpp         | 32 ++++++++--------
+ include/cereal/details/traits.hpp          | 61 +++++++++++++++++-------------
+ include/cereal/external/rapidjson/reader.h | 13 ++-----
+ include/cereal/external/rapidjson/writer.h | 12 ++----
+ include/cereal/types/common.hpp            | 19 +++++++---
+ include/cereal/types/memory.hpp            | 10 ++---
+ 7 files changed, 77 insertions(+), 72 deletions(-)
+
+diff --git a/include/cereal/cereal.hpp b/include/cereal/cereal.hpp
+index b2858af..a219729 100644
+--- a/include/cereal/cereal.hpp
++++ b/include/cereal/cereal.hpp
+@@ -856,7 +856,7 @@ namespace cereal
+           std::uint32_t version;
+           process( make_nvp<ArchiveType>("cereal_class_version", version) );
+-          itsVersionedTypes.emplace_hint( lookupResult, hash, version );
++          itsVersionedTypes.insert( lookupResult, std::pair<std::size_t, std::uint32_t>(hash, version) );
+           return version;
+         }
+diff --git a/include/cereal/details/helpers.hpp b/include/cereal/details/helpers.hpp
+index e792d44..60e13c8 100644
+--- a/include/cereal/details/helpers.hpp
++++ b/include/cereal/details/helpers.hpp
+@@ -55,7 +55,7 @@ namespace cereal
+   /*! To ensure compatability between 32, 64, etc bit machines, we need to use
+    * a fixed size type instead of size_t, which may vary from machine to
+    * machine. */
+-  using size_type = uint64_t;
++   typedef uint64_t size_type;
+   // forward decls
+   class BinaryOutputArchive;
+@@ -138,12 +138,12 @@ namespace cereal
+       // otherwise, we store a reference.  If we were passed an array, don't
+       // decay the type - keep it as an array, and then proceed as normal
+       // with the RValue business
+-      using DT = typename std::conditional<std::is_array<typename std::remove_reference<T>::type>::value,
++      typedef typename std::conditional<std::is_array<typename std::remove_reference<T>::type>::value,
+                                            typename std::remove_cv<T>::type,
+-                                           typename std::decay<T>::type>::type;
+-      using Type = typename std::conditional<std::is_rvalue_reference<T>::value,
++                                           typename std::decay<T>::type>::type DT;
++      typedef typename std::conditional<std::is_rvalue_reference<T>::value,
+                                              DT,
+-                                             typename std::add_lvalue_reference<DT>::type>::type;
++                                             typename std::add_lvalue_reference<DT>::type>::type Type;
+       // prevent nested nvps
+       static_assert( !std::is_base_of<detail::NameValuePairCore, T>::value,
+                      "Cannot pair a name to a NameValuePair" );
+@@ -207,9 +207,9 @@ namespace cereal
+   {
+     //! Internally store the pointer as a void *, keeping const if created with
+     //! a const pointer
+-    using PT = typename std::conditional<std::is_const<typename std::remove_pointer<T>::type>::value,
++    typedef typename std::conditional<std::is_const<typename std::remove_pointer<T>::type>::value,
+                                          const void *,
+-                                         void *>::type;
++                                         void *>::type PT;
+     BinaryData( T && d, uint64_t s ) : data(d), size(s) {}
+@@ -248,10 +248,10 @@ namespace cereal
+     private:
+       // If we get passed an RValue, we'll just make a local copy if it here
+       // otherwise, we store a reference
+-      using DT = typename std::decay<T>::type;
+-      using Type = typename std::conditional<std::is_rvalue_reference<T>::value,
++      typedef typename std::decay<T>::type DT;
++      typedef typename std::conditional<std::is_rvalue_reference<T>::value,
+                                              DT,
+-                                             typename std::add_lvalue_reference<DT>::type>::type;
++                                             typename std::add_lvalue_reference<DT>::type>::type Type;
+     public:
+       SizeTag( T && sz ) : size(const_cast<Type>(sz)) {}
+@@ -283,17 +283,17 @@ namespace cereal
+   template <class Key, class Value>
+   struct MapItem
+   {
+-    using DecayKey = typename std::decay<Key>::type;
+-    using KeyType = typename std::conditional<
++    typedef typename std::decay<Key>::type DecayKey;
++    typedef typename std::conditional<
+       std::is_rvalue_reference<Key>::value,
+       DecayKey,
+-      typename std::add_lvalue_reference<DecayKey>::type>::type;
++      typename std::add_lvalue_reference<DecayKey>::type>::type KeyType;
+-    using DecayValue = typename std::decay<Value>::type;
+-    using ValueType =  typename std::conditional<
++    typedef typename std::decay<Value>::type DecayValue;
++    typedef  typename std::conditional<
+       std::is_rvalue_reference<Value>::value,
+       DecayValue,
+-      typename std::add_lvalue_reference<DecayValue>::type>::type;
++      typename std::add_lvalue_reference<DecayValue>::type>::type ValueType;
+     //! Construct a MapItem from a key and a value
+     /*! @internal */
+diff --git a/include/cereal/details/traits.hpp b/include/cereal/details/traits.hpp
+index 871886f..011054b 100644
+--- a/include/cereal/details/traits.hpp
++++ b/include/cereal/details/traits.hpp
+@@ -411,12 +411,12 @@ namespace cereal
+       };
+       template <class T, class A, bool Valid>
+-      struct get_member_save_minimal_type { using type = void; };
++      struct get_member_save_minimal_type { typedef void type; };
+       template <class T, class A>
+       struct get_member_save_minimal_type<T, A, true>
+       {
+-        using type = decltype( cereal::access::member_save_minimal( std::declval<A const &>(), std::declval<T const &>() ) );
++        typedef decltype( cereal::access::member_save_minimal( std::declval<A const &>(), std::declval<T const &>() ) ) type;
+       };
+     } // end namespace detail
+@@ -428,7 +428,7 @@ namespace cereal
+         "cereal detected a non-const member save_minimal.  "
+         "save_minimal member functions must always be const" );
+-      using type = typename detail::get_member_save_minimal_type<T, A, check::value>::type;
++      typedef typename detail::get_member_save_minimal_type<T, A, check::value>::type type;
+       static_assert( (check::value && is_minimal_type<type>::value) || !check::value,
+         "cereal detected a member save_minimal with an invalid return type.  "
+         "return type must be arithmetic or string" );
+@@ -473,12 +473,12 @@ namespace cereal
+       };
+       template <class T, class A, bool Valid>
+-      struct get_member_versioned_save_minimal_type { using type = void; };
++      struct get_member_versioned_save_minimal_type { typedef void type; };
+       template <class T, class A>
+       struct get_member_versioned_save_minimal_type<T, A, true>
+       {
+-        using type = decltype( cereal::access::member_save_minimal( std::declval<A const &>(), std::declval<T const &>(), 0 ) );
++        typedef decltype( cereal::access::member_save_minimal( std::declval<A const &>(), std::declval<T const &>(), 0 ) ) type;
+       };
+     } // end namespace detail
+@@ -490,7 +490,7 @@ namespace cereal
+         "cereal detected a versioned non-const member save_minimal.  "
+         "save_minimal member functions must always be const" );
+-      using type = typename detail::get_member_versioned_save_minimal_type<T, A, check::value>::type;
++      typedef typename detail::get_member_versioned_save_minimal_type<T, A, check::value>::type type;
+       static_assert( (check::value && is_minimal_type<type>::value) || !check::value,
+         "cereal detected a versioned member save_minimal with an invalid return type.  "
+         "return type must be arithmetic or string" );
+@@ -519,12 +519,12 @@ namespace cereal
+       };
+       template <class T, class A, bool Valid>
+-      struct get_non_member_save_minimal_type { using type = void; };
++      struct get_non_member_save_minimal_type { typedef void type; };
+       template <class T, class A>
+       struct get_non_member_save_minimal_type <T, A, true>
+       {
+-        using type = decltype( save_minimal( std::declval<A const &>(), std::declval<T const &>() ) );
++        typedef decltype( save_minimal( std::declval<A const &>(), std::declval<T const &>() ) ) type;
+       };
+     } // end namespace detail
+@@ -536,7 +536,7 @@ namespace cereal
+         "cereal detected a non-const type parameter in non-member save_minimal.  "
+         "save_minimal non-member functions must always pass their types as const" );
+-      using type = typename detail::get_non_member_save_minimal_type<T, A, check::value>::type;
++      typedef typename detail::get_non_member_save_minimal_type<T, A, check::value>::type type;
+       static_assert( (check::value && is_minimal_type<type>::value) || !check::value,
+         "cereal detected a non-member save_minimal with an invalid return type.  "
+         "return type must be arithmetic or string" );
+@@ -565,12 +565,12 @@ namespace cereal
+       };
+       template <class T, class A, bool Valid>
+-      struct get_non_member_versioned_save_minimal_type { using type = void; };
++      struct get_non_member_versioned_save_minimal_type { typedef void type; };
+       template <class T, class A>
+       struct get_non_member_versioned_save_minimal_type <T, A, true>
+       {
+-        using type = decltype( save_minimal( std::declval<A const &>(), std::declval<T const &>(), 0 ) );
++        typedef decltype( save_minimal( std::declval<A const &>(), std::declval<T const &>(), 0 ) ) type;
+       };
+     } // end namespace detail
+@@ -582,7 +582,7 @@ namespace cereal
+         "cereal detected a non-const type parameter in versioned non-member save_minimal.  "
+         "save_minimal non-member functions must always pass their types as const" );
+-      using type = typename detail::get_non_member_versioned_save_minimal_type<T, A, check::value>::type;
++      typedef typename detail::get_non_member_versioned_save_minimal_type<T, A, check::value>::type type;
+       static_assert( (check::value && is_minimal_type<type>::value) || !check::value,
+         "cereal detected a non-member versioned save_minimal with an invalid return type.  "
+         "return type must be arithmetic or string" );
+@@ -608,7 +608,7 @@ namespace cereal
+       template <class Source>
+       struct NoConvertConstRef : NoConvertBase
+       {
+-        using type = Source; //!< Used to get underlying type easily
++        typedef Source type; //!< Used to get underlying type easily
+         template <class Dest, class = typename std::enable_if<std::is_same<Source, Dest>::value>::type>
+         operator Dest () = delete;
+@@ -626,7 +626,7 @@ namespace cereal
+       template <class Source>
+       struct NoConvertRef : NoConvertBase
+       {
+-        using type = Source; //!< Used to get underlying type easily
++        typedef Source type; //!< Used to get underlying type easily
+         template <class Dest, class = typename std::enable_if<std::is_same<Source, Dest>::value>::type>
+         operator Dest () = delete;
+@@ -698,7 +698,7 @@ namespace cereal
+           "cereal detected member load_minimal but no valid member save_minimal.  "
+           "cannot evaluate correctness of load_minimal without valid save_minimal." );
+-        using SaveType = typename detail::get_member_save_minimal_type<T, A, true>::type;
++        typedef typename detail::get_member_save_minimal_type<T, A, true>::type SaveType;
+         const static bool value = has_member_load_minimal_impl<T, A>::value;
+         const static bool valid = has_member_load_minimal_type_impl<T, A, SaveType>::value;
+@@ -759,7 +759,7 @@ namespace cereal
+           "cereal detected member versioned load_minimal but no valid member versioned save_minimal.  "
+           "cannot evaluate correctness of load_minimal without valid save_minimal." );
+-        using SaveType = typename detail::get_member_versioned_save_minimal_type<T, A, true>::type;
++        typedef typename detail::get_member_versioned_save_minimal_type<T, A, true>::type SaveType;
+         const static bool value = has_member_versioned_load_minimal_impl<T, A>::value;
+         const static bool valid = has_member_versioned_load_minimal_type_impl<T, A, SaveType>::value;
+@@ -814,8 +814,8 @@ namespace cereal
+           "cereal detected non-member load_minimal but no valid non-member save_minimal.  "
+           "cannot evaluate correctness of load_minimal without valid save_minimal." );
+-        using SaveType = typename detail::get_non_member_save_minimal_type<T, A, true>::type;
+-        using check = has_non_member_load_minimal_impl<T, A, SaveType>;
++        typedef typename detail::get_non_member_save_minimal_type<T, A, true>::type SaveType;
++        typedef has_non_member_load_minimal_impl<T, A, SaveType> check;
+         static const bool value = check::exists;
+         static_assert( check::valid || !check::exists, "cereal detected different types in corresponding non-member load_minimal and save_minimal functions.  "
+@@ -866,8 +866,8 @@ namespace cereal
+           "cereal detected non-member versioned load_minimal but no valid non-member versioned save_minimal.  "
+           "cannot evaluate correctness of load_minimal without valid save_minimal." );
+-        using SaveType = typename detail::get_non_member_versioned_save_minimal_type<T, A, true>::type;
+-        using check = has_non_member_versioned_load_minimal_impl<T, A, SaveType>;
++        typedef typename detail::get_non_member_versioned_save_minimal_type<T, A, true>::type SaveType;
++        typedef has_non_member_versioned_load_minimal_impl<T, A, SaveType> check;;
+         static const bool value = check::exists;
+         static_assert( check::valid || !check::exists, "cereal detected different types in corresponding non-member versioned load_minimal and save_minimal functions.  "
+@@ -1182,9 +1182,16 @@ namespace cereal
+       };
+     }
++    // works around the lack of decltype inheritance in GCC 4.6
++    template<class T>
++    struct shared_wrapper
++    {
++       typedef decltype(detail::shared_from_this_wrapper::check(std::declval<T>())) type;
++
++    };
+     //! Determine if T or any base class of T has inherited from std::enable_shared_from_this
+     template<class T>
+-    struct has_shared_from_this : decltype(detail::shared_from_this_wrapper::check(std::declval<T>()))
++    struct has_shared_from_this : shared_wrapper<T>::type
+     { };
+     //! Get the type of the base class of T which inherited from std::enable_shared_from_this
+@@ -1192,10 +1199,10 @@ namespace cereal
+     struct get_shared_from_this_base
+     {
+       private:
+-        using PtrType = decltype(detail::shared_from_this_wrapper::get(std::declval<T>()));
++        typedef decltype(detail::shared_from_this_wrapper::get(std::declval<T>())) PtrType;
+       public:
+         //! The type of the base of T that inherited from std::enable_shared_from_this
+-        using type = typename std::decay<typename PtrType::element_type>::type;
++        typedef typename std::decay<typename PtrType::element_type>::type type;
+     };
+     // ######################################################################
+@@ -1209,14 +1216,14 @@ namespace cereal
+     template <class T, bool IsCerealMinimalTrait = std::is_base_of<detail::NoConvertBase, T>::value>
+     struct strip_minimal
+     {
+-      using type = T;
++      typedef T type;
+     };
+     //! Specialization for types wrapped in a NoConvert
+     template <class T>
+     struct strip_minimal<T, true>
+     {
+-      using type = typename T::type;
++      typedef typename T::type type;
+     };
+   } // namespace traits
+@@ -1232,10 +1239,12 @@ namespace cereal
+       { return nullptr; }
+     };
++    template<class T>
++    struct is_default_constructible : std::is_constructible<T>{};
+     template <class T, class A>
+     struct Construct<T, A, false, false>
+     {
+-      static_assert( std::is_default_constructible<T>::value,
++      static_assert( is_default_constructible<T>::value,
+                      "Trying to serialize a an object with no default constructor. \n\n "
+                      "Types must either be default constructible or define either a member or non member Construct function. \n "
+                      "Construct functions generally have the signature: \n\n "
+diff --git a/include/cereal/external/rapidjson/reader.h b/include/cereal/external/rapidjson/reader.h
+index 7790907..3ee838c 100644
+--- a/include/cereal/external/rapidjson/reader.h
++++ b/include/cereal/external/rapidjson/reader.h
+@@ -402,20 +402,13 @@ private:
+       }
+   // cereal Temporary until constexpr support is added in RTM
+-#ifdef _MSC_VER
++//#ifdef _MSC_VER
+   template <class Ch>
+   bool characterOk( Ch c )
+   {
+     return c < 256;
+   }
+-
+-  template <>
+-  bool characterOk<char>( Ch )
+-  {
+-    return true;
+-  }
+-
+-#else
++/*#else
+   // As part of a fix for GCC 4.7
+   template <class T>
+   static constexpr int to_int( T t ){ return t; }
+@@ -432,7 +425,7 @@ private:
+     characterOk(Ch c)
+   { return c < 256; }
+ #endif
+-
++*/
+       // Parse string, handling the prefix and suffix double quotes and escaping.
+       template<unsigned parseFlags, typename Stream, typename Handler>
+       void ParseString(Stream& stream, Handler& handler) {
+diff --git a/include/cereal/external/rapidjson/writer.h b/include/cereal/external/rapidjson/writer.h
+index 0f87255..e02c27a 100644
+--- a/include/cereal/external/rapidjson/writer.h
++++ b/include/cereal/external/rapidjson/writer.h
+@@ -177,20 +177,14 @@ protected:
+       }
+   // cereal Temporary until constexpr support is added in RTM
+-#ifdef _MSC_VER
++//#ifdef _MSC_VER
+   template <class Ch>
+   bool characterOk( Ch c )
+   {
+     return c < 256;
+   }
+-  template <>
+-  bool characterOk<char>( Ch )
+-  {
+-    return true;
+-  }
+-
+-#else
++/*#else
+   // As part of a fix for GCC 4.7
+   template <class T>
+   static constexpr int to_int( T t ){ return t; }
+@@ -206,7 +200,7 @@ protected:
+   typename std::enable_if< to_int(std::numeric_limits<Ch>::max()) >= to_int(256), bool>::type
+     characterOk(Ch c)
+   { return c < 256; }
+-#endif
++#endif*/
+       //! \todo Optimization with custom double-to-string converter.
+       void WriteDouble(double d) {
+diff --git a/include/cereal/types/common.hpp b/include/cereal/types/common.hpp
+index abb8bfd..5c014cd 100644
+--- a/include/cereal/types/common.hpp
++++ b/include/cereal/types/common.hpp
+@@ -55,6 +55,15 @@ namespace cereal
+     namespace
+     {
++      template<class en>
++      struct underlying_type
++      {
++          typedef typename std::conditional<
++                  en(-1)<en(0),
++                  typename std::make_signed<en>::type,
++                  typename std::make_unsigned<en>::type
++                  > ::type type;
++      };
+       //! Gets the underlying type of an enum
+       /*! @internal */
+       template <class T, bool IsEnum>
+@@ -64,7 +73,7 @@ namespace cereal
+       /*! Specialization for when we actually have an enum
+           @internal */
+       template <class T>
+-      struct enum_underlying_type<T, true> { using type = typename std::underlying_type<T>::type; };
++      struct enum_underlying_type<T, true> { typedef typename underlying_type<T>::type type; };
+     } // anon namespace
+     //! Checks if a type is an enum
+@@ -78,13 +87,13 @@ namespace cereal
+     class is_enum
+     {
+       private:
+-        using DecayedT  = typename std::decay<T>::type;
+-        using StrippedT = typename ::cereal::traits::strip_minimal<DecayedT>::type;
++        typedef typename std::decay<T>::type DecayedT;
++        typedef typename ::cereal::traits::strip_minimal<DecayedT>::type StrippedT;
+       public:
+         static const bool value = std::is_enum<StrippedT>::value;
+-        using type = StrippedT;
+-        using base_type = typename enum_underlying_type<StrippedT, value>::type;
++        typedef StrippedT type;
++        typedef typename enum_underlying_type<StrippedT, value>::type base_type;
+     };
+   }
+diff --git a/include/cereal/types/memory.hpp b/include/cereal/types/memory.hpp
+index bf56c92..d2357ff 100644
+--- a/include/cereal/types/memory.hpp
++++ b/include/cereal/types/memory.hpp
+@@ -115,9 +115,9 @@ namespace cereal
+     class EnableSharedStateHelper
+     {
+       // typedefs for parent type and storage type
+-      using BaseType = typename ::cereal::traits::get_shared_from_this_base<T>::type;
+-      using ParentType = std::enable_shared_from_this<BaseType>;
+-      using StorageType = typename std::aligned_storage<sizeof(ParentType)>::type;
++      typedef typename ::cereal::traits::get_shared_from_this_base<T>::type BaseType;
++      typedef std::enable_shared_from_this<BaseType> ParentType;
++      typedef typename std::aligned_storage<sizeof(ParentType)>::type StorageType;
+       public:
+         //! Saves the state of some type inheriting from enable_shared_from_this
+@@ -257,7 +257,7 @@ namespace cereal
+     {
+       // Storage type for the pointer - since we can't default construct this type,
+       // we'll allocate it using std::aligned_storage and use a custom deleter
+-      using ST = typename std::aligned_storage<sizeof(T)>::type;
++      typedef typename std::aligned_storage<sizeof(T)>::type ST;
+       // Valid flag - set to true once construction finishes
+       //  This prevents us from calling the destructor on
+@@ -345,7 +345,7 @@ namespace cereal
+     {
+       // Storage type for the pointer - since we can't default construct this type,
+       // we'll allocate it using std::aligned_storage
+-      using ST = typename std::aligned_storage<sizeof(T)>::type;
++      typedef typename std::aligned_storage<sizeof(T)>::type ST;
+       // Allocate storage - note the ST type so that deleter is correct if
+       //                    an exception is thrown before we are initialized
+-- 
+1.9.3
+
index 6225119..0072783 100644 (file)
 //
 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 
-#include <new>
-
 #include "InProcClientWrapper.h"
 #include "ocstack.h"
 
 #include "OCPlatform.h"
 #include "OCResource.h"
-
+#include <OCSerialization.h>
 using namespace std;
 
 namespace OC
 {
-    InProcClientWrapper::InProcClientWrapper(OC::OCPlatform_impl& owner,
+    InProcClientWrapper::InProcClientWrapper(
         std::weak_ptr<std::recursive_mutex> csdkLock, PlatformConfig cfg)
-            : IClientWrapper(owner),
-              m_threadRun(false), m_csdkLock(csdkLock),
-              m_owner(owner),
+            : m_threadRun(false), m_csdkLock(csdkLock),
               m_cfg { cfg }
     {
         // if the config type is server, we ought to never get called.  If the config type
@@ -91,90 +87,11 @@ namespace OC
         }
     }
 
-    std::string InProcClientWrapper::convertOCAddrToString(OCDevAddr& addr,
-        OCSecureType type, const std::string &portStr)
-    {
-        // TODO: we currently assume this is a IPV4 address, need to figure out the actual value
-
-        uint8_t a, b, c, d;
-        uint16_t port;
-
-        if(OCDevAddrToIPv4Addr(&addr, &a, &b, &c, &d) ==0 && OCDevAddrToPort(&addr, &port)==0)
-        {
-            ostringstream os;
-            if(type == OCSecureType::IPV4)
-            {
-                os << "coap://" << static_cast<int>(a) << '.' <<
-                    static_cast<int>(b) << '.' << static_cast<int>(c) <<
-                    '.' << static_cast<int>(d) << ':' <<static_cast<int>(port);
-            }
-            else if(type == OCSecureType::IPV4Secure)
-            {
-                 os << "coaps://" << static_cast<int>(a) <<'.' <<
-                    static_cast<int>(b) <<'.' << static_cast<int>(c) <<
-                    '.' << static_cast<int>(d) << ':' << portStr;
-            }
-            return os.str();
-        }
-        else
-        {
-            return OC::Error::INVALID_IP;
-        }
-    }
-
-    struct ListenContext
-    {
-        FindCallback              callback;
-        IClientWrapper::Ptr       clientWrapper;
-    };
-
-
-    std::shared_ptr<OCResource> InProcClientWrapper::parseOCResource(
-        IClientWrapper::Ptr clientWrapper, OCDevAddr& addr,
-        const boost::property_tree::ptree resourceNode)
-    {
-        std::string uri = resourceNode.get<std::string>(OC::Key::URIKEY, "");
-        bool obs = resourceNode.get<int>(OC::Key::OBSERVABLEKEY,0) == 1;
-        std::vector<std::string> rTs;
-        std::vector<std::string> ifaces;
-
-        boost::property_tree::ptree properties =
-            resourceNode.get_child(OC::Key::PROPERTYKEY, boost::property_tree::ptree());
-
-        boost::property_tree::ptree rT =
-            properties.get_child(OC::Key::RESOURCETYPESKEY, boost::property_tree::ptree());
-        for(auto itr : rT)
-        {
-            rTs.push_back(itr.second.data());
-        }
-        bool secure = properties.get<int>(OC::Key::SECUREKEY,0) == 1;
-
-        boost::property_tree::ptree iF =
-            properties.get_child(OC::Key::INTERFACESKEY, boost::property_tree::ptree());
-        for(auto itr : iF)
-        {
-            ifaces.push_back(itr.second.data());
-        }
-
-        std::string host;
-        if(secure)
-        {
-            string port = properties.get<string>(OC::Key::PORTKEY,"");
-            host= convertOCAddrToString(addr, OCSecureType::IPV4Secure, port);
-        }
-        else
-        {
-            host= convertOCAddrToString(addr, OCSecureType::IPV4);
-        }
-
-        return std::shared_ptr<OCResource>(
-            new OCResource(clientWrapper, host, uri, obs, rTs, ifaces));
-    }
-
     OCStackApplicationResult listenCallback(void* ctx, OCDoHandle handle,
         OCClientResponse* clientResponse)
     {
-        ListenContext* context = static_cast<ListenContext*>(ctx);
+        ClientCallbackContext::ListenContext* context =
+            static_cast<ClientCallbackContext::ListenContext*>(ctx);
 
         if(clientResponse->result != OC_STACK_OK)
         {
@@ -188,48 +105,31 @@ namespace OC
         std::stringstream requestStream;
         requestStream << clientResponse->resJSONPayload;
 
-        boost::property_tree::ptree root;
-
         try
         {
-                boost::property_tree::read_json(requestStream, root);
-        }
-        catch(boost::property_tree::json_parser::json_parser_error &e)
-        {
-                oclog() << "listenCallback(): read_json() failed: " << e.what()
-                        << std::flush;
+            ListenOCContainer container(context->clientWrapper, *clientResponse->addr,
+                    requestStream);
 
-                return OC_STACK_KEEP_TRANSACTION;
-        }
-
-        boost::property_tree::ptree payload =
-                root.get_child(OC::Key::OCKEY, boost::property_tree::ptree());
+            // loop to ensure valid construction of all resources
+            for(auto resource : container.Resources())
+            {
+                std::thread exec(context->callback, resource);
+                exec.detach();
+            }
 
-        for(auto payloadItr : payload)
+        }
+        catch(const std::exception& e)
         {
-                try
-                {
-                    std::shared_ptr<OCResource> resource =
-                        context->clientWrapper->parseOCResource(context->clientWrapper,
-                        *clientResponse->addr,
-                        payloadItr.second);
-
-                    // Note: the call to detach allows the underlying thread to continue until
-                    // completion and allows us to destroy the exec object. This is apparently NOT
-                    // a memory leak, as the thread will apparently take care of itself.
-                    // Additionally, the only parameter here is a shared ptr, so OCResource will be
-                    // disposed of properly upon completion of the callback handler.
-                    std::thread exec(context->callback,resource);
-                    exec.detach();
-                }
-                catch(ResourceInitException& e)
-                {
-                    oclog() << "listenCallback(): failed to create resource: " << e.what()
-                            << std::flush;
-                }
+            oclog() << "listenCallback failed to parse a malformed message: "
+                    << e.what()
+                    << std::endl <<std::endl
+                    << clientResponse->result
+                    << std::flush;
+            return OC_STACK_KEEP_TRANSACTION;
         }
 
         return OC_STACK_KEEP_TRANSACTION;
+
     }
 
     OCStackResult InProcClientWrapper::ListenForResource(const std::string& serviceUrl,
@@ -239,13 +139,13 @@ namespace OC
 
         OCCallbackData cbdata = {0};
 
-        ListenContext* context = new ListenContext();
+        ClientCallbackContext::ListenContext* context = new ClientCallbackContext::ListenContext();
         context->callback = callback;
         context->clientWrapper = shared_from_this();
 
         cbdata.context =  static_cast<void*>(context);
         cbdata.cb = listenCallback;
-        cbdata.cd = [](void* c){delete static_cast<ListenContext*>(c);};
+        cbdata.cd = [](void* c){delete static_cast<ClientCallbackContext::ListenContext*>(c);};
 
         auto cLock = m_csdkLock.lock();
         if(cLock)
@@ -266,124 +166,31 @@ namespace OC
         return result;
     }
 
-    struct GetContext
-    {
-        GetCallback callback;
-    };
-
-    struct SetContext
-    {
-        PutCallback callback;
-    };
-
-
     OCRepresentation parseGetSetCallback(OCClientResponse* clientResponse)
     {
-        std::stringstream requestStream;
-        requestStream<<clientResponse->resJSONPayload;
-        if(strlen((char*)clientResponse->resJSONPayload) == 0)
+        if(clientResponse->resJSONPayload == nullptr || clientResponse->resJSONPayload[0] == '\0')
         {
             return OCRepresentation();
         }
 
-        boost::property_tree::ptree root;
-        try
-        {
-            boost::property_tree::read_json(requestStream, root);
-        }
-        catch(boost::property_tree::json_parser::json_parser_error &e)
+        MessageContainer oc;
+        oc.setJSONRepresentation(clientResponse->resJSONPayload);
+
+        std::vector<OCRepresentation>::const_iterator it = oc.representations().begin();
+        if(it == oc.representations().end())
         {
             return OCRepresentation();
         }
-        boost::property_tree::ptree payload = root.get_child(OC::Key::OCKEY, boost::property_tree::ptree());
-        OCRepresentation root_resource;
-        std::vector<OCRepresentation> children;
-        bool isRoot = true;
-        for ( auto payloadItr : payload)
-        {
-            OCRepresentation child;
-            try
-            {
-                auto resourceNode = payloadItr.second;
-                std::string uri = resourceNode.get<std::string>(OC::Key::URIKEY, "");
-
-                if (isRoot)
-                {
-                    root_resource.setUri(uri);
-                }
-                else
-                {
-                    child.setUri(uri);
-                }
-
-                if( resourceNode.count(OC::Key::PROPERTYKEY) != 0 )
-                {
-                    std::vector<std::string> rTs;
-                    std::vector<std::string> ifaces;
-                    boost::property_tree::ptree properties =
-                        resourceNode.get_child(OC::Key::PROPERTYKEY, boost::property_tree::ptree());
-
-                    boost::property_tree::ptree rT =
-                        properties.get_child(OC::Key::RESOURCETYPESKEY,
-                                                boost::property_tree::ptree());
-                    for(auto itr : rT)
-                    {
-                        rTs.push_back(itr.second.data());
-                    }
-
-                    boost::property_tree::ptree iF =
-                        properties.get_child(OC::Key::INTERFACESKEY, boost::property_tree::ptree());
-                    for(auto itr : iF)
-                    {
-                        ifaces.push_back(itr.second.data());
-                    }
-                    if (isRoot)
-                    {
-                        root_resource.setResourceInterfaces(ifaces);
-                        root_resource.setResourceTypes(rTs);
-                    }
-                    else
-                    {
-                        child.setResourceInterfaces(ifaces);
-                        child.setResourceTypes(rTs);
-                    }
-                }
-
-                if( resourceNode.count(OC::Key::REPKEY) != 0 )
-                {
-                    boost::property_tree::ptree rep =
-                        resourceNode.get_child(OC::Key::REPKEY, boost::property_tree::ptree());
-                    AttributeMap attrs;
-                    for( auto item : rep)
-                    {
-                        std::string name = item.first.data();
-                        std::string value = item.second.data();
-                        attrs[name] = value;
-                    }
-                    if (isRoot)
-                    {
-                        root_resource.setAttributeMap(attrs);
-                    }
-                    else
-                    {
-                        child.setAttributeMap(attrs);
-                    }
-                }
-
-                if (!isRoot)
-                    children.push_back(child);
-            }
-            catch (...)
-            {
-                // TODO
-            }
 
-            isRoot = false;
-         }
+        // first one is considered the root, everything else is considered a child of this one.
+        OCRepresentation root = *it;
+        ++it;
 
-         root_resource.setChildren(children);
+        std::for_each(it, oc.representations().end(),
+                [&root](const OCRepresentation& repItr)
+                {root.addChild(repItr);});
+        return root;
 
-        return root_resource;
     }
 
     void parseServerHeaderOptions(OCClientResponse* clientResponse,
@@ -415,7 +222,8 @@ namespace OC
     OCStackApplicationResult getResourceCallback(void* ctx, OCDoHandle handle,
         OCClientResponse* clientResponse)
     {
-        GetContext* context = static_cast<GetContext*>(ctx);
+        ClientCallbackContext::GetContext* context =
+            static_cast<ClientCallbackContext::GetContext*>(ctx);
 
         OCRepresentation rep;
         HeaderOptions serverHeaderOptions;
@@ -438,11 +246,11 @@ namespace OC
         OCStackResult result;
         OCCallbackData cbdata = {0};
 
-        GetContext* ctx = new GetContext();
+        ClientCallbackContext::GetContext* ctx = new ClientCallbackContext::GetContext();
         ctx->callback = callback;
         cbdata.context = static_cast<void*>(ctx);
         cbdata.cb = &getResourceCallback;
-        cbdata.cd = [](void* c){delete static_cast<GetContext*>(c);};
+        cbdata.cd = [](void* c){delete static_cast<ClientCallbackContext::GetContext*>(c);};
 
         auto cLock = m_csdkLock.lock();
 
@@ -473,7 +281,8 @@ namespace OC
     OCStackApplicationResult setResourceCallback(void* ctx, OCDoHandle handle,
         OCClientResponse* clientResponse)
     {
-        SetContext* context = static_cast<SetContext*>(ctx);
+        ClientCallbackContext::SetContext* context =
+            static_cast<ClientCallbackContext::SetContext*>(ctx);
         OCRepresentation attrs;
         HeaderOptions serverHeaderOptions;
 
@@ -521,14 +330,9 @@ namespace OC
 
     std::string InProcClientWrapper::assembleSetResourcePayload(const OCRepresentation& rep)
     {
-        ostringstream payload;
-        // TODO need to change the format to "{"oc":[]}"
-        payload << "{\"oc\":";
-
-        payload << rep.getJSONRepresentation();
-
-        payload << "}";
-        return payload.str();
+        MessageContainer ocInfo;
+        ocInfo.addRepresentation(rep);
+        return ocInfo.getJSONRepresentation(OCInfoFormat::IncludeOC);
     }
 
     OCStackResult InProcClientWrapper::PostResourceRepresentation(const std::string& host,
@@ -539,10 +343,10 @@ namespace OC
         OCStackResult result;
         OCCallbackData cbdata = {0};
 
-        SetContext* ctx = new SetContext();
+        ClientCallbackContext::SetContext* ctx = new ClientCallbackContext::SetContext();
         ctx->callback = callback;
         cbdata.cb = &setResourceCallback;
-        cbdata.cd = [](void* c){delete static_cast<SetContext*>(c);};
+        cbdata.cd = [](void* c){delete static_cast<ClientCallbackContext::SetContext*>(c);};
         cbdata.context = static_cast<void*>(ctx);
 
         // TODO: in the future the cstack should be combining these two strings!
@@ -582,10 +386,10 @@ namespace OC
         OCStackResult result;
         OCCallbackData cbdata = {0};
 
-        SetContext* ctx = new SetContext();
+        ClientCallbackContext::SetContext* ctx = new ClientCallbackContext::SetContext();
         ctx->callback = callback;
         cbdata.cb = &setResourceCallback;
-        cbdata.cd = [](void* c){delete static_cast<SetContext*>(c);};
+        cbdata.cd = [](void* c){delete static_cast<ClientCallbackContext::SetContext*>(c);};
         cbdata.context = static_cast<void*>(ctx);
 
         // TODO: in the future the cstack should be combining these two strings!
@@ -617,16 +421,11 @@ namespace OC
         return result;
     }
 
-    struct DeleteContext
-    {
-        DeleteCallback callback;
-    };
-
     OCStackApplicationResult deleteResourceCallback(void* ctx, OCDoHandle handle,
         OCClientResponse* clientResponse)
     {
-        DeleteContext* context = static_cast<DeleteContext*>(ctx);
-        OCRepresentation attrs;
+        ClientCallbackContext::DeleteContext* context =
+            static_cast<ClientCallbackContext::DeleteContext*>(ctx);
         HeaderOptions serverHeaderOptions;
 
         if(clientResponse->result == OC_STACK_OK)
@@ -645,10 +444,10 @@ namespace OC
         OCStackResult result;
         OCCallbackData cbdata = {0};
 
-        DeleteContext* ctx = new DeleteContext();
+        ClientCallbackContext::DeleteContext* ctx = new ClientCallbackContext::DeleteContext();
         ctx->callback = callback;
         cbdata.cb = &deleteResourceCallback;
-        cbdata.cd = [](void* c){delete static_cast<DeleteContext*>(c);};
+        cbdata.cd = [](void* c){delete static_cast<ClientCallbackContext::DeleteContext*>(c);};
         cbdata.context = static_cast<void*>(ctx);
 
         ostringstream os;
@@ -678,15 +477,11 @@ namespace OC
         return result;
     }
 
-    struct ObserveContext
-    {
-        ObserveCallback callback;
-    };
-
     OCStackApplicationResult observeResourceCallback(void* ctx, OCDoHandle handle,
         OCClientResponse* clientResponse)
     {
-        ObserveContext* context = static_cast<ObserveContext*>(ctx);
+        ClientCallbackContext::ObserveContext* context =
+            static_cast<ClientCallbackContext::ObserveContext*>(ctx);
         OCRepresentation attrs;
         HeaderOptions serverHeaderOptions;
         uint32_t sequenceNumber = clientResponse->sequenceNumber;
@@ -709,11 +504,11 @@ namespace OC
         OCStackResult result;
         OCCallbackData cbdata = {0};
 
-        ObserveContext* ctx = new ObserveContext();
+        ClientCallbackContext::ObserveContext* ctx = new ClientCallbackContext::ObserveContext();
         ctx->callback = callback;
         cbdata.context = static_cast<void*>(ctx);
         cbdata.cb = &observeResourceCallback;
-        cbdata.cd = [](void* c){delete static_cast<ObserveContext*>(c);};
+        cbdata.cd = [](void* c){delete static_cast<ClientCallbackContext::ObserveContext*>(c);};
 
         OCMethod method;
         if (observeType == ObserveType::Observe)
@@ -768,7 +563,8 @@ namespace OC
             OCHeaderOption options[MAX_HEADER_OPTIONS];
 
             assembleHeaderOptions(options, headerOptions);
-            result = OCCancel(handle, static_cast<OCQualityOfService>(QoS), options, headerOptions.size());
+            result = OCCancel(handle, static_cast<OCQualityOfService>(QoS), options,
+                    headerOptions.size());
         }
         else
         {
@@ -778,15 +574,11 @@ namespace OC
         return result;
     }
 
-    struct SubscribePresenceContext
-    {
-        SubscribeCallback callback;
-    };
-
     OCStackApplicationResult subscribePresenceCallback(void* ctx, OCDoHandle handle,
         OCClientResponse* clientResponse)
     {
-        SubscribePresenceContext* context = static_cast<SubscribePresenceContext*>(ctx);
+        ClientCallbackContext::SubscribePresenceContext* context =
+            static_cast<ClientCallbackContext::SubscribePresenceContext*>(ctx);
         std::thread exec(context->callback, clientResponse->result, clientResponse->sequenceNumber);
 
         exec.detach();
@@ -799,11 +591,13 @@ namespace OC
     {
         OCCallbackData cbdata = {0};
 
-        SubscribePresenceContext* ctx = new SubscribePresenceContext();
+        ClientCallbackContext::SubscribePresenceContext* ctx =
+            new ClientCallbackContext::SubscribePresenceContext();
         ctx->callback = presenceHandler;
         cbdata.cb = &subscribePresenceCallback;
         cbdata.context = static_cast<void*>(ctx);
-        cbdata.cd = [](void* c){delete static_cast<SubscribePresenceContext*>(c);};
+        cbdata.cd = [](void* c)
+            {delete static_cast<ClientCallbackContext::SubscribePresenceContext*>(c);};
         auto cLock = m_csdkLock.lock();
 
         std::ostringstream os;
index c057c7d..751dc87 100644 (file)
@@ -280,10 +280,9 @@ OCEntityHandlerResult EntityHandlerWrapper(OCEntityHandlerFlag flag,
 
 namespace OC
 {
-    InProcServerWrapper::InProcServerWrapper(OC::OCPlatform_impl& owner,
+    InProcServerWrapper::InProcServerWrapper(
         std::weak_ptr<std::recursive_mutex> csdkLock, PlatformConfig cfg)
-     : IServerWrapper(owner),
-       m_csdkLock(csdkLock)
+     : m_csdkLock(csdkLock)
     {
         OCMode initType;
 
index 4671c2b..fee95c9 100644 (file)
@@ -68,16 +68,16 @@ namespace OC
         switch(config.mode)
         {
             case ModeType::Server:
-                m_server = m_WrapperInstance->CreateServerWrapper(*this, m_csdkLock, config);
+                m_server = m_WrapperInstance->CreateServerWrapper(m_csdkLock, config);
                 break;
 
             case ModeType::Client:
-                m_client = m_WrapperInstance->CreateClientWrapper(*this, m_csdkLock, config);
+                m_client = m_WrapperInstance->CreateClientWrapper(m_csdkLock, config);
                 break;
 
             case ModeType::Both:
-                m_server = m_WrapperInstance->CreateServerWrapper(*this, m_csdkLock, config);
-                m_client = m_WrapperInstance->CreateClientWrapper(*this, m_csdkLock, config);
+                m_server = m_WrapperInstance->CreateServerWrapper(m_csdkLock, config);
+                m_client = m_WrapperInstance->CreateClientWrapper(m_csdkLock, config);
                 break;
          }
     }
@@ -129,7 +129,7 @@ namespace OC
          return result_guard(OC_STACK_ERROR);
         }
 
-        std::string payload(pResponse->getPayload());
+        std::string payload(pResponse->getResourceRepresentation().getJSONRepresentation());
 
         return result_guard(
                    OCNotifyListOfObservers(resourceHandle,
diff --git a/resource/src/OCRepresentation.cpp b/resource/src/OCRepresentation.cpp
new file mode 100644 (file)
index 0000000..f251818
--- /dev/null
@@ -0,0 +1,486 @@
+//******************************************************************
+//
+// Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+/// @file OCRepresentation.cpp
+
+/// @brief  This file contains the implementation of classes and its members
+///         related to OCRepresentation
+
+#include <cereal/cereal.hpp>
+#include <cereal/types/map.hpp>
+#include <cereal/types/vector.hpp>
+#include <cereal/types/utility.hpp>
+#include <algorithm>
+#include <OCRepresentation.h>
+namespace OC
+{
+    typedef cereal::JSONOutputArchive OutputArchiveType;
+    typedef cereal::JSONInputArchive InputArchiveType;
+
+    void MessageContainer::setJSONRepresentation(const std::string& payload)
+    {
+        std::stringstream os(payload);
+        {
+            InputArchiveType archive(os);
+            archive(cereal::make_nvp(OC::Key::OCKEY, m_reps));
+        }
+    }
+
+    void MessageContainer::setJSONRepresentation(const unsigned char* payload)
+    {
+        setJSONRepresentation(std::string(reinterpret_cast<const char*>(payload)));
+    }
+
+    std::string MessageContainer::getJSONRepresentation(OCInfoFormat f) const
+    {
+        std::stringstream os;
+
+        // note: the block is required because cereal closes the JSON string
+        // upon destruction, so the archive needs to be destroyed before accessing
+        // the data
+        {
+            if(f == OCInfoFormat::IncludeOC)
+            {
+                OutputArchiveType archive(os);
+                archive(cereal::make_nvp(OC::Key::OCKEY, m_reps));
+            }
+            else if(f== OCInfoFormat::ExcludeOC)
+            {
+                bool firstPrinted = false;
+                for(std::vector<OCRepresentation>::size_type i = 0; i< m_reps.size();++i)
+                {
+                    if(!m_reps[i].empty())
+                    {
+                        if(firstPrinted)
+                        {
+                            os<<',';
+                        }
+                        firstPrinted=true;
+                        os << m_reps[i].getJSONRepresentation();
+                    }
+                }
+            }
+        }
+        return os.str();
+    }
+
+    const std::vector<OCRepresentation>& MessageContainer::representations() const
+    {
+        return m_reps;
+    }
+
+    void MessageContainer::addRepresentation(const OCRepresentation& rep)
+    {
+        m_reps.push_back(rep);
+    }
+}
+
+namespace OC
+{
+    OCRepresentation::OCRepresentation()
+    :m_interfaceType(InterfaceType::None)
+    { }
+    std::string OCRepresentation::getJSONRepresentation() const
+    {
+        std::stringstream os;
+
+        // note: the block is required because cereal closes the JSON string
+        // upon destruction, so the archive needs to be destroyed before accessing
+        // the data
+        {
+            OutputArchiveType archive (os);
+            save(archive);
+        }
+
+        return os.str();
+    }
+
+    void OCRepresentation::addChild(const OCRepresentation& rep)
+    {
+        m_children.push_back(rep);
+    }
+
+    void OCRepresentation::clearChildren()
+    {
+        m_children.clear();
+    }
+
+    const std::vector<OCRepresentation>& OCRepresentation::getChildren() const
+    {
+        return m_children;
+    }
+
+    void OCRepresentation::setUri(const std::string& uri)
+    {
+        m_uri = uri;
+    }
+
+    std::string OCRepresentation::getUri() const
+    {
+        return m_uri;
+    }
+
+    const std::vector<std::string>& OCRepresentation::getResourceTypes() const
+    {
+        return m_resourceTypes;
+    }
+
+    void OCRepresentation::setResourceTypes(const std::vector<std::string>& resourceTypes)
+    {
+        m_resourceTypes = resourceTypes;
+    }
+
+    const std::vector<std::string>& OCRepresentation::getResourceInterfaces() const
+    {
+        return m_interfaces;
+    }
+
+    void OCRepresentation::setResourceInterfaces(const std::vector<std::string>& resourceInterfaces)
+    {
+        m_interfaces = resourceInterfaces;
+    }
+
+    bool OCRepresentation::hasAttribute(const std::string& str) const
+    {
+        return m_values.find(str) != m_values.end();
+    }
+
+    bool OCRepresentation::empty() const
+    {
+        // This logic is meant to determine whether based on the JSON serialization rules
+        // if this object will result in empty JSON.  URI is only serialized if there is valid
+        // data, ResourceType and Interfaces are only serialized if we are a nothing, a
+        // child of a default or link item.
+        // Our values array is only printed in the if we are the child of a Batch resource,
+        // the parent in a 'default' situation, or not in a child/parent relationship.
+        if(!m_uri.empty())
+        {
+            return false;
+        }
+        else if ((m_interfaceType == InterfaceType::None
+                        || m_interfaceType==InterfaceType::DefaultChild
+                        || m_interfaceType==InterfaceType::LinkChild)
+                    && (m_resourceTypes.size()>0 || m_interfaces.size()>0))
+        {
+            return false;
+        }
+        else if((m_interfaceType == InterfaceType::None
+                        || m_interfaceType == InterfaceType::BatchChild
+                        || m_interfaceType == InterfaceType::DefaultParent)
+                    && m_values.size()>0)
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+    int OCRepresentation::numberOfAttributes() const
+    {
+        return m_values.size();
+    }
+
+    bool OCRepresentation::erase(const std::string& str)
+    {
+        return m_values.erase(str);
+    }
+
+    void OCRepresentation::setNULL(const std::string& str)
+    {
+        m_values[str] = OC::NullType();
+    }
+
+    bool OCRepresentation::isNULL(const std::string& str) const
+    {
+        auto x = m_values.find(str);
+
+        if(m_values.end() != x)
+        {
+            return x->second.which() == AttributeValueNullIndex;
+        }
+        else
+        {
+            throw OCException(OC::Exception::INVALID_ATTRIBUTE+ str);
+        }
+    }
+}
+
+// note: the below is used to load an AttributeValue map out of JSON
+namespace OC
+{
+    namespace detail
+    {
+        enum class typeTag:uint8_t
+        {
+            NOTHING = 0,
+            _string,
+            _int,
+            _double,
+            _bool,
+            _representation
+        };
+
+        typedef rapidjson::Document::GenericValue GenericValue;
+
+        AttributeValue parseAttributeValue(const GenericValue& v);
+        AttributeValue parseAttributeValue(const GenericValue& v,
+                const unsigned int curLevel, unsigned int& maxDepth, typeTag& t);
+        AttributeValue parseAttributeValueObject(const GenericValue& v, typeTag& t);
+        AttributeValue parseAttributeValueArray(const GenericValue& v,
+                const unsigned int curLevel, unsigned int& maxDepth, typeTag& t);
+        AttributeValue parseAttributeValuePrimitive(const GenericValue& v, typeTag& t);
+
+        AttributeValue parseAttributeValue(const GenericValue& v)
+        {
+            // base entrance, start everything at '0'
+            unsigned int max_depth {0};
+            typeTag t {typeTag::NOTHING};
+
+            return parseAttributeValue(v, 0, max_depth, t);
+        }
+
+        AttributeValue parseAttributeValue(const GenericValue& v,
+                const unsigned int curLevel, unsigned int& maxDepth, typeTag& t)
+        {
+            if(v.IsObject())
+            {
+                return parseAttributeValueObject(v, t);
+            }
+            else if(v.IsArray())
+            {
+                return parseAttributeValueArray(v, curLevel + 1, maxDepth, t);
+            }
+            else
+            {
+                return parseAttributeValuePrimitive(v,t);
+            }
+        }
+
+        AttributeValue parseAttributeValueObject(const GenericValue& v, typeTag& t)
+        {
+            typedef rapidjson::Value::ConstMemberIterator CMI;
+            t = typeTag::_representation;
+            OC::OCRepresentation rep;
+
+            for(CMI itr = v.MemberBegin(); itr!= v.MemberEnd(); ++itr)
+            {
+                std::string keyName = itr->name.GetString();
+
+                if(keyName == OC::Key::URIKEY)
+                {
+                    rep.setUri(boost::get<std::string>(parseAttributeValue(itr->value)));
+                }
+                else if (keyName == OC::Key::PROPERTYKEY)
+                {
+                    for(CMI itr2 = itr->value.MemberBegin();
+                            itr->value.MemberEnd()!=itr2;
+                            ++itr2)
+                    {
+                        if(keyName == OC::Key::RESOURCETYPESKEY)
+                        {
+                            rep.setResourceTypes(
+                                    boost::get<std::vector<std::string>>(
+                                        parseAttributeValue(itr->value)));
+                        }
+                        else if(keyName == OC::Key::PROPERTYKEY)
+                        {
+                            rep.setResourceInterfaces(
+                                    boost::get<std::vector<std::string>>(
+                                        parseAttributeValue(itr->value)));
+                        }
+                    }
+                }
+                else if (keyName == OC::Key::REPKEY)
+                {
+                    for(CMI itr2 = itr->value.MemberBegin();
+                            itr->value.MemberEnd()!=itr2;
+                            ++itr2)
+                    {
+                        rep.setValue(itr2->name.GetString(),
+                                parseAttributeValue(itr2->value));
+                    }
+                }
+            }
+
+            return rep;
+        }
+
+        AttributeValue parseAttributeValuePrimitive(const GenericValue& v, typeTag& t)
+        {
+            if(v.IsString())
+            {
+                t = typeTag::_string;
+                return std::string(v.GetString());
+            }
+            else if (v.IsNumber())
+            {
+                if(v.IsDouble())
+                {
+                    t = typeTag::_double;
+                    return double(v.GetDouble());
+                }
+                else if (v.IsInt())
+                {
+                    t = typeTag::_int;
+                    return int(v.GetInt());
+                }
+                else
+                {
+                    throw OC::OCException(OC::Exception::INVALID_JSON_NUMERIC
+                            + std::to_string(v.GetType()));
+                }
+            }
+            else if(v.IsBool_())
+            {
+                t=typeTag::_bool;
+                return bool(v.GetBool_());
+            }
+            else if(v.IsNull_())
+            {
+                return OC::NullType();
+            }
+            else
+            {
+                throw OC::OCException(OC::Exception::INVALID_JSON_TYPE
+                        + std::to_string(v.GetType()));
+            }
+        }
+
+        std::vector<AttributeValue> gatherArrayContents(const GenericValue& v,
+                const unsigned int curLevel, unsigned int& maxDepth, typeTag& t)
+        {
+            std::vector<AttributeValue> out;
+
+            std::transform(v.Begin(), v.End(), back_inserter(out),
+                    [curLevel, &maxDepth, &t](const GenericValue& x)
+                    {
+                        return parseAttributeValue(x, curLevel, maxDepth, t);
+                    });
+            return out;
+        }
+
+        template<class OutT>
+        struct valueToConcrete
+        {
+            OutT operator()(const AttributeValue& v)
+            {
+                return boost::get<OutT>(v);
+            }
+
+        };
+
+        template <class OutSeqT>
+        OutSeqT valuesToConcreteVectors(const std::vector<AttributeValue>& vs)
+        {
+            OutSeqT ret;
+
+            std::transform(begin(vs),end(vs), back_inserter(ret),
+                valueToConcrete<typename OutSeqT::value_type>());
+            return ret;
+        }
+
+        template<class valueType>
+        AttributeValue remapArrayDepth(const unsigned int curLevel,
+                const std::vector<OC::AttributeValue>& vs)
+        {
+            switch(curLevel)
+            {
+                default:
+                    throw OC::OCException(OC::Exception::INVALID_JSON_ARRAY_DEPTH);
+                    break;
+                case 1:
+                    return valuesToConcreteVectors<std::vector<valueType>>(vs);
+                    break;
+                case 2:
+                    return valuesToConcreteVectors<std::vector<std::vector<valueType>>>(vs);
+                    break;
+                case 3:
+                    return valuesToConcreteVectors
+                        <std::vector<std::vector<std::vector<valueType>>>>(vs);
+                    break;
+            }
+        }
+
+        AttributeValue convertArrayToConcretes(const typeTag t,
+                const unsigned int curLevel, const std::vector<OC::AttributeValue>& vs)
+        {
+            // This function converts a std::vector of AttributeValue to a std::vector
+            // of concrete types.  Since we don't use a recursive Variant, we need
+            // to get back to a 'base' primitive type
+            switch(t)
+            {
+                default:
+                case typeTag::NOTHING:
+                    throw OC::OCException(OC::Exception::INVALID_JSON_TYPE_TAG);
+                    break;
+                case typeTag::_string:
+                    return remapArrayDepth<std::string>(curLevel, vs);
+                    break;
+                case typeTag::_int:
+                    return remapArrayDepth<int>(curLevel, vs);
+                    break;
+                case typeTag::_double:
+                    return remapArrayDepth<double>(curLevel, vs);
+                    break;
+                case typeTag::_bool:
+                    return remapArrayDepth<bool>(curLevel, vs);
+                    break;
+                case typeTag::_representation:
+                    return remapArrayDepth<OCRepresentation>(curLevel, vs);
+                    break;
+            }
+        }
+
+        AttributeValue parseAttributeValueArray(const GenericValue& v,
+                const unsigned int curLevel, unsigned int& maxDepth, typeTag& t)
+        {
+            const unsigned int max_level = 3;
+
+            if(curLevel > max_level)
+            {
+                throw OC::OCException(OC::Exception::INVALID_JSON_ARRAY_DEPTH);
+            }
+
+            if(curLevel > maxDepth)
+            {
+                maxDepth = curLevel;
+            }
+
+            auto arrayItems = gatherArrayContents(v, curLevel, maxDepth, t);
+            const int remapLevel = maxDepth - (curLevel -1);
+            return convertArrayToConcretes(t, remapLevel, arrayItems);
+        }
+    }
+}
+
+namespace cereal
+{
+   void JSONInputArchive::loadAttributeValues(std::map<std::string, OC::AttributeValue>& map)
+   {
+       for(auto&b = itsIteratorStack.back();
+           b.Member && b.itsMemberItEnd != b.itsMemberItBegin+b.itsIndex;
+           ++b)
+       {
+           std::string key = b.itsMemberItBegin[b.itsIndex].name.GetString();
+           const GenericValue& v = itsIteratorStack.back().value();
+           map[key] = OC::detail::parseAttributeValue(v);
+       }
+   }
+}
index b3062e9..2ec4eb6 100644 (file)
@@ -43,7 +43,7 @@ OCResource::OCResource(std::weak_ptr<IClientWrapper> clientWrapper, const std::s
         m_clientWrapper.expired())
     {
         throw ResourceInitException(m_uri.empty(), resourceTypes.empty(),
-                interfaces.empty(), m_clientWrapper.expired());
+                interfaces.empty(), m_clientWrapper.expired(), false, false);
     }
 }
 
index e8283c0..ae26745 100644 (file)
@@ -38,6 +38,13 @@ include $(ROOT_DIR)/../csdk/local.properties
 
 OUT_DIR          := $(BUILD)
 
+ifeq ($(ROOT_DIR),)
+       ROOT_DIR:=$(PWD)
+endif
+
+DEPEND_DIR:=$(ROOT_DIR)/../dependencies
+CEREAL_DIR:=$(DEPEND_DIR)/cereal
+
 INC_DIRS  := -I../include/
 INC_DIRS  += -I../oc_logger/include
 INC_DIRS  += -I../csdk/stack/include
@@ -46,6 +53,7 @@ INC_DIRS  += -I../csdk/ocrandom/include
 INC_DIRS  += -I../csdk/logger/include
 INC_DIRS  += -I../csdk/libcoap
 INC_DIRS  += -I$(GTEST_DIR)/include
+INC_DIRS  += -I$(CEREAL_DIR)/include
 
 LIB_OC_LOGGER := ../oc_logger/lib/oc_logger.a