Imported Upstream version 0.9.1
[platform/upstream/iotivity.git] / service / things-manager / sdk / src / ThingsConfiguration.cpp
1 //******************************************************************
2 //
3 // Copyright 2014 Samsung Electronics All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
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
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
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.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 /**
22  * @file
23  *
24  */
25
26 #include <OCApi.h>
27 #include <OCPlatform.h>
28 #include <cstdlib>
29 #include <algorithm>
30 #include "ThingsConfiguration.h"
31
32 using namespace OC;
33
34 namespace OIC
35 {
36     int cnt = 0;
37
38     std::map< std::string, ConfigurationRequestEntry > configurationRequestTable;
39     ThingsConfiguration* ThingsConfiguration::thingsConfigurationInstance = NULL;
40     ConfigurationCallback g_bootstrapCallback;
41
42     ConfigurationRequestEntry::ConfigurationRequestEntry(std::string ID,
43                                                         ConfigurationCallback callback,
44                                                         std::shared_ptr< OCResource > resource,
45                                                         std::string updateVal)
46     {
47         m_ID = ID;
48         m_callback = callback;
49         m_resource = resource;
50         m_updateVal = updateVal;
51     }
52
53     ConfigurationUnitInfo::ConfigurationUnitInfo(std::string name,
54                                                 std::string attribute,
55                                                 std::string uri)
56     {
57         m_name = name;
58         m_attribute = attribute;
59         m_uri = uri;
60     }
61
62     std::string ConfigurationUnitInfo::getJSON()
63     {
64         std::string res;
65
66         res = "{\"name\":\"" + m_name + "\",\"property\":\"" + m_attribute + "\"}";
67
68         return res;
69     }
70
71     ThingsConfiguration::ThingsConfiguration(void)
72     {
73         ConfigurationUnitInfo unit[] =
74         {
75         { "all", "All attributes", "/oic/con" },
76         { "r", "Region", "/oic/con" },
77         { "st", "System Time", "/oic/con"},
78         { "loc", "Location", "/oic/con"},
79         { "c","Currency", "/oic/con" } };
80
81         for (int i = 0; i < NUMCONFUNIT; i++)
82             ConfigurationUnitTable.push_back(unit[i]);
83     }
84
85     ThingsConfiguration::~ThingsConfiguration(void){}
86
87     void ThingsConfiguration::setGroupManager(GroupManager *groupmanager)
88     {
89         g_groupmanager = groupmanager;
90     }
91
92     ThingsConfiguration* ThingsConfiguration::getInstance()
93     {
94         if (thingsConfigurationInstance == NULL)
95         {
96             thingsConfigurationInstance = new ThingsConfiguration();
97         }
98         return thingsConfigurationInstance;
99     }
100
101     void ThingsConfiguration::deleteInstance()
102     {
103         if (thingsConfigurationInstance)
104         {
105             delete thingsConfigurationInstance;
106             thingsConfigurationInstance = NULL;
107         }
108     }
109
110     std::string ThingsConfiguration::getAttributeByConfigurationName(ConfigurationName name)
111     {
112         for (auto it = ConfigurationUnitTable.begin(); ConfigurationUnitTable.end() != it; it++)
113         {
114             if ((*it).m_name == name)
115                 return (*it).m_attribute;
116         }
117
118         return "";
119     }
120
121     std::string ThingsConfiguration::getUriByConfigurationName(ConfigurationName name)
122     {
123         for (auto it = ConfigurationUnitTable.begin(); ConfigurationUnitTable.end() != it; it++)
124         {
125             if ((*it).m_name == name)
126                 return (*it).m_uri;
127         }
128
129         return "";
130     }
131
132     std::string ThingsConfiguration::getUpdateVal(std::string conf)
133     {
134         std::map< std::string, ConfigurationRequestEntry >::iterator it =
135                 configurationRequestTable.find(conf);
136
137         if (it == configurationRequestTable.end())
138             return NULL;
139         else
140             return it->second.m_updateVal;
141
142     }
143     std::shared_ptr< OCResource > ThingsConfiguration::getResource(std::string conf)
144     {
145         std::map< std::string, ConfigurationRequestEntry >::iterator it =
146                 configurationRequestTable.find(conf);
147
148         if (it == configurationRequestTable.end())
149             return NULL;
150         else
151             return it->second.m_resource;
152     }
153
154     ConfigurationCallback ThingsConfiguration::getCallback(std::string conf)
155     {
156         std::map< std::string, ConfigurationRequestEntry >::iterator it =
157                 configurationRequestTable.find(conf);
158
159         if (it == configurationRequestTable.end())
160             return NULL;
161         else
162             return it->second.m_callback;
163     }
164
165     std::string ThingsConfiguration::getListOfSupportedConfigurationUnits()
166     {
167         std::string res;
168
169         res = "{\"Configuration Units\":[";
170
171         auto it = ConfigurationUnitTable.begin();
172         while (1)
173         {
174             res = res + (*it).getJSON();
175             it++;
176
177             if (it == ConfigurationUnitTable.end())
178                 break;
179             else
180                 res += ",";
181         }
182
183         res += "]}";
184
185         return res;
186     }
187
188     std::string ThingsConfiguration::getHostFromURI(std::string oldUri)
189     {
190         size_t f;
191         std::string newUri;
192
193         if ((f = oldUri.find("/factoryset/oic/")) != string::npos)
194             newUri = oldUri.replace(f, oldUri.size(), "");
195         else if ((f = oldUri.find("/oic/")) != string::npos)
196             newUri = oldUri.replace(f, oldUri.size(), "");
197
198         return newUri;
199     }
200
201     void ThingsConfiguration::onDeleteActionSet(const HeaderOptions& headerOptions,
202             const OCRepresentation& rep, const int eCode, std::string conf)
203     {
204         std::shared_ptr < OCResource > resource = getResource(conf);
205
206         if (resource)
207         {
208             QueryParamsMap query;
209
210             // After deletion of the left action set, find target child resource's URIs by sending
211             // GET message. Note that, this resource is surely a collection resource which has child
212             // resources.
213             resource->get(resource->getResourceTypes().at(0), DEFAULT_INTERFACE, query,
214                     std::function<
215                             void(const HeaderOptions& headerOptions, const OCRepresentation& rep,
216                                     const int eCode) >(
217                             std::bind(&ThingsConfiguration::onGetChildInfoForUpdate, this,
218                                     std::placeholders::_1, std::placeholders::_2,
219                                     std::placeholders::_3, conf)));
220         }
221
222     }
223
224     void ThingsConfiguration::onGetChildInfoForUpdate(const HeaderOptions& headerOptions,
225             const OCRepresentation& rep, const int eCode, std::string conf)
226     {
227         if (eCode != OC_STACK_OK)
228         {
229             std::cout << "onPut Response error: " << eCode << std::endl;
230             getCallback(conf)(headerOptions, rep, eCode);
231             return ;
232         }
233
234         std::cout << "GET request was successful" << std::endl;
235
236         std::cout << "\tResource URI: " << rep.getUri() << std::endl;
237
238         std::vector < OCRepresentation > children = rep.getChildren();
239         for (auto oit = children.begin(); oit != children.end(); ++oit)
240         {
241             std::cout << "\t\tChild Resource URI: " << oit->getUri() << std::endl;
242         }
243
244         // Get information by using configuration name(conf)
245         std::shared_ptr < OCResource > resource = getResource(conf);
246         std::string actionstring = conf;
247         std::string uri = getUriByConfigurationName(conf);
248         std::string attrKey = conf;
249
250         if (uri == "")
251             return;
252
253         if (resource)
254         {
255             // In this nest, we create a new action set of which name is the configuration name.
256             // Required information consists of a host address, URI, attribute key, and
257             // attribute value.
258             ActionSet *newActionSet = new ActionSet();
259             newActionSet->actionsetName = conf;
260
261             for (auto oit = children.begin(); oit != children.end(); ++oit)
262             {
263                 Action *newAction = new Action();
264
265                 // oit->getUri() includes a host address as well as URI.
266                 // We should split these to each other and only use the host address to create
267                 // a child resource's URI. Note that the collection resource and its child
268                 // resource are located in same host.
269                 newAction->target = getHostFromURI(oit->getUri()) + uri;
270
271                 Capability *newCapability = new Capability();
272                 newCapability->capability = attrKey;
273                 newCapability->status = getUpdateVal(conf);
274
275                 newAction->listOfCapability.push_back(newCapability);
276                 newActionSet->listOfAction.push_back(newAction);
277             }
278
279             // Request to create a new action set by using the above actionSet
280             g_groupmanager->addActionSet(resource, newActionSet,
281                     std::function<
282                             void(const HeaderOptions& headerOptions,
283                                     const OCRepresentation& rep, const int eCode) >(
284                             std::bind(&ThingsConfiguration::onCreateActionSet, this,
285                                     std::placeholders::_1, std::placeholders::_2,
286                                     std::placeholders::_3, conf)));
287
288             free(newActionSet);
289         }
290     }
291
292     void ThingsConfiguration::onGetChildInfoForGet(const HeaderOptions& headerOptions,
293             const OCRepresentation& rep, const int eCode, std::string conf)
294     {
295         if (eCode != OC_STACK_OK)
296         {
297             std::cout << "onGet Response error: " << eCode << std::endl;
298             getCallback(conf)(headerOptions, rep, eCode);
299             return ;
300         }
301
302         std::cout << "GET request was successful" << std::endl;
303         std::cout << "\tResource URI: " << rep.getUri() << std::endl;
304
305         std::shared_ptr< OCResource > resource, tempResource;
306         std::vector < std::shared_ptr< OCResource > > p_resources;
307         std::vector < std::string > m_if;
308         std::string uri = getUriByConfigurationName(conf);
309
310         if (uri == "")
311             return;
312
313         if (uri == "/factoryset" || uri == "/factoryset/oic/con")
314             m_if.push_back(BATCH_INTERFACE);
315         else
316             m_if.push_back(DEFAULT_INTERFACE);
317
318         std::vector < OCRepresentation > children = rep.getChildren();
319         for (auto oit = children.begin(); oit != children.end(); ++oit)
320         {
321             std::cout << "\t\tChild Resource URI: " << oit->getUri() << std::endl;
322
323             // Using a host address and child URIs, we can dynamically create resource objects.
324             // Note that the child resources have not found before, we have no resource objects.
325             // For this reason, we create the resource objects.
326
327             std::string host = getHostFromURI(oit->getUri());
328
329             tempResource = OCPlatform::constructResourceObject(host, uri, OC_IPV4, true,
330                     oit->getResourceTypes(), m_if);
331
332             p_resources.push_back(tempResource);
333         }
334
335         // Send GET messages to the child resources in turn.
336         for (unsigned int i = 0; i < p_resources.size(); ++i)
337         {
338             resource = p_resources.at(i);
339             if (resource)
340             {
341                 try
342                 {
343                     QueryParamsMap test;
344                     resource->get(test, getCallback(conf));
345                 }
346                 catch (OCException& e)
347                 {
348                     std::cout << e.reason() << std::endl;
349                 }
350
351             }
352         }
353     }
354
355     void ThingsConfiguration::onCreateActionSet(const HeaderOptions& headerOptions,
356             const OCRepresentation& rep, const int eCode, std::string conf)
357     {
358         if (eCode != OC_STACK_OK)
359         {
360             std::cout << "onPut Response error: " << eCode << std::endl;
361             getCallback(conf)(headerOptions, rep, eCode);
362             return ;
363         }
364
365         std::cout << "PUT request was successful" << std::endl;
366
367         std::shared_ptr < OCResource > resource = getResource(conf);
368         if (resource)
369         {
370             // Now, it is time to execute the action set.
371             g_groupmanager->executeActionSet(resource, conf,
372                     std::function<
373                             void(const HeaderOptions& headerOptions,
374                                     const OCRepresentation& rep, const int eCode) >(
375                             std::bind(&ThingsConfiguration::onExecuteForGroupAction, this,
376                                     std::placeholders::_1, std::placeholders::_2,
377                                     std::placeholders::_3, conf)));
378         }
379     }
380
381     void ThingsConfiguration::onExecuteForGroupAction(const HeaderOptions& headerOptions,
382             const OCRepresentation& rep, const int eCode, std::string conf)
383     {
384         if (eCode != OC_STACK_OK)
385         {
386             std::cout << "onPut Response error: " << eCode << std::endl;
387             getCallback(conf)(headerOptions, rep, eCode);
388             return ;
389         }
390
391         std::cout << "PUT request was successful" << std::endl;
392
393         getCallback(conf)(headerOptions, rep, eCode);
394     }
395
396     bool ThingsConfiguration::isSimpleResource(std::shared_ptr< OCResource > resource)
397     {
398
399         for (unsigned int i = 0; i < resource->getResourceTypes().size(); ++i)
400         {
401             if (resource->getResourceTypes().at(i).find(".resourceset", 0) != std::string::npos)
402                 return false;
403         }
404
405         return true;
406     }
407
408     bool ThingsConfiguration::hasBatchInterface(std::shared_ptr< OCResource > resource)
409     {
410         for (unsigned int i = 0; i < resource->getResourceInterfaces().size(); ++i)
411         {
412             if (resource->getResourceInterfaces().at(i) == BATCH_INTERFACE)
413                 return true;
414         }
415
416         return false;
417     }
418
419     void ThingsConfiguration::onGet(const HeaderOptions& headerOptions, const OCRepresentation& rep,
420             const int eCode, std::string conf)
421     {
422         if (eCode != OC_STACK_OK)
423         {
424             std::cout << "onGet Response error: " << eCode << std::endl;
425             getCallback(conf)(headerOptions, rep, eCode);
426             return ;
427         }
428
429         std::cout << "Get request was successful" << std::endl;
430
431         getCallback(conf)(headerOptions, rep, eCode);
432     }
433
434     void ThingsConfiguration::onPut(const HeaderOptions& headerOptions, const OCRepresentation& rep,
435             const int eCode, std::string conf)
436     {
437         if (eCode != OC_STACK_OK)
438         {
439             std::cout << "onPut Response error: " << eCode << std::endl;
440             getCallback(conf)(headerOptions, rep, eCode);
441             return;
442         }
443
444         std::cout << "PUT request was successful" << std::endl;
445
446         getCallback(conf)(headerOptions, rep, eCode);
447     }
448
449     OCStackResult ThingsConfiguration::updateConfigurations(std::shared_ptr< OCResource > resource,
450             std::map< ConfigurationName, ConfigurationValue > configurations,
451             ConfigurationCallback callback)
452     {
453         // For M2, # of configurations is 1
454         // First, mapping a semantic name(ConfigurationUnit) into resource's name(uri ...)
455         if (configurations.size() == 0)
456         {
457             std::cout << "# of request configuration is 0" << std::endl;
458             return OC_STACK_ERROR;
459         }
460
461         if (!resource)
462         {
463             std::cout << "resource is NULL\n";
464             return OC_STACK_ERROR;
465         }
466
467         std::map< ConfigurationName, ConfigurationValue >::iterator it = configurations.begin();
468         std::string conf = it->first; // configuration name
469         std::transform(conf.begin(), conf.end(), conf.begin(), ::tolower); // to lower case
470
471         // Check the request queue if a previous request is still left. If so, remove it.
472         std::map< std::string, ConfigurationRequestEntry >::iterator iter =
473                 configurationRequestTable.find(conf);
474         if (iter != configurationRequestTable.end())
475             configurationRequestTable.erase(iter);
476
477         // Create new request entry stored in the queue
478         ConfigurationRequestEntry newCallback(conf, callback, resource, it->second);
479         configurationRequestTable.insert(std::make_pair(conf, newCallback));
480
481         OCRepresentation rep;
482         QueryParamsMap query;
483         if (isSimpleResource(resource))
484         {
485             // This resource does not need to use a group manager. Just send a PUT message
486             rep.setValue(conf, getUpdateVal(conf));
487             return resource->put(resource->getResourceTypes().at(0), DEFAULT_INTERFACE, rep, query,
488                     std::function<
489                             void(const HeaderOptions& headerOptions, const OCRepresentation& rep,
490                                     const int eCode) >(
491                             std::bind(&ThingsConfiguration::onGet, this, std::placeholders::_1,
492                                     std::placeholders::_2, std::placeholders::_3, conf)));
493         }
494         else
495         {
496             // This resource is a collection resource which uses group manager functionalities.
497             // First, delete an existing action set of which name is same as a current action set
498             // name. As of now, the name is determined by "Configuration Name" which a user just
499             // specifies.
500             return g_groupmanager->deleteActionSet(resource, conf,
501                     std::function<
502                             void(const HeaderOptions& headerOptions, const OCRepresentation& rep,
503                                     const int eCode) >(
504                             std::bind(&ThingsConfiguration::onDeleteActionSet, this,
505                                     std::placeholders::_1, std::placeholders::_2,
506                                     std::placeholders::_3, conf)));
507         }
508     }
509
510     OCStackResult ThingsConfiguration::getConfigurations(std::shared_ptr< OCResource > resource,
511             std::vector< ConfigurationName > configurations, ConfigurationCallback callback)
512     {
513         // For M2, # of configurations is 1
514         // First, mapping a semantic name(ConfigurationUnit) into resource's name(uri ...)
515         if (configurations.size() == 0)
516         {
517             std::cout << "# of request configuration is 0" << std::endl;
518             return OC_STACK_ERROR;
519         }
520         if (!resource)
521         {
522             std::cout << "resource is NULL\n";
523             return OC_STACK_ERROR;
524         }
525
526         std::vector< ConfigurationName >::iterator it = configurations.begin();
527         std::string conf = (*it); // configuration name
528         std::transform(conf.begin(), conf.end(), conf.begin(), ::tolower); // to lower case
529
530         // Check the request queue if a previous request is still left. If so, remove it.
531         std::map< std::string, ConfigurationRequestEntry >::iterator iter =
532                 configurationRequestTable.find(conf);
533         if (iter != configurationRequestTable.end())
534             configurationRequestTable.erase(iter);
535
536         // Create new request entry stored in the queue
537         ConfigurationRequestEntry newCallback(conf, callback, resource, conf);
538         configurationRequestTable.insert(std::make_pair(conf, newCallback));
539
540         QueryParamsMap query;
541         OCRepresentation rep;
542
543         if (isSimpleResource(resource))
544         {
545             // This resource is a simple resource. Just send a PUT message
546             std::string m_if = DEFAULT_INTERFACE;
547
548             if (hasBatchInterface(resource))
549                 m_if = BATCH_INTERFACE;
550
551             return resource->get(resource->getResourceTypes().at(0), m_if, query,
552                     std::function<
553                             void(const HeaderOptions& headerOptions, const OCRepresentation& rep,
554                                     const int eCode) >(
555                             std::bind(&ThingsConfiguration::onGet, this, std::placeholders::_1,
556                                     std::placeholders::_2, std::placeholders::_3, conf)));
557         }
558         else
559         {
560             // This resource is a collection resource. On the contrary of a update, it does not use
561             // group manager functionality. It just acquires child resource's URI and send GET
562             // massages to the child resources in turn.
563             // First, request the child resources's URI.
564             return resource->get(resource->getResourceTypes().at(0), DEFAULT_INTERFACE, query,
565                     std::function<
566                             void(const HeaderOptions& headerOptions, const OCRepresentation& rep,
567                                     const int eCode) >(
568                             std::bind(&ThingsConfiguration::onGetChildInfoForGet, this,
569                                     std::placeholders::_1, std::placeholders::_2,
570                                     std::placeholders::_3, conf)));
571         }
572
573     }
574
575 // callback handler on GET request
576     void ThingsConfiguration::onGetBootstrapInformation(const HeaderOptions& headerOptions,
577             const OCRepresentation& rep, const int eCode)
578     {
579         if (eCode != OC_STACK_OK)
580         {
581             std::cout << "onGET Response error: " << eCode << std::endl;
582             g_bootstrapCallback(headerOptions, rep, eCode);
583             return;
584         }
585
586         g_bootstrapCallback(headerOptions, rep, eCode);
587     }
588
589     void ThingsConfiguration::onFoundBootstrapServer(
590             std::vector< std::shared_ptr< OCResource > > resources)
591     {
592         std::string resourceURI;
593         std::string hostAddress;
594
595         try
596         {
597             // Do some operations with resource object.
598             for (unsigned int i = 0; i < resources.size(); ++i)
599             {
600                 std::shared_ptr < OCResource > resource = resources.at(i);
601
602                 if (resource)
603                 { // Request configuration resources
604
605                     std::cout << "Getting bootstrap server representation on: " << DEFAULT_INTERFACE
606                             << std::endl;
607
608                     resource->get("bootstrap", DEFAULT_INTERFACE, QueryParamsMap(),
609                             &onGetBootstrapInformation);
610
611                 }
612                 else
613                 {
614                     // Resource is invalid
615                     std::cout << "Resource is invalid" << std::endl;
616                 }
617             }
618
619         }
620         catch (std::exception& e)
621         {
622             //log(e.what());
623         }
624     }
625
626     OCStackResult ThingsConfiguration::doBootstrap(ConfigurationCallback callback)
627     {
628         if(callback == NULL)
629             return OC_STACK_ERROR;
630         else
631           g_bootstrapCallback = callback;
632
633         // Find bootstrap server.
634         std::vector < std::string > type;
635         type.push_back("bootstrap");
636
637         std::cout << "Finding Bootstrap Server resource... " << std::endl;
638         return g_groupmanager->findCandidateResources(type, &onFoundBootstrapServer);
639     }
640 }
641