Modify the term "Diagnostics" to "Maintenance" in file names
[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             tempResource = OCPlatform::constructResourceObject(host, uri, CT_ADAPTER_IP, true,
331                     oit->getResourceTypes(), m_if);
332
333             p_resources.push_back(tempResource);
334         }
335
336         // Send GET messages to the child resources in turn.
337         for (unsigned int i = 0; i < p_resources.size(); ++i)
338         {
339             resource = p_resources.at(i);
340             if (resource)
341             {
342                 try
343                 {
344                     QueryParamsMap test;
345                     resource->get(test, getCallback(conf));
346                 }
347                 catch (OCException& e)
348                 {
349                     std::cout << e.reason() << std::endl;
350                 }
351
352             }
353         }
354     }
355
356     void ThingsConfiguration::onCreateActionSet(const HeaderOptions& headerOptions,
357             const OCRepresentation& rep, const int eCode, std::string conf)
358     {
359         if (eCode != OC_STACK_OK)
360         {
361             std::cout << "onPut Response error: " << eCode << std::endl;
362             getCallback(conf)(headerOptions, rep, eCode);
363             return ;
364         }
365
366         std::cout << "PUT request was successful" << std::endl;
367
368         std::shared_ptr < OCResource > resource = getResource(conf);
369         if (resource)
370         {
371             // Now, it is time to execute the action set.
372             g_groupmanager->executeActionSet(resource, conf,
373                     std::function<
374                             void(const HeaderOptions& headerOptions,
375                                     const OCRepresentation& rep, const int eCode) >(
376                             std::bind(&ThingsConfiguration::onExecuteForGroupAction, this,
377                                     std::placeholders::_1, std::placeholders::_2,
378                                     std::placeholders::_3, conf)));
379         }
380     }
381
382     void ThingsConfiguration::onExecuteForGroupAction(const HeaderOptions& headerOptions,
383             const OCRepresentation& rep, const int eCode, std::string conf)
384     {
385         if (eCode != OC_STACK_OK)
386         {
387             std::cout << "onPut Response error: " << eCode << std::endl;
388             getCallback(conf)(headerOptions, rep, eCode);
389             return ;
390         }
391
392         std::cout << "PUT request was successful" << std::endl;
393
394         getCallback(conf)(headerOptions, rep, eCode);
395     }
396
397     bool ThingsConfiguration::isSimpleResource(std::shared_ptr< OCResource > resource)
398     {
399
400         for (unsigned int i = 0; i < resource->getResourceTypes().size(); ++i)
401         {
402             if (resource->getResourceTypes().at(i).find(".resourceset", 0) != std::string::npos)
403                 return false;
404         }
405
406         return true;
407     }
408
409     bool ThingsConfiguration::hasBatchInterface(std::shared_ptr< OCResource > resource)
410     {
411         for (unsigned int i = 0; i < resource->getResourceInterfaces().size(); ++i)
412         {
413             if (resource->getResourceInterfaces().at(i) == BATCH_INTERFACE)
414                 return true;
415         }
416
417         return false;
418     }
419
420     void ThingsConfiguration::onGet(const HeaderOptions& headerOptions, const OCRepresentation& rep,
421             const int eCode, std::string conf)
422     {
423         if (eCode != OC_STACK_OK)
424         {
425             std::cout << "onGet Response error: " << eCode << std::endl;
426             getCallback(conf)(headerOptions, rep, eCode);
427             return ;
428         }
429
430         std::cout << "Get request was successful" << std::endl;
431
432         getCallback(conf)(headerOptions, rep, eCode);
433     }
434
435     void ThingsConfiguration::onPut(const HeaderOptions& headerOptions, const OCRepresentation& rep,
436             const int eCode, std::string conf)
437     {
438         if (eCode != OC_STACK_OK)
439         {
440             std::cout << "onPut Response error: " << eCode << std::endl;
441             getCallback(conf)(headerOptions, rep, eCode);
442             return;
443         }
444
445         std::cout << "PUT request was successful" << std::endl;
446
447         getCallback(conf)(headerOptions, rep, eCode);
448     }
449
450     OCStackResult ThingsConfiguration::updateConfigurations(std::shared_ptr< OCResource > resource,
451             std::map< ConfigurationName, ConfigurationValue > configurations,
452             ConfigurationCallback callback)
453     {
454         // For M2, # of configurations is 1
455         // First, mapping a semantic name(ConfigurationUnit) into resource's name(uri ...)
456         if (configurations.size() == 0)
457         {
458             std::cout << "# of request configuration is 0" << std::endl;
459             return OC_STACK_ERROR;
460         }
461
462         if (!resource)
463         {
464             std::cout << "resource is NULL\n";
465             return OC_STACK_ERROR;
466         }
467
468         std::map< ConfigurationName, ConfigurationValue >::iterator it = configurations.begin();
469         std::string conf = it->first; // configuration name
470         std::transform(conf.begin(), conf.end(), conf.begin(), ::tolower); // to lower case
471
472         // Check the request queue if a previous request is still left. If so, remove it.
473         std::map< std::string, ConfigurationRequestEntry >::iterator iter =
474                 configurationRequestTable.find(conf);
475         if (iter != configurationRequestTable.end())
476             configurationRequestTable.erase(iter);
477
478         // Create new request entry stored in the queue
479         ConfigurationRequestEntry newCallback(conf, callback, resource, it->second);
480         configurationRequestTable.insert(std::make_pair(conf, newCallback));
481
482         OCRepresentation rep;
483         QueryParamsMap query;
484         if (isSimpleResource(resource))
485         {
486             // This resource does not need to use a group manager. Just send a PUT message
487             rep.setValue(conf, getUpdateVal(conf));
488             return resource->put(resource->getResourceTypes().at(0), DEFAULT_INTERFACE, rep, query,
489                     std::function<
490                             void(const HeaderOptions& headerOptions, const OCRepresentation& rep,
491                                     const int eCode) >(
492                             std::bind(&ThingsConfiguration::onGet, this, std::placeholders::_1,
493                                     std::placeholders::_2, std::placeholders::_3, conf)));
494         }
495         else
496         {
497             // This resource is a collection resource which uses group manager functionalities.
498             // First, delete an existing action set of which name is same as a current action set
499             // name. As of now, the name is determined by "Configuration Name" which a user just
500             // specifies.
501             return g_groupmanager->deleteActionSet(resource, conf,
502                     std::function<
503                             void(const HeaderOptions& headerOptions, const OCRepresentation& rep,
504                                     const int eCode) >(
505                             std::bind(&ThingsConfiguration::onDeleteActionSet, this,
506                                     std::placeholders::_1, std::placeholders::_2,
507                                     std::placeholders::_3, conf)));
508         }
509     }
510
511     OCStackResult ThingsConfiguration::getConfigurations(std::shared_ptr< OCResource > resource,
512             std::vector< ConfigurationName > configurations, ConfigurationCallback callback)
513     {
514         // For M2, # of configurations is 1
515         // First, mapping a semantic name(ConfigurationUnit) into resource's name(uri ...)
516         if (configurations.size() == 0)
517         {
518             std::cout << "# of request configuration is 0" << std::endl;
519             return OC_STACK_ERROR;
520         }
521         if (!resource)
522         {
523             std::cout << "resource is NULL\n";
524             return OC_STACK_ERROR;
525         }
526
527         std::vector< ConfigurationName >::iterator it = configurations.begin();
528         std::string conf = (*it); // configuration name
529         std::transform(conf.begin(), conf.end(), conf.begin(), ::tolower); // to lower case
530
531         // Check the request queue if a previous request is still left. If so, remove it.
532         std::map< std::string, ConfigurationRequestEntry >::iterator iter =
533                 configurationRequestTable.find(conf);
534         if (iter != configurationRequestTable.end())
535             configurationRequestTable.erase(iter);
536
537         // Create new request entry stored in the queue
538         ConfigurationRequestEntry newCallback(conf, callback, resource, conf);
539         configurationRequestTable.insert(std::make_pair(conf, newCallback));
540
541         QueryParamsMap query;
542         OCRepresentation rep;
543
544         if (isSimpleResource(resource))
545         {
546             // This resource is a simple resource. Just send a PUT message
547             std::string m_if = DEFAULT_INTERFACE;
548
549             if (hasBatchInterface(resource))
550                 m_if = BATCH_INTERFACE;
551
552             return resource->get(resource->getResourceTypes().at(0), m_if, query,
553                     std::function<
554                             void(const HeaderOptions& headerOptions, const OCRepresentation& rep,
555                                     const int eCode) >(
556                             std::bind(&ThingsConfiguration::onGet, this, std::placeholders::_1,
557                                     std::placeholders::_2, std::placeholders::_3, conf)));
558         }
559         else
560         {
561             // This resource is a collection resource. On the contrary of a update, it does not use
562             // group manager functionality. It just acquires child resource's URI and send GET
563             // massages to the child resources in turn.
564             // First, request the child resources's URI.
565             return resource->get(resource->getResourceTypes().at(0), DEFAULT_INTERFACE, query,
566                     std::function<
567                             void(const HeaderOptions& headerOptions, const OCRepresentation& rep,
568                                     const int eCode) >(
569                             std::bind(&ThingsConfiguration::onGetChildInfoForGet, this,
570                                     std::placeholders::_1, std::placeholders::_2,
571                                     std::placeholders::_3, conf)));
572         }
573
574     }
575
576 // callback handler on GET request
577     void ThingsConfiguration::onGetBootstrapInformation(const HeaderOptions& headerOptions,
578             const OCRepresentation& rep, const int eCode)
579     {
580         if (eCode != OC_STACK_OK)
581         {
582             std::cout << "onGET Response error: " << eCode << std::endl;
583             g_bootstrapCallback(headerOptions, rep, eCode);
584             return;
585         }
586
587         g_bootstrapCallback(headerOptions, rep, eCode);
588     }
589
590     void ThingsConfiguration::onFoundBootstrapServer(
591             std::vector< std::shared_ptr< OCResource > > resources)
592     {
593         std::string resourceURI;
594         std::string hostAddress;
595
596         try
597         {
598             // Do some operations with resource object.
599             for (unsigned int i = 0; i < resources.size(); ++i)
600             {
601                 std::shared_ptr < OCResource > resource = resources.at(i);
602
603                 if (resource)
604                 { // Request configuration resources
605
606                     std::cout << "Getting bootstrap server representation on: " << DEFAULT_INTERFACE
607                             << std::endl;
608
609                     resource->get("bootstrap", DEFAULT_INTERFACE, QueryParamsMap(),
610                             &onGetBootstrapInformation);
611
612                 }
613                 else
614                 {
615                     // Resource is invalid
616                     std::cout << "Resource is invalid" << std::endl;
617                 }
618             }
619
620         }
621         catch (std::exception& e)
622         {
623             //log(e.what());
624         }
625     }
626
627     OCStackResult ThingsConfiguration::doBootstrap(ConfigurationCallback callback)
628     {
629         if(callback == NULL)
630             return OC_STACK_ERROR;
631         else
632           g_bootstrapCallback = callback;
633
634         // Find bootstrap server.
635         std::vector < std::string > type;
636         type.push_back("bootstrap");
637
638         std::cout << "Finding Bootstrap Server resource... " << std::endl;
639         return g_groupmanager->findCandidateResources(type, &onFoundBootstrapServer);
640     }
641 }
642