Modifying version number for building on tizen 3.0
[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                 tempResource = OCPlatform::constructResourceObject(host, uri, true,
280                         oit->getResourceTypes(), m_if);
281
282                 p_resources.push_back(tempResource);
283             }
284
285             // Send GET messages to the child resources in turn.
286             for (unsigned int i = 0; i < p_resources.size(); ++i)
287             {
288                 resource = p_resources.at(i);
289                 if (resource)
290                 {
291                     try
292                     {
293                         if (isSimpleResource(resource))
294                         {
295                             QueryParamsMap test;
296                             resource->get(test, getCallback(conf));
297                         }
298                         else
299                         {
300                             QueryParamsMap test;
301                             resource->get(resource->getResourceTypes().at(0), BATCH_INTERFACE, test,
302                                     getCallback(conf));
303                         }
304                     }
305                     catch (OCException& e)
306                     {
307                         std::cout << e.reason() << std::endl;
308                     }
309
310                 }
311             }
312         }
313         else
314         {
315             std::cout << "onPut Response error: " << eCode << std::endl;
316             std::exit(-1);
317         }
318     }
319
320     void ThingsConfiguration::onCreateActionSet(const HeaderOptions& headerOptions,
321             const OCRepresentation& rep, const int eCode, std::string conf)
322     {
323         if (eCode == SUCCESS_RESPONSE)
324         {
325             std::cout << "PUT request was successful" << std::endl;
326
327             std::shared_ptr < OCResource > resource = getResource(conf);
328             if (resource)
329             {
330                 // Now, it is time to execute the action set.
331                 g_groupmanager->executeActionSet(resource, conf,
332                         std::function<
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)));
338             }
339         }
340         else
341         {
342             std::cout << "onPut Response error: " << eCode << std::endl;
343             std::exit(-1);
344         }
345     }
346
347     void ThingsConfiguration::onExecuteForGroupAction(const HeaderOptions& headerOptions,
348             const OCRepresentation& rep, const int eCode, std::string conf)
349     {
350         if (eCode == SUCCESS_RESPONSE)
351         {
352             std::cout << "PUT request was successful" << std::endl;
353
354             getCallback(conf)(headerOptions, rep, eCode);
355         }
356         else
357         {
358             std::cout << "onPut Response error: " << eCode << std::endl;
359             std::exit(-1);
360         }
361     }
362
363     bool ThingsConfiguration::isSimpleResource(std::shared_ptr< OCResource > resource)
364     {
365
366         for (unsigned int i = 0; i < resource->getResourceTypes().size(); ++i)
367         {
368             if (resource->getResourceTypes().at(i).find(".resourceset", 0) != std::string::npos)
369                 return false;
370         }
371
372         return true;
373     }
374
375     bool ThingsConfiguration::hasBatchInterface(std::shared_ptr< OCResource > resource)
376     {
377         for (unsigned int i = 0; i < resource->getResourceInterfaces().size(); ++i)
378         {
379             if (resource->getResourceInterfaces().at(i) == BATCH_INTERFACE)
380                 return true;
381         }
382
383         return false;
384     }
385
386     void ThingsConfiguration::onGet(const HeaderOptions& headerOptions, const OCRepresentation& rep,
387             const int eCode, std::string conf)
388     {
389         if (eCode == SUCCESS_RESPONSE)
390         {
391             std::cout << "Get request was successful" << std::endl;
392
393             getCallback(conf)(headerOptions, rep, eCode);
394         }
395         else
396         {
397             std::cout << "onPut Response error: " << eCode << std::endl;
398             std::exit(-1);
399         }
400     }
401
402     void ThingsConfiguration::onPut(const HeaderOptions& headerOptions, const OCRepresentation& rep,
403             const int eCode, std::string conf)
404     {
405         if (eCode == SUCCESS_RESPONSE)
406         {
407             std::cout << "PUT request was successful" << std::endl;
408
409             // Callback
410             getCallback(conf)(headerOptions, rep, eCode);
411         }
412         else
413         {
414             std::cout << "onPut Response error: " << eCode << std::endl;
415             std::exit(-1);
416         }
417     }
418
419     OCStackResult ThingsConfiguration::updateConfigurations(std::shared_ptr< OCResource > resource,
420             std::map< ConfigurationName, ConfigurationValue > configurations,
421             ConfigurationCallback callback)
422     {
423         // For M2, # of configurations is 1
424         // First, mapping a semantic name(ConfigurationUnit) into resource's name(uri ...)
425         if (configurations.size() == 0)
426         {
427             std::cout << "# of request configuration is 0" << std::endl;
428             return OC_STACK_ERROR;
429         }
430
431         if (!resource)
432         {
433             std::cout << "resource is NULL\n";
434             return OC_STACK_ERROR;
435         }
436
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
440
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);
446
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));
450
451         OCRepresentation rep;
452         QueryParamsMap query;
453         if (isSimpleResource(resource))
454         {
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,
458                     std::function<
459                             void(const HeaderOptions& headerOptions, const OCRepresentation& rep,
460                                     const int eCode) >(
461                             std::bind(&ThingsConfiguration::onGet, this, std::placeholders::_1,
462                                     std::placeholders::_2, std::placeholders::_3, conf)));
463         }
464         else
465         {
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
469             // specifies.
470             return g_groupmanager->deleteActionSet(resource, conf,
471                     std::function<
472                             void(const HeaderOptions& headerOptions, const OCRepresentation& rep,
473                                     const int eCode) >(
474                             std::bind(&ThingsConfiguration::onDeleteActionSet, this,
475                                     std::placeholders::_1, std::placeholders::_2,
476                                     std::placeholders::_3, conf)));
477         }
478     }
479
480     OCStackResult ThingsConfiguration::getConfigurations(std::shared_ptr< OCResource > resource,
481             std::vector< ConfigurationName > configurations, ConfigurationCallback callback)
482     {
483         // For M2, # of configurations is 1
484         // First, mapping a semantic name(ConfigurationUnit) into resource's name(uri ...)
485         if (configurations.size() == 0)
486         {
487             std::cout << "# of request configuration is 0" << std::endl;
488             return OC_STACK_ERROR;
489         }
490         if (!resource)
491         {
492             std::cout << "resource is NULL\n";
493             return OC_STACK_ERROR;
494         }
495
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
499
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);
505
506         // Create new request entry stored in the queue
507         ConfigurationRequestEntry newCallback(conf, callback, resource, conf);
508         configurationRequestTable.insert(std::make_pair(conf, newCallback));
509
510         QueryParamsMap query;
511         OCRepresentation rep;
512
513         if (isSimpleResource(resource))
514         {
515             // This resource is a simple resource. Just send a PUT message
516             std::string m_if = DEFAULT_INTERFACE;
517
518             if (hasBatchInterface(resource))
519                 m_if = BATCH_INTERFACE;
520
521             return resource->get(resource->getResourceTypes().at(0), m_if, query,
522                     std::function<
523                             void(const HeaderOptions& headerOptions, const OCRepresentation& rep,
524                                     const int eCode) >(
525                             std::bind(&ThingsConfiguration::onGet, this, std::placeholders::_1,
526                                     std::placeholders::_2, std::placeholders::_3, conf)));
527         }
528         else
529         {
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,
535                     std::function<
536                             void(const HeaderOptions& headerOptions, const OCRepresentation& rep,
537                                     const int eCode) >(
538                             std::bind(&ThingsConfiguration::onGetChildInfoForGet, this,
539                                     std::placeholders::_1, std::placeholders::_2,
540                                     std::placeholders::_3, conf)));
541         }
542
543     }
544
545 // callback handler on GET request
546     void ThingsConfiguration::onGetBootstrapInformation(const HeaderOptions& headerOptions,
547             const OCRepresentation& rep, const int eCode)
548     {
549         if (eCode == SUCCESS_RESPONSE)
550         {
551             g_bootstrapCallback(headerOptions, rep, eCode);
552         }
553
554         else
555         {
556             std::cout << "onGET Response error: " << eCode << std::endl;
557             std::exit(-1);
558         }
559     }
560
561     void ThingsConfiguration::onFoundBootstrapServer(
562             std::vector< std::shared_ptr< OCResource > > resources)
563     {
564         std::string resourceURI;
565         std::string hostAddress;
566
567         try
568         {
569             // Do some operations with resource object.
570             for (unsigned int i = 0; i < resources.size(); ++i)
571             {
572                 std::shared_ptr < OCResource > resource = resources.at(i);
573
574                 if (resource)
575                 { // Request configuration resources
576
577                     std::cout << "Getting bootstrap server representation on: " << DEFAULT_INTERFACE
578                             << std::endl;
579
580                     resource->get("bootstrap", DEFAULT_INTERFACE, QueryParamsMap(),
581                             &onGetBootstrapInformation);
582
583                 }
584                 else
585                 {
586                     // Resource is invalid
587                     std::cout << "Resource is invalid" << std::endl;
588                 }
589             }
590
591         }
592         catch (std::exception& e)
593         {
594             //log(e.what());
595         }
596     }
597
598     OCStackResult ThingsConfiguration::doBootstrap(ConfigurationCallback callback)
599     {
600         if(callback == NULL)
601             return OC_STACK_ERROR;
602         else
603           g_bootstrapCallback = callback;
604
605         // Find bootstrap server.
606         std::vector < std::string > type;
607         type.push_back("bootstrap");
608
609         std::cout << "Finding Bootstrap Server resource... " << std::endl;
610         return g_groupmanager->findCandidateResources(type, &onFoundBootstrapServer);
611     }
612 }