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