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