// 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;
// 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)
{
#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
// 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;
// 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)
{
#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
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
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;
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
}
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;
}
std::string m_uri;
+ std::string m_serverId;
bool m_loaded;
ListenResourcePropertiesContainer m_props;
else
{
oclog() << "ConvertOCAddrToString(): Invalid Ip"
- << std::flush;
+ << std::flush;
throw ResourceInitException(false, false, false, false, false, true);
}
else
{
oclog() << "ConvertOCAddrToString() : Invalid Port"
- <<std::flush;
+ <<std::flush;
throw ResourceInitException(false, false, false, false, true, false);
}
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
}
static const std::string REPKEY = "rep";
static const std::string SECUREKEY = "sec";
static const std::string PORTKEY = "port";
- }
+ static const std::string SERVERIDKEY = "sid";
+ }
}
{
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;
return std::shared_ptr<OCResource>(new OCResource(m_client,
host,
- uri, connectivityType,
+ uri, "", connectivityType,
isObservable,
resourceTypes,
interfaces));
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));
#include "OCResource.h"
#include "OCUtilities.h"
+#include <boost/lexical_cast.hpp>
+
namespace OC {
using OC::nil_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)
}
#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();
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