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