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