Fix problem for multiple api call
[platform/upstream/iotivity.git] / service / things-manager / sdk / src / GroupManager.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    GroupManager.cpp
22 ///  @brief
23
24 #include "GroupManager.h"
25 #include <algorithm>
26 #include <thread>
27 #include <unistd.h>
28
29 #include <string.h>
30
31 #define PLAIN_DELIMITER "\""
32 #define ACTION_DELIMITER "*"
33 #define DESC_DELIMITER "|"
34 #define ATTR_DELIMITER "="
35
36 using namespace OC;
37
38 namespace OIC
39 {
40 std::map< std::vector< std::string >, CandidateCallback > candidateRequest;
41 std::map< std::vector< std::string >, CandidateCallback > candidateRequestForTimer;
42 std::map< std::string, std::map< std::string, std::shared_ptr< OCResource > > > rtForResourceList;
43 std::vector< std::string > allFoundResourceTypes;
44 std::mutex callbackLock;
45
46
47 template< typename T >
48 bool IsSubset(std::vector< T > full, std::vector< T > sub)
49 {
50     std::sort(full.begin(), full.end());
51     std::sort(sub.begin(), sub.end());
52     return std::includes(full.begin(), full.end(), sub.begin(), sub.end());
53 }
54 std::vector< std::string > &str_split(const std::string &s, char delim,
55         std::vector< std::string > &elems)
56 {
57     std::stringstream ss(s);
58     std::string item;
59     while (std::getline(ss, item, delim))
60     {
61         elems.push_back(item);
62     }
63     return elems;
64 }
65
66 std::vector< std::string > str_split(const std::string &s, char delim)
67 {
68     std::vector< std::string > elems;
69     str_split(s, delim, elems);
70     return elems;
71 }
72
73 void GroupManager::onFoundResource(std::shared_ptr< OCResource > resource, int waitsec)
74 {
75
76     std::string resourceURI;
77     std::string hostAddress;
78     try
79     {
80         // Do some operations with resource object.
81         if (resource)
82         {
83
84             std::cout << "DISCOVERED Resource:" << std::endl;
85             // Get the resource URI
86             resourceURI = resource->uri();
87             std::cout << "\tURI of the resource: " << resourceURI << std::endl;
88
89             // Get the resource host address
90             hostAddress = resource->host();
91             std::cout << "\tHost address of the resource: " << hostAddress << std::endl;
92
93             // Get the resource types
94             std::cout << "\tList of resource types: " << std::endl;
95
96             hostAddress.append(resourceURI);
97
98             for (auto &resourceTypes : resource->getResourceTypes())
99             {
100                 std::cout << "\t\t" << resourceTypes << std::endl;
101
102                 if (std::find(allFoundResourceTypes.begin(), allFoundResourceTypes.end(),
103                         resourceTypes) == allFoundResourceTypes.end())
104                 {
105                     allFoundResourceTypes.push_back(resourceTypes);
106                 }
107
108                 rtForResourceList[resourceTypes][hostAddress] = resource;
109             }
110
111             // Get the resource interfaces
112             std::cout << "\tList of resource interfaces: " << std::endl;
113             for (auto &resourceInterfaces : resource->getResourceInterfaces())
114             {
115                 std::cout << "\t\t" << resourceInterfaces << std::endl;
116             }
117
118             if (waitsec == -1)
119             {
120                 findPreparedRequest(candidateRequest);
121             }
122         }
123         else
124         {
125             // Resource is invalid
126             std::cout << "Resource is invalid" << std::endl;
127         }
128
129     }
130     catch (std::exception& e)
131     {
132         //log(e.what());
133     }
134 }
135
136 GroupManager::GroupManager(void)
137 {
138     ;
139 }
140
141 /**
142  * Virtual destructor
143  */
144 GroupManager::~GroupManager(void)
145 {
146     candidateRequest.clear();
147     candidateRequestForTimer.clear();
148     rtForResourceList.clear();
149     allFoundResourceTypes.clear();
150 }
151
152 void GroupManager::findPreparedRequest(
153         std::map< std::vector< std::string >, CandidateCallback > &request)
154 {
155     std::lock_guard<std::mutex> lock(callbackLock);
156     std::vector< std::shared_ptr< OCResource > > resources;
157
158     for (auto it = request.begin(); it != request.end();)
159     {
160
161         if (IsSubset(allFoundResourceTypes, it->first))
162         {
163             for (unsigned int i = 0; i < it->first.size(); ++i)
164             {
165
166                 for (auto secondIt = rtForResourceList[it->first.at(i)].begin();
167                         secondIt != rtForResourceList[it->first.at(i)].end(); ++secondIt)
168                 {
169                     //insert resource related to request
170                     resources.push_back(secondIt->second);
171                 }
172             }
173
174             it->second(resources);
175
176             //TODO : decide policy - callback only once
177             request.erase(it++);
178         }
179         else
180         {
181             ++it;
182         }
183
184     }
185
186 }
187
188 void GroupManager::lazyCallback(int second)
189 {
190     sleep(second);
191     findPreparedRequest(candidateRequestForTimer);
192
193 }
194
195 OCStackResult GroupManager::findCandidateResources(std::vector< std::string > resourceTypes,
196         CandidateCallback callback, int waitsec)
197 {
198     if (resourceTypes.size() < 1)
199     {
200         return OC_STACK_ERROR;
201     }
202     if(callback == NULL)
203     {
204         return OC_STACK_ERROR;
205     }
206
207     std::sort(resourceTypes.begin(), resourceTypes.end());
208     resourceTypes.erase(std::unique(resourceTypes.begin(), resourceTypes.end()),
209             resourceTypes.end());
210
211     if (waitsec >= 0)
212     {
213         candidateRequestForTimer.insert(std::make_pair(resourceTypes, callback));
214     }
215     else
216     {
217         candidateRequest.insert(std::make_pair(resourceTypes, callback));
218     }
219
220     for (unsigned int i = 0; i < resourceTypes.size(); ++i)
221     {
222         std::cout << "resourceTypes : " << resourceTypes.at(i) << std::endl;
223         std::string query = OC_WELL_KNOWN_QUERY;
224         query += "?rt=";
225         query += resourceTypes.at(i);
226
227         OCPlatform::findResource("", query, OC_WIFI,
228                 std::function < void(std::shared_ptr < OCResource > resource)
229                 > (std::bind(&GroupManager::onFoundResource, this,
230                         std::placeholders::_1, waitsec)));
231     }
232
233     if (waitsec >= 0)
234     {
235         std::thread exec(
236                 std::function< void(int second) >(
237                         std::bind(&GroupManager::lazyCallback, this, std::placeholders::_1)),
238                 waitsec);
239         exec.detach();
240     }
241
242     return OC_STACK_OK;
243 }
244
245
246 OCStackResult GroupManager::bindResourceToGroup(OCResourceHandle& childHandle, std::shared_ptr< OCResource > resource, OCResourceHandle& collectionHandle)
247 {
248
249     OCStackResult result = OCPlatform::registerResource(childHandle, resource);
250
251     cout << "\tresource registed!" << endl;
252
253     if(result == OC_STACK_OK)
254     {
255         OCPlatform::bindResource(collectionHandle, childHandle);
256     }
257     else
258     {
259         cout << "\tresource Error!" << endl;
260     }
261
262     return result;
263  }
264
265
266
267 /*
268  Presence Check
269  */
270
271 std::map< std::string, CollectionPresenceCallback > presenceCallbacks;
272
273 // Callback to presence
274 void GroupManager::collectionPresenceHandler(OCStackResult result, const unsigned int nonce,
275         const std::string& hostAddress, std::string host, std::string uri)
276 {
277     std::cout << "uri : " << uri << std::endl;
278     std::cout << "host : " << host << std::endl;
279     std::cout << "result : " << result << std::endl;
280     switch (result)
281     {
282         case OC_STACK_OK:
283             std::cout << "Nonce# " << nonce << std::endl;
284             break;
285         case OC_STACK_PRESENCE_STOPPED:
286             std::cout << "Presence Stopped\n";
287             break;
288         case OC_STACK_PRESENCE_DO_NOT_HANDLE:
289             std::cout << "Presence do not handle\n";
290             break;
291         case OC_STACK_PRESENCE_TIMEOUT:
292             std::cout << "Presence TIMEOUT\n";
293             break;
294         default:
295             std::cout << "Error\n";
296             break;
297     }
298
299     if (presenceCallbacks.find(uri) != presenceCallbacks.end())
300     {
301         (presenceCallbacks.find(uri)->second)(uri, result);
302     }
303 }
304
305 void GroupManager::checkCollectionRepresentation(const OCRepresentation& rep,
306         CollectionPresenceCallback callback)
307 {
308     std::cout << "\tResource URI: " << rep.getUri() << std::endl;
309
310     /* //bug not found
311      if(rep.hasAttribute("name"))
312      {
313      std::cout << "\tRoom name: " << rep.getValue<std::string>("name") << std::endl;
314      }
315      */
316     std::vector< OCRepresentation > children = rep.getChildren();
317
318     if(children.size() == 0 )
319     {
320         callback("", OC_STACK_ERROR);
321         return;
322     }
323
324     for (auto oit = children.begin(); oit != children.end(); ++oit)
325     {
326         std::cout << "\t\tChild Resource URI: " << oit->getUri() << std::endl;
327         std::vector< std::string > hostAddressVector = str_split(oit->getUri(), '/');
328         std::string hostAddress = "";
329         for (unsigned int i = 0; i < hostAddressVector.size(); ++i)
330         {
331             if (i < 3)
332             {
333                 hostAddress.append(hostAddressVector.at(i));
334                 if (i != 2)
335                 {
336                     hostAddress.append("/");
337                 }
338             }
339         }
340
341         std::vector< std::string > resourceTypes = oit->getResourceTypes();
342         for (unsigned int i = 0; i < resourceTypes.size(); ++i)
343         {
344             std::cout << "\t\t\tresourcetype :" << resourceTypes.at(i) << std::endl;
345         }
346
347         std::string resourceType = "core.";
348         resourceType.append(str_split(oit->getUri(), '/').at(4));
349         std::cout << "\t\tconvertRT : " << resourceType << std::endl;
350         std::cout << "\t\thost : " << hostAddress << std::endl;
351         OCPlatform::OCPresenceHandle presenceHandle;
352
353         OCStackResult result = OCPlatform::subscribePresence(presenceHandle, hostAddress,
354                 resourceType, OC_WIFI,
355                 std::function<
356                         void(OCStackResult result, const unsigned int nonce,
357                                 const std::string& hostAddress) >(
358                         std::bind(&GroupManager::collectionPresenceHandler, this,
359                                 std::placeholders::_1, std::placeholders::_2,
360                                 std::placeholders::_3, hostAddress, oit->getUri())));
361
362         if (result == OC_STACK_OK)
363         {
364             std::cout << "\t\tOK!" << std::endl;
365             presenceCallbacks.insert(std::make_pair(oit->getUri(), callback));
366         }
367         else
368         {
369             callback("", OC_STACK_ERROR);
370         }
371
372     }
373 }
374
375 void GroupManager::onGetForPresence(const HeaderOptions& headerOptions,
376         const OCRepresentation& rep, const int eCode, CollectionPresenceCallback callback)
377 {
378     if (eCode == OC_STACK_OK)
379     {
380         std::cout << "GET request was successful" << std::endl;
381         std::cout << "Resource URI: " << rep.getUri() << std::endl;
382
383         checkCollectionRepresentation(rep, callback);
384
385     }
386     else
387     {
388         std::cout << "onGET Response error: " << eCode << std::endl;
389         callback("", OC_STACK_ERROR);
390         std::exit(-1);
391     }
392 }
393
394 OCStackResult GroupManager::subscribeCollectionPresence(
395         std::shared_ptr< OCResource > collectionResource, CollectionPresenceCallback callback)
396 {
397     if(callback == NULL || collectionResource == NULL)
398     {
399         return OC_STACK_ERROR;
400     }
401
402     OCStackResult result = OC_STACK_OK;
403     //callback("core.room",OC_STACK_OK);
404
405     QueryParamsMap queryParam;
406
407     //parameter 1 = resourceType
408     collectionResource->get("", DEFAULT_INTERFACE, queryParam,
409             std::function<
410                     void(const HeaderOptions& headerOptions, const OCRepresentation& rep,
411                             const int eCode) >(
412                     std::bind(&GroupManager::onGetForPresence, this, std::placeholders::_1,
413                             std::placeholders::_2, std::placeholders::_3, callback)));
414
415     return result;
416 }
417
418 /*
419  Group Action
420  */
421
422 std::string GroupManager::getStringFromActionSet(const ActionSet *newActionSet)
423 {
424     std::string message = "";
425
426     if(newActionSet == NULL)
427         return message;
428
429     message = newActionSet->actionsetName;
430     message.append("*");
431     for (auto iterAction = newActionSet->listOfAction.begin();
432             iterAction != newActionSet->listOfAction.end(); iterAction++)
433     {
434         message.append("uri=");
435         message.append((*iterAction)->target);
436         message.append("|");
437
438         for (auto iterCapa = (*iterAction)->listOfCapability.begin();
439                 iterCapa != (*iterAction)->listOfCapability.end(); iterCapa++)
440         {
441             message.append((*iterCapa)->capability);
442             message.append("=");
443             message.append((*iterCapa)->status);
444
445             if (iterCapa + 1 != (*iterAction)->listOfCapability.end())
446                 message.append("|");
447         }
448
449         if (iterAction + 1 != newActionSet->listOfAction.end())
450         {
451             message.append("*");
452         }
453     }
454
455     return message;
456 }
457
458 ActionSet* GroupManager::getActionSetfromString(std::string desc)
459 {
460
461     char *token = NULL;
462     char *plainText = NULL;
463     char *plainPtr = NULL;
464
465     ActionSet *actionset = new ActionSet();
466     plainText = new char[(desc.length() + 1)];
467     strcpy(plainText, desc.c_str());
468
469     token = strtok_r(plainText, ACTION_DELIMITER, &plainPtr);
470
471     if (token != NULL)
472     {
473         actionset->actionsetName = std::string(token);
474         token = strtok_r(NULL, ACTION_DELIMITER, &plainPtr);
475     }
476     else
477     {
478         delete actionset;
479         delete[] plainText;
480         return NULL;
481     }
482
483     while (token)
484     {
485         char *descPtr = NULL;
486         char *desc = new char[(strlen(token) + 1)];
487
488         if (desc != NULL)
489         {
490             Action *action = NULL;
491             strcpy(desc, token);
492             token = strtok_r(desc, DESC_DELIMITER, &descPtr);
493
494             // cout << "desc :: " << token << endl;
495             while (token != NULL)
496             {
497                 char *attrPtr = NULL;
498                 char *attr = new char[(strlen(token) + 1)];
499
500                 strcpy(attr, token);
501
502                 // cout << "attr :: " << attr << endl;
503
504                 token = strtok_r(attr, ATTR_DELIMITER, &attrPtr);
505                 while (token != NULL)
506                 {
507                     if (strcmp(token, "uri") == 0)
508                     {
509                         token = strtok_r(NULL, ATTR_DELIMITER, &attrPtr);
510                         action = new Action();
511
512                         if (action != NULL)
513                         {
514                             action->target = std::string(token);
515                         }
516                         else
517                         {
518                             delete actionset;
519                             delete[] attr;
520                             delete desc;
521                             delete[] plainText;
522                             return NULL;
523                         }
524                     }
525                     else
526                     {
527                         Capability *capa = new Capability();
528                         capa->capability = std::string(token);
529                         token = strtok_r(NULL, ATTR_DELIMITER, &attrPtr);
530                         capa->status = std::string(token);
531
532                         if (action != NULL)
533                         {
534                             action->listOfCapability.push_back(capa);
535                         }
536                         else
537                         {
538                             delete capa;
539                             delete actionset;
540                             delete[] attr;
541                             delete[] plainText;
542                             delete desc;
543                             return NULL;
544                         }
545                     }
546
547                     token = strtok_r(NULL, ATTR_DELIMITER, &attrPtr);
548                 }
549
550                 delete[] attr;
551                 token = strtok_r(NULL, DESC_DELIMITER, &descPtr);
552             }
553
554             actionset->listOfAction.push_back(action);
555             //delete action;
556         }
557         else
558         {
559             delete actionset;
560             delete[] plainText;
561             return NULL;
562         }
563
564         delete[] desc;
565
566         token = strtok_r(NULL, ACTION_DELIMITER, &plainPtr);
567     }
568
569     delete plainText;
570     return actionset;
571 }
572
573 OCStackResult GroupManager::addActionSet(std::shared_ptr< OCResource > resource,
574         const ActionSet* newActionSet, PutCallback cb)
575 {
576     // BUILD message of ActionSet which it is included delimiter.
577     if ((resource != NULL) && (newActionSet != NULL))
578     {
579         std::string message = getStringFromActionSet(newActionSet);
580         OCRepresentation rep;
581
582         rep.setValue("ActionSet", message);
583
584         return resource->put(resource->getResourceTypes().front(), GROUP_INTERFACE, rep,
585                 QueryParamsMap(), cb);
586     }
587     else
588     {
589         return OC_STACK_ERROR;
590     }
591 }
592
593 OCStackResult GroupManager::executeActionSet(std::shared_ptr< OCResource > resource,
594         std::string actionsetName, PostCallback cb)
595 {
596     if (resource != NULL)
597     {
598         OCRepresentation rep;
599
600         rep.setValue("DoAction", actionsetName);
601         return resource->post(resource->getResourceTypes().front(), GROUP_INTERFACE, rep,
602                 QueryParamsMap(), cb);
603     }
604     else
605     {
606         return OC_STACK_ERROR;
607     }
608 }
609
610 OCStackResult GroupManager::getActionSet(std::shared_ptr< OCResource > resource,
611         std::string actionsetName, PostCallback cb)
612 {
613     if (resource != NULL)
614     {
615         OCRepresentation rep;
616
617         rep.setValue("GetActionSet", actionsetName);
618
619         return resource->post(resource->getResourceTypes().front(), GROUP_INTERFACE, rep,
620                 QueryParamsMap(), cb);
621     }
622     else
623     {
624         return OC_STACK_ERROR;
625     }
626 }
627
628 OCStackResult GroupManager::deleteActionSet(std::shared_ptr< OCResource > resource,
629         std::string actionsetName, PutCallback cb)
630 {
631     if (resource != NULL)
632     {
633         OCRepresentation rep;
634
635         rep.setValue("DelActionSet", actionsetName);
636
637         return resource->put(resource->getResourceTypes().front(), GROUP_INTERFACE, rep,
638                 QueryParamsMap(), cb);
639     }
640     else
641     {
642         return OC_STACK_ERROR;
643     }
644 }
645 }