Fix merge issues, Group action feature omit.
[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 "GroupManager.h"
27 #include <algorithm>
28 #include <thread>
29 #include <unistd.h>
30
31 #include <string.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_WELL_KNOWN_QUERY;
227         query.append("?rt=");
228         query.append(resourceTypes.at(i));
229
230         OCPlatform::findResource("", 
231                 query,
232                 OC_ETHERNET,
233                 std::function < void(std::shared_ptr < OCResource > resource)
234                         > (std::bind(&GroupManager::onFoundResource, this, std::placeholders::_1,
235                                 waitsec)));
236
237         // OCPlatform::findResource("",
238         //         query,
239         //         OC_WIFI,
240         //         std::function < void(std::shared_ptr < OCResource > resource)
241         //                 > (std::bind(&GroupManager::onFoundResource, this, std::placeholders::_1,
242         //                         waitsec)));
243     }
244
245     if (waitsec >= 0)
246     {
247         std::thread exec(
248                 std::function< void(int second) >(
249                         std::bind(&GroupManager::lazyCallback, this, std::placeholders::_1)),
250                 waitsec);
251         exec.detach();
252     }
253
254     return OC_STACK_OK;
255 }
256
257
258 OCStackResult GroupManager::bindResourceToGroup(OCResourceHandle& childHandle, std::shared_ptr< OCResource > resource, OCResourceHandle& collectionHandle)
259 {
260
261     OCStackResult result = OCPlatform::registerResource(childHandle, resource);
262
263     cout << "\tresource registed!" << endl;
264
265     if(result == OC_STACK_OK)
266     {
267         OCPlatform::bindResource(collectionHandle, childHandle);
268     }
269     else
270     {
271         cout << "\tresource Error!" << endl;
272     }
273
274     return result;
275  }
276
277
278
279 /*
280  Presence Check
281  */
282
283 std::map< std::string, CollectionPresenceCallback > presenceCallbacks;
284
285 // Callback to presence
286 void GroupManager::collectionPresenceHandler(OCStackResult result, const unsigned int nonce,
287         const std::string& hostAddress, std::string host, std::string uri)
288 {
289     std::cout << "uri : " << uri << std::endl;
290     std::cout << "host : " << host << std::endl;
291     std::cout << "result : " << result << std::endl;
292     switch (result)
293     {
294         case OC_STACK_OK:
295             std::cout << "Nonce# " << nonce << std::endl;
296             break;
297         case OC_STACK_PRESENCE_STOPPED:
298             std::cout << "Presence Stopped\n";
299             break;
300         case OC_STACK_PRESENCE_DO_NOT_HANDLE:
301             std::cout << "Presence do not handle\n";
302             break;
303         case OC_STACK_PRESENCE_TIMEOUT:
304             std::cout << "Presence TIMEOUT\n";
305             break;
306         default:
307             std::cout << "Error\n";
308             break;
309     }
310
311     if (presenceCallbacks.find(uri) != presenceCallbacks.end())
312     {
313         (presenceCallbacks.find(uri)->second)(uri, result);
314     }
315 }
316
317 void GroupManager::checkCollectionRepresentation(const OCRepresentation& rep,
318         CollectionPresenceCallback callback)
319 {
320     std::cout << "\tResource URI: " << rep.getUri() << std::endl;
321
322     /* //bug not found
323      if(rep.hasAttribute("name"))
324      {
325      std::cout << "\tRoom name: " << rep.getValue<std::string>("name") << std::endl;
326      }
327      */
328     std::vector< OCRepresentation > children = rep.getChildren();
329     if(children.size() == 0 )
330     {
331         callback("", OC_STACK_ERROR);
332         return;
333     }
334
335     for (auto oit = children.begin(); oit != children.end(); ++oit)
336     {
337         // std::cout << "\t\tChild Resource URI: " << oit->getUri() << std::endl;
338         std::vector< std::string > hostAddressVector = str_split(oit->getUri(), '/');
339         std::string hostAddress = "";
340         for (unsigned int i = 0; i < hostAddressVector.size(); ++i)
341         {
342             if (i < 3)
343             {
344                 hostAddress.append(hostAddressVector.at(i));
345                 if (i != 2)
346                 {
347                     hostAddress.append("/");
348                 }
349             }
350         }
351
352         std::vector< std::string > resourceTypes = oit->getResourceTypes();
353         // for (unsigned int i = 0; i < resourceTypes.size(); ++i)
354         // {
355         //     std::cout << "\t\t\tresourcetype :" << resourceTypes.at(i) << std::endl;
356         // }
357
358         // std::string resourceType = "core.";
359         // resourceType.append(str_split(oit->getUri(), '/').at(4));
360         // std::cout << "\t\tconvertRT : " << resourceType << std::endl;
361         // std::cout << "\t\tresource type front : " << resourceTypes.front() << endl;
362         // std::cout << "\t\thost : " << hostAddress << std::endl;
363         OCPlatform::OCPresenceHandle presenceHandle;
364         OCStackResult result = OC_STACK_ERROR;
365
366         result = OCPlatform::subscribePresence(presenceHandle, hostAddress,
367                 // resourceType,
368                 resourceTypes.front(),
369                 OC_ETHERNET,
370                 std::function<
371                         void(OCStackResult result, const unsigned int nonce,
372                                 const std::string& hostAddress) >(
373                         std::bind(&GroupManager::collectionPresenceHandler, this,
374                                 std::placeholders::_1, std::placeholders::_2,
375                                 std::placeholders::_3, hostAddress, oit->getUri())));
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     Capability *capa = NULL;
490     ActionSet *actionset = new ActionSet();
491
492     if(description.empty())
493     {
494         goto exit;
495     }
496     else if(description.at(0) == '*')
497     {
498         goto exit;
499     }
500
501     plainText = new char[(description.length() + 1)];
502     strcpy(plainText, description.c_str());
503
504     token = strtok_r(plainText, ACTION_DELIMITER, &plainPtr);
505
506     if (token != NULL)
507     {
508         actionset->actionsetName = std::string(token);
509
510         if((actionset->actionsetName).empty())
511             goto exit;
512
513         token = strtok_r(NULL, ACTION_DELIMITER, &plainPtr);
514     }
515     else
516     {
517         goto exit;
518     }
519
520     if (token != NULL)
521     {
522         sscanf(token, "%ld %d", &actionset->mDelay, (int*)&actionset->type);
523
524         token = strtok_r(NULL, ACTION_DELIMITER, &plainPtr);
525     }
526     else
527     {
528         goto exit;
529     }
530
531     while (token)
532     {
533         char *descPtr = NULL;
534         desc = new char[(strlen(token) + 1)];
535
536         if (desc != NULL)
537         {
538             Action *action = NULL;
539             strcpy(desc, token);
540             token = strtok_r(desc, DESC_DELIMITER, &descPtr);
541
542             while (token != NULL)
543             {
544                 char *attrPtr = NULL;
545                 attr = new char[(strlen(token) + 1)];
546
547                 strcpy(attr, token);
548
549                 token = strtok_r(attr, ATTR_DELIMITER, &attrPtr);
550                 while (token != NULL)
551                 {
552                     if (strcmp(token, "uri") == 0)
553                     {
554                         token = strtok_r(NULL, ATTR_DELIMITER, &attrPtr);
555                         if(token == NULL)
556                         {
557                             goto exit;
558                         }
559
560                         action = new Action();
561                         if (action != NULL)
562                         {
563                             action->target = std::string(token);
564                         }
565                         else
566                         {
567                             goto exit;
568                         }
569                     }
570                     else
571                     {
572                         capa = new Capability();
573                         capa->capability = std::string(token);
574                         token = strtok_r(NULL, ATTR_DELIMITER, &attrPtr);
575
576                         if( token == NULL )
577                             goto exit;
578
579                         capa->status = std::string(token);
580
581                         if (action != NULL)
582                             action->listOfCapability.push_back(capa);
583                         else
584                             goto exit;
585                     }
586
587                     token = strtok_r(NULL, ATTR_DELIMITER, &attrPtr);
588                 }
589                 DELETEARRAY(attr);
590                 token = strtok_r(NULL, DESC_DELIMITER, &descPtr);
591             }
592
593             if( actionset != NULL )
594                 actionset->listOfAction.push_back(action);
595             else
596                 goto exit;
597             //delete action;
598         }
599         else
600         {
601             goto exit;
602
603         }
604
605         DELETEARRAY(desc);
606
607         token = strtok_r(NULL, ACTION_DELIMITER, &plainPtr);
608     }
609
610     DELETE(plainText);
611     return actionset;
612
613 exit:
614     DELETE(capa)
615     DELETE(actionset)
616     DELETEARRAY(attr);
617     DELETEARRAY(plainText);
618     DELETEARRAY(desc);
619     return NULL;
620 }
621
622 OCStackResult GroupManager::addActionSet(std::shared_ptr< OCResource > resource,
623         const ActionSet* newActionSet, PutCallback cb)
624 {
625     // BUILD message of ActionSet which it is included delimiter.
626     if ((resource != NULL) && (newActionSet != NULL))
627     {
628         if(newActionSet->mDelay < 0)
629         {
630             return OC_STACK_INVALID_PARAM; 
631         }
632
633         std::string message = getStringFromActionSet(newActionSet);
634
635         OCRepresentation rep;
636         rep.setValue("ActionSet", message);
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
646 OCStackResult GroupManager::executeActionSet(std::shared_ptr< OCResource > resource,
647         std::string actionsetName, PostCallback cb)
648 {
649     if (resource != NULL)
650     {
651         OCRepresentation rep;
652
653         rep.setValue("DoAction", actionsetName);
654         return resource->post(resource->getResourceTypes().front(), GROUP_INTERFACE, rep,
655                 QueryParamsMap(), cb);
656     }
657     else
658     {
659         return OC_STACK_ERROR;
660     }
661 }
662
663 OCStackResult GroupManager::executeActionSet(std::shared_ptr< OCResource > resource,
664         std::string actionsetName, long int delay, PostCallback cb)
665 {
666     if(delay <= 0 )
667     {
668         return OC_STACK_INVALID_PARAM;
669     }
670     if (resource != NULL)
671     {
672         std::string value = actionsetName;
673         value.append("*");
674         value.append(std::to_string(delay));
675
676         OCRepresentation rep;
677         rep.setValue("DoScheduledAction", value);
678         return resource->post(resource->getResourceTypes().front(), GROUP_INTERFACE, rep,
679                 QueryParamsMap(), cb);
680     }
681     else
682     {
683         return OC_STACK_ERROR;
684     }
685 }
686
687 OCStackResult GroupManager::cancelActionSet(std::shared_ptr< OCResource > resource,
688         std::string actionsetName, PostCallback cb)
689 {
690     if (resource != NULL)
691     {
692         OCRepresentation rep;
693
694         rep.setValue("CancelAction", actionsetName);
695         return resource->post(resource->getResourceTypes().front(), GROUP_INTERFACE, rep,
696                 QueryParamsMap(), cb);
697     }
698     else
699     {
700         return OC_STACK_ERROR;
701     }
702 }
703
704 OCStackResult GroupManager::getActionSet(std::shared_ptr< OCResource > resource,
705         std::string actionsetName, PostCallback cb)
706 {
707     if (resource != NULL)
708     {
709         OCRepresentation rep;
710
711         rep.setValue("GetActionSet", actionsetName);
712
713         return resource->post(resource->getResourceTypes().front(), GROUP_INTERFACE, rep,
714                 QueryParamsMap(), cb);
715     }
716     else
717     {
718         return OC_STACK_ERROR;
719     }
720 }
721
722 OCStackResult GroupManager::deleteActionSet(std::shared_ptr< OCResource > resource,
723         std::string actionsetName, PutCallback cb)
724 {
725     if (resource != NULL)
726     {
727         OCRepresentation rep;
728
729         rep.setValue("DelActionSet", actionsetName);
730
731         return resource->put(resource->getResourceTypes().front(), GROUP_INTERFACE, rep,
732                 QueryParamsMap(), cb);
733     }
734     else
735     {
736         return OC_STACK_ERROR;
737     }
738 }