1 //******************************************************************
3 // Copyright 2014 Samsung Electronics All Rights Reserved.
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
11 // http://www.apache.org/licenses/LICENSE-2.0
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
21 /// @file ThingsConfiguration.cpp
25 #include <OCPlatform.h>
28 #include "ThingsConfiguration.h"
34 const int SUCCESS_RESPONSE = 0;
37 std::map< std::string, ConfigurationRequestEntry > configurationRequestTable;
39 ThingsConfiguration* ThingsConfiguration::thingsConfigurationInstance = NULL;
41 ConfigurationCallback g_bootstrapCallback;
43 ThingsConfiguration* ThingsConfiguration::getInstance()
45 if (thingsConfigurationInstance == NULL)
47 thingsConfigurationInstance = new ThingsConfiguration();
49 return thingsConfigurationInstance;
52 void ThingsConfiguration::deleteInstance()
54 if (thingsConfigurationInstance)
56 delete thingsConfigurationInstance;
57 thingsConfigurationInstance = NULL;
61 std::string ThingsConfiguration::getAttributeByConfigurationName(ConfigurationName name)
63 for (auto it = ConfigurationUnitTable.begin(); ConfigurationUnitTable.end() != it; it++)
65 if ((*it).m_name == name)
66 return (*it).m_attribute;
72 std::string ThingsConfiguration::getUriByConfigurationName(ConfigurationName name)
74 for (auto it = ConfigurationUnitTable.begin(); ConfigurationUnitTable.end() != it; it++)
76 if ((*it).m_name == name)
83 std::string ThingsConfiguration::getUpdateVal(std::string conf)
85 std::map< std::string, ConfigurationRequestEntry >::iterator it =
86 configurationRequestTable.find(conf);
88 if (it == configurationRequestTable.end())
91 return it->second.m_updateVal;
94 std::shared_ptr< OCResource > ThingsConfiguration::getResource(std::string conf)
96 std::map< std::string, ConfigurationRequestEntry >::iterator it =
97 configurationRequestTable.find(conf);
99 if (it == configurationRequestTable.end())
102 return it->second.m_resource;
105 ConfigurationCallback ThingsConfiguration::getCallback(std::string conf)
107 std::map< std::string, ConfigurationRequestEntry >::iterator it =
108 configurationRequestTable.find(conf);
110 if (it == configurationRequestTable.end())
113 return it->second.m_callback;
116 std::string ThingsConfiguration::getListOfSupportedConfigurationUnits()
120 res = "{\"Configuration Units\":[";
122 auto it = ConfigurationUnitTable.begin();
125 res = res + (*it).getJSON();
128 if (it == ConfigurationUnitTable.end())
139 std::string ThingsConfiguration::getHostFromURI(std::string oldUri)
144 if ((f = oldUri.find("/factoryset/oic/")) != string::npos)
145 newUri = oldUri.replace(f, oldUri.size(), "");
146 else if ((f = oldUri.find("/oic/")) != string::npos)
147 newUri = oldUri.replace(f, oldUri.size(), "");
152 void ThingsConfiguration::onDeleteActionSet(const HeaderOptions& headerOptions,
153 const OCRepresentation& rep, const int eCode, std::string conf)
155 std::shared_ptr < OCResource > resource = getResource(conf);
157 std::cout << __func__ << std::endl;
161 QueryParamsMap query;
163 // After deletion of the left action set, find target child resource's URIs by sending
164 // GET message. Note that, this resource is surely a collection resource which has child
166 resource->get(resource->getResourceTypes().at(0), DEFAULT_INTERFACE, query,
168 void(const HeaderOptions& headerOptions, const OCRepresentation& rep,
170 std::bind(&ThingsConfiguration::onGetChildInfoForUpdate, this,
171 std::placeholders::_1, std::placeholders::_2,
172 std::placeholders::_3, conf)));
178 void ThingsConfiguration::onGetChildInfoForUpdate(const HeaderOptions& headerOptions,
179 const OCRepresentation& rep, const int eCode, std::string conf)
181 if (eCode == SUCCESS_RESPONSE)
183 std::cout << "GET request was successful" << std::endl;
185 std::cout << "\tResource URI: " << rep.getUri() << std::endl;
187 std::vector < OCRepresentation > children = rep.getChildren();
188 for (auto oit = children.begin(); oit != children.end(); ++oit)
190 std::cout << "\t\tChild Resource URI: " << oit->getUri() << std::endl;
193 // Get information by using configuration name(conf)
194 std::shared_ptr < OCResource > resource = getResource(conf);
195 std::string actionstring = conf;
196 std::string uri = getUriByConfigurationName(conf);
197 std::string attr = getAttributeByConfigurationName(conf);
204 // In this nest, we create a new action set of which name is the configuration name.
205 // Required information consists of a host address, URI, attribute key, and
207 ActionSet *newActionSet = new ActionSet();
208 newActionSet->actionsetName = conf;
210 for (auto oit = children.begin(); oit != children.end(); ++oit)
212 Action *newAction = new Action();
214 // oit->getUri() includes a host address as well as URI.
215 // We should split these to each other and only use the host address to create
216 // a child resource's URI. Note that the collection resource and its child
217 // resource are located in same host.
218 newAction->target = getHostFromURI(oit->getUri()) + uri;
220 Capability *newCapability = new Capability();
221 newCapability->capability = attr;
222 newCapability->status = getUpdateVal(conf);
224 newAction->listOfCapability.push_back(newCapability);
225 newActionSet->listOfAction.push_back(newAction);
228 // Request to create a new action set by using the above actionSet
229 g_groupmanager->addActionSet(resource, newActionSet,
231 void(const HeaderOptions& headerOptions,
232 const OCRepresentation& rep, const int eCode) >(
233 std::bind(&ThingsConfiguration::onCreateActionSet, this,
234 std::placeholders::_1, std::placeholders::_2,
235 std::placeholders::_3, conf)));
243 std::cout << "onPut Response error: " << eCode << std::endl;
248 void ThingsConfiguration::onGetChildInfoForGet(const HeaderOptions& headerOptions,
249 const OCRepresentation& rep, const int eCode, std::string conf)
251 if (eCode == SUCCESS_RESPONSE)
253 std::cout << "GET request was successful" << std::endl;
254 std::cout << "\tResource URI: " << rep.getUri() << std::endl;
256 std::shared_ptr< OCResource > resource, tempResource;
257 std::vector < std::shared_ptr< OCResource > > p_resources;
258 std::vector < std::string > m_if;
259 std::string uri = getUriByConfigurationName(conf);
264 if (uri == "/oic/con" || uri == "/factoryset" || uri == "/factoryset/oic/con")
265 m_if.push_back(BATCH_INTERFACE);
267 m_if.push_back(DEFAULT_INTERFACE);
269 std::vector < OCRepresentation > children = rep.getChildren();
270 for (auto oit = children.begin(); oit != children.end(); ++oit)
272 std::cout << "\t\tChild Resource URI: " << oit->getUri() << std::endl;
274 // Using a host address and child URIs, we can dynamically create resource objects.
275 // Note that the child resources have not found before, we have no resource objects.
276 // For this reason, we create the resource objects.
278 std::string host = getHostFromURI(oit->getUri());
279 tempResource = OCPlatform::constructResourceObject(host, uri, true,
280 oit->getResourceTypes(), m_if);
282 p_resources.push_back(tempResource);
285 // Send GET messages to the child resources in turn.
286 for (unsigned int i = 0; i < p_resources.size(); ++i)
288 resource = p_resources.at(i);
293 if (isSimpleResource(resource))
296 resource->get(test, getCallback(conf));
301 resource->get(resource->getResourceTypes().at(0), BATCH_INTERFACE, test,
305 catch (OCException& e)
307 std::cout << e.reason() << std::endl;
315 std::cout << "onPut Response error: " << eCode << std::endl;
320 void ThingsConfiguration::onCreateActionSet(const HeaderOptions& headerOptions,
321 const OCRepresentation& rep, const int eCode, std::string conf)
323 if (eCode == SUCCESS_RESPONSE)
325 std::cout << "PUT request was successful" << std::endl;
327 std::shared_ptr < OCResource > resource = getResource(conf);
330 // Now, it is time to execute the action set.
331 g_groupmanager->executeActionSet(resource, conf,
333 void(const HeaderOptions& headerOptions,
334 const OCRepresentation& rep, const int eCode) >(
335 std::bind(&ThingsConfiguration::onExecuteForGroupAction, this,
336 std::placeholders::_1, std::placeholders::_2,
337 std::placeholders::_3, conf)));
342 std::cout << "onPut Response error: " << eCode << std::endl;
347 void ThingsConfiguration::onExecuteForGroupAction(const HeaderOptions& headerOptions,
348 const OCRepresentation& rep, const int eCode, std::string conf)
350 if (eCode == SUCCESS_RESPONSE)
352 std::cout << "PUT request was successful" << std::endl;
354 getCallback(conf)(headerOptions, rep, eCode);
358 std::cout << "onPut Response error: " << eCode << std::endl;
363 bool ThingsConfiguration::isSimpleResource(std::shared_ptr< OCResource > resource)
366 for (unsigned int i = 0; i < resource->getResourceTypes().size(); ++i)
368 if (resource->getResourceTypes().at(i).find(".resourceset", 0) != std::string::npos)
375 bool ThingsConfiguration::hasBatchInterface(std::shared_ptr< OCResource > resource)
377 for (unsigned int i = 0; i < resource->getResourceInterfaces().size(); ++i)
379 if (resource->getResourceInterfaces().at(i) == BATCH_INTERFACE)
386 void ThingsConfiguration::onGet(const HeaderOptions& headerOptions, const OCRepresentation& rep,
387 const int eCode, std::string conf)
389 if (eCode == SUCCESS_RESPONSE)
391 std::cout << "Get request was successful" << std::endl;
393 getCallback(conf)(headerOptions, rep, eCode);
397 std::cout << "onPut Response error: " << eCode << std::endl;
402 void ThingsConfiguration::onPut(const HeaderOptions& headerOptions, const OCRepresentation& rep,
403 const int eCode, std::string conf)
405 if (eCode == SUCCESS_RESPONSE)
407 std::cout << "PUT request was successful" << std::endl;
410 getCallback(conf)(headerOptions, rep, eCode);
414 std::cout << "onPut Response error: " << eCode << std::endl;
419 OCStackResult ThingsConfiguration::updateConfigurations(std::shared_ptr< OCResource > resource,
420 std::map< ConfigurationName, ConfigurationValue > configurations,
421 ConfigurationCallback callback)
423 // For M2, # of configurations is 1
424 // First, mapping a semantic name(ConfigurationUnit) into resource's name(uri ...)
425 if (configurations.size() == 0)
427 std::cout << "# of request configuration is 0" << std::endl;
428 return OC_STACK_ERROR;
433 std::cout << "resource is NULL\n";
434 return OC_STACK_ERROR;
437 std::map< ConfigurationName, ConfigurationValue >::iterator it = configurations.begin();
438 std::string conf = it->first; // configuration name
439 std::transform(conf.begin(), conf.end(), conf.begin(), ::tolower); // to lower case
441 // Check the request queue if a previous request is still left. If so, remove it.
442 std::map< std::string, ConfigurationRequestEntry >::iterator iter =
443 configurationRequestTable.find(conf);
444 if (iter != configurationRequestTable.end())
445 configurationRequestTable.erase(iter);
447 // Create new request entry stored in the queue
448 ConfigurationRequestEntry newCallback(conf, callback, resource, it->second);
449 configurationRequestTable.insert(std::make_pair(conf, newCallback));
451 OCRepresentation rep;
452 QueryParamsMap query;
453 if (isSimpleResource(resource))
455 // This resource does not need to use a group manager. Just send a PUT message
456 rep.setValue(getAttributeByConfigurationName(conf), getUpdateVal(conf));
457 return resource->put(resource->getResourceTypes().at(0), DEFAULT_INTERFACE, rep, query,
459 void(const HeaderOptions& headerOptions, const OCRepresentation& rep,
461 std::bind(&ThingsConfiguration::onGet, this, std::placeholders::_1,
462 std::placeholders::_2, std::placeholders::_3, conf)));
466 // This resource is a collection resource which uses group manager functionalities.
467 // First, delete an existing action set of which name is same as a current action set
468 // name. As of now, the name is determined by "Configuration Name" which a user just
470 return g_groupmanager->deleteActionSet(resource, conf,
472 void(const HeaderOptions& headerOptions, const OCRepresentation& rep,
474 std::bind(&ThingsConfiguration::onDeleteActionSet, this,
475 std::placeholders::_1, std::placeholders::_2,
476 std::placeholders::_3, conf)));
480 OCStackResult ThingsConfiguration::getConfigurations(std::shared_ptr< OCResource > resource,
481 std::vector< ConfigurationName > configurations, ConfigurationCallback callback)
483 // For M2, # of configurations is 1
484 // First, mapping a semantic name(ConfigurationUnit) into resource's name(uri ...)
485 if (configurations.size() == 0)
487 std::cout << "# of request configuration is 0" << std::endl;
488 return OC_STACK_ERROR;
492 std::cout << "resource is NULL\n";
493 return OC_STACK_ERROR;
496 std::vector< ConfigurationName >::iterator it = configurations.begin();
497 std::string conf = (*it); // configuration name
498 std::transform(conf.begin(), conf.end(), conf.begin(), ::tolower); // to lower case
500 // Check the request queue if a previous request is still left. If so, remove it.
501 std::map< std::string, ConfigurationRequestEntry >::iterator iter =
502 configurationRequestTable.find(conf);
503 if (iter != configurationRequestTable.end())
504 configurationRequestTable.erase(iter);
506 // Create new request entry stored in the queue
507 ConfigurationRequestEntry newCallback(conf, callback, resource, conf);
508 configurationRequestTable.insert(std::make_pair(conf, newCallback));
510 QueryParamsMap query;
511 OCRepresentation rep;
513 if (isSimpleResource(resource))
515 // This resource is a simple resource. Just send a PUT message
516 std::string m_if = DEFAULT_INTERFACE;
518 if (hasBatchInterface(resource))
519 m_if = BATCH_INTERFACE;
521 return resource->get(resource->getResourceTypes().at(0), m_if, query,
523 void(const HeaderOptions& headerOptions, const OCRepresentation& rep,
525 std::bind(&ThingsConfiguration::onGet, this, std::placeholders::_1,
526 std::placeholders::_2, std::placeholders::_3, conf)));
530 // This resource is a collection resource. On the contrary of a update, it does not use
531 // group manager functionality. It just acquires child resource's URI and send GET
532 // massages to the child resources in turn.
533 // First, request the child resources's URI.
534 return resource->get(resource->getResourceTypes().at(0), DEFAULT_INTERFACE, query,
536 void(const HeaderOptions& headerOptions, const OCRepresentation& rep,
538 std::bind(&ThingsConfiguration::onGetChildInfoForGet, this,
539 std::placeholders::_1, std::placeholders::_2,
540 std::placeholders::_3, conf)));
545 // callback handler on GET request
546 void ThingsConfiguration::onGetBootstrapInformation(const HeaderOptions& headerOptions,
547 const OCRepresentation& rep, const int eCode)
549 if (eCode == SUCCESS_RESPONSE)
551 g_bootstrapCallback(headerOptions, rep, eCode);
556 std::cout << "onGET Response error: " << eCode << std::endl;
561 void ThingsConfiguration::onFoundBootstrapServer(
562 std::vector< std::shared_ptr< OCResource > > resources)
564 std::string resourceURI;
565 std::string hostAddress;
569 // Do some operations with resource object.
570 for (unsigned int i = 0; i < resources.size(); ++i)
572 std::shared_ptr < OCResource > resource = resources.at(i);
575 { // Request configuration resources
577 std::cout << "Getting bootstrap server representation on: " << DEFAULT_INTERFACE
580 resource->get("bootstrap", DEFAULT_INTERFACE, QueryParamsMap(),
581 &onGetBootstrapInformation);
586 // Resource is invalid
587 std::cout << "Resource is invalid" << std::endl;
592 catch (std::exception& e)
598 OCStackResult ThingsConfiguration::doBootstrap(ConfigurationCallback callback)
601 return OC_STACK_ERROR;
603 g_bootstrapCallback = callback;
605 // Find bootstrap server.
606 std::vector < std::string > type;
607 type.push_back("bootstrap");
609 std::cout << "Finding Bootstrap Server resource... " << std::endl;
610 return g_groupmanager->findCandidateResources(type, &onFoundBootstrapServer);