Implement ServerID parsing and sample app
authorSudarshan Prasad <sudarshan.prasad@intel.com>
Thu, 25 Dec 2014 03:44:03 +0000 (19:44 -0800)
committerSudarshan Prasad <sudarshan.prasad@intel.com>
Thu, 25 Dec 2014 04:27:02 +0000 (20:27 -0800)
This changeset will correctly parse the Connectivity abstraction
ServerID and provide it as a unique identifier to the client implementer.
This change also includes a sample app that shows off this functionality.

Note: this change was brought from https://oic-review.01.org/gerrit/#/c/624

Change-Id: I0151744d3481da806f5345c0798f7b951fb91394
Signed-off-by: Yuliya Kamatkova <yuliya.kamatkova@intel.com>
Signed-off-by: Sudarshan Prasad <sudarshan.prasad@intel.com>
resource/examples/simpleclient.cpp
resource/examples/simpleclientHQ.cpp
resource/include/OCResource.h
resource/include/OCSerialization.h
resource/include/StringConstants.h
resource/src/InProcClientWrapper.cpp
resource/src/OCPlatform_impl.cpp
resource/src/OCResource.cpp

index 0451ddb..8e6ae74 100644 (file)
 // OCClient.cpp : Defines the entry point for the console application.
 //
 #include <string>
+#include <map>
 #include <cstdlib>
 #include <pthread.h>
 #include <mutex>
 #include <condition_variable>
-
 #include "OCPlatform.h"
 #include "OCApi.h"
 
 using namespace OC;
 
+typedef std::map<OCResourceIdentifier, std::shared_ptr<OCResource>> DiscoveredResourceMap;
+
+DiscoveredResourceMap discoveredResources;
 std::shared_ptr<OCResource> curResource;
 static ObserveType OBSERVE_TYPE_TO_USE = ObserveType::Observe;
 
@@ -272,15 +275,27 @@ void getLightRepresentation(std::shared_ptr<OCResource> resource)
 // Callback to found resources
 void foundResource(std::shared_ptr<OCResource> resource)
 {
-    if(curResource)
-    {
-        std::cout << "Found another resource, ignoring"<<std::endl;
-    }
-
     std::string resourceURI;
     std::string hostAddress;
     try
     {
+        if(discoveredResources.find(resource->uniqueIdentifier()) == discoveredResources.end())
+        {
+            std::cout << "Found resource " << resource->uniqueIdentifier() <<
+                " for the first time on server with ID: "<< resource->sid()<<std::endl;
+            discoveredResources[resource->uniqueIdentifier()] = resource;
+        }
+        else
+        {
+            std::cout<<"Found resource "<< resource->uniqueIdentifier() << " again!"<<std::endl;
+        }
+
+        if(curResource)
+        {
+            std::cout << "Found another resource, ignoring"<<std::endl;
+            return;
+        }
+
         // Do some operations with resource object.
         if(resource)
         {
@@ -380,6 +395,22 @@ int main(int argc, char* argv[]) {
 #endif
         std::cout<< "Finding Resource... " <<std::endl;
 
+        // Find resource is done twice so that we discover the original resources a second time.
+        // These resources will have the same uniqueidentifier (yet be different objects), so that
+        // we can verify/show the duplicate-checking code in foundResource(above);
+#ifdef CA_INT
+        OCConnectivityType connectivityType = OC_WIFI;
+        OCPlatform::findResource("", "coap://224.0.1.187/oc/core?rt=core.light",
+                    connectivityType, &foundResource);
+#else
+        OCPlatform::findResource("", "coap://224.0.1.187/oc/core?rt=core.light", &foundResource);
+#endif
+        std::cout<< "Finding Resource for second time... " <<std::endl;
+        while(true)
+        {
+            // some operations
+        }
+
         // A condition variable will free the mutex it is given, then do a non-
         // intensive block until 'notify' is called on it.  In this case, since we
         // don't ever call cv.notify, this should be a non-processor intensive version
index a215ef0..f1c0f4d 100644 (file)
 
 // OCClient.cpp : Defines the entry point for the console application.
 //
+#include <set>
 #include <string>
 #include <cstdlib>
 #include <pthread.h>
 #include <mutex>
 #include <condition_variable>
-
 #include "OCPlatform.h"
 #include "OCApi.h"
 
 using namespace OC;
 
+struct dereference_compare
+{
+    bool operator()(std::shared_ptr<OCResource> lhs, std::shared_ptr<OCResource> rhs )const
+    {
+        return *lhs < *rhs;
+    }
+};
+typedef std::set<std::shared_ptr<OCResource>, dereference_compare> DiscoveredResourceSet;
+
+DiscoveredResourceSet discoveredResources;
 const int SUCCESS_RESPONSE = 0;
 std::shared_ptr<OCResource> curResource;
 static ObserveType OBSERVE_TYPE_TO_USE = ObserveType::Observe;
@@ -285,15 +295,27 @@ void getLightRepresentation(std::shared_ptr<OCResource> resource)
 // Callback to found resources
 void foundResource(std::shared_ptr<OCResource> resource)
 {
-    if(curResource)
-    {
-        std::cout << "Found another resource, ignoring"<<std::endl;
-    }
-
     std::string resourceURI;
     std::string hostAddress;
     try
     {
+        if(discoveredResources.find(resource) == discoveredResources.end())
+        {
+            std::cout << "Found resource " << resource->uniqueIdentifier() <<
+                " for the first time on server with ID: "<< resource->sid()<<std::endl;
+            discoveredResources.insert(resource);
+        }
+        else
+        {
+            std::cout<<"Found resource "<< resource->uniqueIdentifier() << " again!"<<std::endl;
+        }
+
+        if(curResource)
+        {
+            std::cout << "Found another resource, ignoring"<<std::endl;
+            return;
+        }
+
         // Do some operations with resource object.
         if(resource)
         {
@@ -394,6 +416,23 @@ int main(int argc, char* argv[]) {
 #endif
         std::cout<< "Finding Resource... " <<std::endl;
 
+        // Find resource is done twice so that we discover the original resources a second time.
+        // These resources will have the same uniqueidentifier (yet be different objects), so that
+        // we can verify/show the duplicate-checking code in foundResource(above);
+#ifdef CA_INT
+        OCConnectivityType connectivityType = OC_WIFI;
+        OCPlatform::findResource("", "coap://224.0.1.187/oc/core?rt=core.light",
+                connectivityType, &foundResource, OC::QualityOfService::LowQos);
+#else
+        OCPlatform::findResource("", "coap://224.0.1.187/oc/core?rt=core.light", &foundResource,
+                OC::QualityOfService::LowQos);
+#endif
+        std::cout<< "Finding Resource for second time... " <<std::endl;
+        while(true)
+        {
+            // some operations
+        }
+
         // A condition variable will free the mutex it is given, then do a non-
         // intensive block until 'notify' is called on it.  In this case, since we
         // don't ever call cv.notify, this should be a non-processor intensive version
index cf9bded..5846994 100644 (file)
 
 namespace OC
 {
+    class OCResource;
+    class OCResourceIdentifier;
+    ostream& operator <<(ostream& os, const OCResourceIdentifier& ri);
+    /**
+    *  @brief  OCResourceIdentifier represents the identity information for a server. This
+    *          object combined with the OCResource's URI property uniquely identify an
+    *          OCResource on or across networks.
+    *          Equality operators are implemented.  However, internal representation is subject
+    *          to change and thus should not be accessed or depended on.
+    */
+    class OCResourceIdentifier
+    {
+        friend class OCResource;
+        friend ostream& operator <<(ostream& os, const OCResourceIdentifier& ri);
+
+        public:
+            bool operator==(const OCResourceIdentifier &other) const;
+
+            bool operator!=(const OCResourceIdentifier &other) const;
+
+            bool operator<(const OCResourceIdentifier &other) const;
+
+            bool operator>(const OCResourceIdentifier &other) const;
+
+            bool operator<=(const OCResourceIdentifier &other) const;
+
+            bool operator>=(const OCResourceIdentifier &other) const;
+
+        private:
+
+            OCResourceIdentifier(const std::string& wireServerIdentifier,
+                    const std::string& resourceUri );
+
+        private:
+            uint32_t m_representation;
+            const std::string& m_resourceUri;
+    };
+
     /**
     *   @brief  OCResource represents an OC resource. A resource could be a light controller,
     *           temperature sensor, smoke detector, etc. A resource comes with a well-defined
@@ -307,9 +345,43 @@ namespace OC
             return m_interfaces;
         }
 
+        // TODO-CA Revisit this since we are exposing two identifiers
+        /**
+        * Function to get a unqiue identifier for this
+        * resource across network interfaces.  This will
+        * be guaranteed unique for every resource-per-server
+        * independent of how this was discovered.
+        * @return OCResourceIdentifier object, which can
+        * be used for all comparison and hashing.
+        */
+        OCResourceIdentifier uniqueIdentifier() const;
+
+        /**
+        * Function to get a string representation of the resource's server ID.
+        * This is unique per- server independent on how it was discovered.
+        * Note: The format of the return value is subject to change and will
+        * likely change both in size and contents in the future.
+        */
+        std::string sid() const;
+
+        // overloaded operators allow for putting into a 'set'
+        // the uniqueidentifier allows for putting into a hash
+        bool operator==(const OCResource &other) const;
+
+        bool operator!=(const OCResource &other) const;
+
+        bool operator<(const OCResource &other) const;
+
+        bool operator>(const OCResource &other) const;
+
+        bool operator<=(const OCResource &other) const;
+
+        bool operator>=(const OCResource &other) const;
+
     private:
         std::weak_ptr<IClientWrapper> m_clientWrapper;
         std::string m_uri;
+        OCResourceIdentifier m_resourceId;
         std::string m_host;
 #ifdef CA_INT
         uint8_t m_connectivityType;
@@ -325,12 +397,12 @@ namespace OC
     private:
 #ifdef CA_INT
         OCResource(std::weak_ptr<IClientWrapper> clientWrapper, const std::string& host,
-            const std::string& uri, uint8_t m_connectivityType, bool observable,
-            const std::vector<std::string>& resourceTypes,
+            const std::string& uri, const std::string& serverId, uint8_t m_connectivityType,
+            bool observable, const std::vector<std::string>& resourceTypes,
             const std::vector<std::string>& interfaces);
 #else
         OCResource(std::weak_ptr<IClientWrapper> clientWrapper, const std::string& host,
-            const std::string& uri, bool observable,
+            const std::string& uri, const std::string& serverId, bool observable,
             const std::vector<std::string>& resourceTypes,
             const std::vector<std::string>& interfaces);
 #endif
index ff47918..2872813 100644 (file)
@@ -122,6 +122,15 @@ namespace OC
                 }
                 try
                 {
+                    ar(cereal::make_nvp(OC::Key::SERVERIDKEY, m_serverId));
+                    m_loaded=true;
+                }
+                catch(cereal::Exception&)
+                {
+                    ar.setNextName(nullptr);
+                }
+                try
+                {
                     ar(cereal::make_nvp(OC::Key::PROPERTYKEY, m_props));
                     m_loaded=true;
                 }
@@ -133,6 +142,7 @@ namespace OC
 
 
             std::string m_uri;
+            std::string m_serverId;
             bool m_loaded;
             ListenResourcePropertiesContainer m_props;
 
@@ -217,7 +227,7 @@ namespace OC
                 else
                 {
                     oclog() << "ConvertOCAddrToString(): Invalid Ip"
-                        << std::flush;
+                            << std::flush;
                     throw ResourceInitException(false, false, false, false, false, true);
                 }
 
@@ -234,7 +244,7 @@ namespace OC
                 else
                 {
                     oclog() << "ConvertOCAddrToString() : Invalid Port"
-                        <<std::flush;
+                            <<std::flush;
                     throw ResourceInitException(false, false, false, false, true, false);
                 }
 
@@ -264,14 +274,14 @@ namespace OC
                             m_resources.push_back(std::shared_ptr<OCResource>(
                                 new OCResource(m_clientWrapper,
                                     ConvertOCAddrToString(res.secureType(),res.port()),
-                                    res.m_uri, connectivityType, res.observable(), res.resourceTypes(),
-                                    res.interfaces())));
+                                    res.m_uri, res.m_serverId, connectivityType, res.observable(),
+                                    res.resourceTypes(), res.interfaces())));
 #else
                             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())));
+                                    res.m_uri, res.m_serverId, res.observable(),
+                                    res.resourceTypes(), res.interfaces())));
 #endif
                         }
 
index d30539c..1bdd1c1 100644 (file)
@@ -131,7 +131,8 @@ namespace OC
         static const std::string REPKEY                     = "rep";
         static const std::string SECUREKEY                  = "sec";
         static const std::string PORTKEY                    = "port";
-  }
+        static const std::string SERVERIDKEY                = "sid";
+    }
 
 }
 
index 4244b5a..9fd3153 100644 (file)
@@ -163,7 +163,9 @@ namespace OC
         {
             oclog() << "listenCallback failed to parse a malformed message: "
                     << e.what()
-                    << std::endl <<std::endl
+                    << std::endl
+                    << clientResponse->resJSONPayload
+                    << std::endl
                     << clientResponse->result
                     << std::flush;
             return OC_STACK_KEEP_TRANSACTION;
index e4eda8e..00ddad2 100644 (file)
@@ -152,7 +152,7 @@ namespace OC
 
         return std::shared_ptr<OCResource>(new OCResource(m_client,
                                             host,
-                                            uri, connectivityType,
+                                            uri, "", connectivityType,
                                             isObservable,
                                             resourceTypes,
                                             interfaces));
@@ -210,6 +210,8 @@ namespace OC
         return std::shared_ptr<OCResource>(new OCResource(m_client,
                                             host,
                                             uri,
+                                            "", // 'created' Resources have no way of knowing their
+                                                // server ID, so this has to be blank initially.
                                             isObservable,
                                             resourceTypes,
                                             interfaces));
index 3581eee..847d21d 100644 (file)
@@ -21,6 +21,8 @@
 #include "OCResource.h"
 #include "OCUtilities.h"
 
+#include <boost/lexical_cast.hpp>
+
 namespace OC {
 
 using OC::nil_guard;
@@ -29,10 +31,12 @@ using OC::checked_guard;
 
 #ifdef CA_INT
 OCResource::OCResource(std::weak_ptr<IClientWrapper> clientWrapper, const std::string& host,
-                       const std::string& uri, uint8_t connectivityType, bool observable,
+                       const std::string& uri, const std::string& serverId,
+                       uint8_t connectivityType, bool observable,
                        const std::vector<std::string>& resourceTypes,
                        const std::vector<std::string>& interfaces)
- :  m_clientWrapper(clientWrapper), m_uri(uri), m_connectivityType(connectivityType),
+ :  m_clientWrapper(clientWrapper), m_uri(uri), m_resourceId(serverId, m_uri),
+    m_connectivityType(connectivityType),
     m_host(host), m_isObservable(observable),
     m_isCollection(false), m_resourceTypes(resourceTypes), m_interfaces(interfaces),
     m_observeHandle(nullptr)
@@ -51,11 +55,12 @@ OCResource::OCResource(std::weak_ptr<IClientWrapper> clientWrapper, const std::s
 }
 #else
 OCResource::OCResource(std::weak_ptr<IClientWrapper> clientWrapper, const std::string& host,
-                       const std::string& uri, bool observable, const std::vector<std::string>& resourceTypes,
+                       const std::string& uri, const std::string& serverId, bool observable,
+                       const std::vector<std::string>& resourceTypes,
                        const std::vector<std::string>& interfaces)
- :  m_clientWrapper(clientWrapper), m_uri(uri), m_host(host), m_isObservable(observable),
-    m_isCollection(false), m_resourceTypes(resourceTypes), m_interfaces(interfaces),
-    m_observeHandle(nullptr)
+ :  m_clientWrapper(clientWrapper), m_uri(uri), m_resourceId(serverId, m_uri), m_host(host),
+    m_isObservable(observable), m_isCollection(false), m_resourceTypes(resourceTypes),
+    m_interfaces(interfaces), m_observeHandle(nullptr)
 {
     m_isCollection = std::find(m_interfaces.begin(), m_interfaces.end(), LINK_INTERFACE)
                         != m_interfaces.end();
@@ -331,4 +336,99 @@ bool OCResource::isObservable() const
     return m_isObservable;
 }
 
+
+OCResourceIdentifier OCResource::uniqueIdentifier() const
+{
+    return m_resourceId;
+}
+
+std::string OCResource::sid() const
+{
+    std::ostringstream os;
+    os << this->uniqueIdentifier().m_representation;
+    return os.str();
+}
+
+bool OCResource::operator==(const OCResource &other) const
+{
+    return m_resourceId == other.m_resourceId;
+}
+
+bool OCResource::operator!=(const OCResource &other) const
+{
+    return m_resourceId != other.m_resourceId;
+}
+
+bool OCResource::operator<(const OCResource &other) const
+{
+    return m_resourceId < other.m_resourceId;
+}
+
+bool OCResource::operator>(const OCResource &other) const
+{
+    return m_resourceId > other.m_resourceId;
+}
+
+bool OCResource::operator<=(const OCResource &other) const
+{
+    return m_resourceId <= other.m_resourceId;
+}
+
+bool OCResource::operator>=(const OCResource &other) const
+{
+    return m_resourceId >= other.m_resourceId;
+}
+
+OCResourceIdentifier::OCResourceIdentifier(const std::string& wireServerIdentifier,
+        const std::string& resourceUri)
+    :m_representation(0), m_resourceUri(resourceUri)
+{
+    // test required so we can create Resources without a server. Will leave as default.
+    if(!wireServerIdentifier.empty())
+    {
+        m_representation = boost::lexical_cast<unsigned int>(wireServerIdentifier);
+    }
+}
+
+ostream& operator <<(ostream& os, const OCResourceIdentifier& ri)
+{
+
+    os << ri.m_representation<<ri.m_resourceUri;
+
+    return os;
+}
+
+bool OCResourceIdentifier::operator==(const OCResourceIdentifier &other) const
+{
+    return m_representation == other.m_representation
+        && m_resourceUri == other.m_resourceUri;
+}
+
+bool OCResourceIdentifier::operator!=(const OCResourceIdentifier &other) const
+{
+    return !(*this == other);
+}
+
+bool OCResourceIdentifier::operator<(const OCResourceIdentifier &other) const
+{
+    return m_resourceUri < other.m_resourceUri
+        || (m_resourceUri == other.m_resourceUri &&
+                m_representation < other.m_representation);
+}
+
+bool OCResourceIdentifier::operator>(const OCResourceIdentifier &other) const
+{
+    return *this != other && !(*this<other);
+}
+
+bool OCResourceIdentifier::operator<=(const OCResourceIdentifier &other) const
+{
+    return !(*this > other);
+}
+
+bool OCResourceIdentifier::operator>=(const OCResourceIdentifier &other) const
+{
+    return !(*this < other);
+}
+
 } // namespace OC