Apply the 'CA_INT' of Connectivity Abstraction for Things Manager.
[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
45 template< typename T >
46 bool IsSubset(std::vector< T > full, std::vector< T > sub)
47 {
48     std::sort(full.begin(), full.end());
49     std::sort(sub.begin(), sub.end());
50     return std::includes(full.begin(), full.end(), sub.begin(), sub.end());
51 }
52 std::vector< std::string > &str_split(const std::string &s, char delim,
53         std::vector< std::string > &elems)
54 {
55     std::stringstream ss(s);
56     std::string item;
57     while (std::getline(ss, item, delim))
58     {
59         elems.push_back(item);
60     }
61     return elems;
62 }
63
64 std::vector< std::string > str_split(const std::string &s, char delim)
65 {
66     std::vector< std::string > elems;
67     str_split(s, delim, elems);
68     return elems;
69 }
70
71 void GroupManager::onFoundResource(std::shared_ptr< OCResource > resource, int waitsec)
72 {
73
74     std::string resourceURI;
75     std::string hostAddress;
76     try
77     {
78         // Do some operations with resource object.
79         if (resource)
80         {
81
82             std::cout << "DISCOVERED Resource:" << std::endl;
83             // Get the resource URI
84             resourceURI = resource->uri();
85             std::cout << "\tURI of the resource: " << resourceURI << std::endl;
86
87             // Get the resource host address
88             hostAddress = resource->host();
89             std::cout << "\tHost address of the resource: " << hostAddress << std::endl;
90
91             // Get the resource types
92             std::cout << "\tList of resource types: " << std::endl;
93
94             hostAddress.append(resourceURI);
95
96             for (auto &resourceTypes : resource->getResourceTypes())
97             {
98                 std::cout << "\t\t" << resourceTypes << std::endl;
99
100                 if (std::find(allFoundResourceTypes.begin(), allFoundResourceTypes.end(),
101                         resourceTypes) == allFoundResourceTypes.end())
102                 {
103                     allFoundResourceTypes.push_back(resourceTypes);
104                 }
105
106                 rtForResourceList[resourceTypes][hostAddress] = resource;
107             }
108
109             // Get the resource interfaces
110             std::cout << "\tList of resource interfaces: " << std::endl;
111             for (auto &resourceInterfaces : resource->getResourceInterfaces())
112             {
113                 std::cout << "\t\t" << resourceInterfaces << std::endl;
114             }
115
116             if (waitsec == -1)
117             {
118                 findPreparedRequest(candidateRequest);
119             }
120         }
121         else
122         {
123             // Resource is invalid
124             std::cout << "Resource is invalid" << std::endl;
125         }
126
127     }
128     catch (std::exception& e)
129     {
130         //log(e.what());
131     }
132 }
133
134 GroupManager::GroupManager(void)
135 {
136     ;
137 }
138
139 /**
140  * Virtual destructor
141  */
142 GroupManager::~GroupManager(void)
143 {
144     candidateRequest.clear();
145     candidateRequestForTimer.clear();
146     rtForResourceList.clear();
147     allFoundResourceTypes.clear();
148 }
149
150 void GroupManager::findPreparedRequest(
151         std::map< std::vector< std::string >, CandidateCallback > &request)
152 {
153     std::vector< std::shared_ptr< OCResource > > resources;
154
155     for (auto it = request.begin(); it != request.end();)
156     {
157
158         if (IsSubset(allFoundResourceTypes, it->first))
159         {
160             //std::cout << "IS SUBSET !!! \n";
161
162             for (unsigned int i = 0; i < it->first.size(); ++i)
163             {
164
165                 for (auto secondIt = rtForResourceList[it->first.at(i)].begin();
166                         secondIt != rtForResourceList[it->first.at(i)].end(); ++secondIt)
167                 {
168                     resources.push_back(secondIt->second);
169                 }
170             }
171
172             it->second(resources);
173
174             //TODO : decide policy - callback only once
175             request.erase(it++);
176         }
177         else
178         {
179             ++it;
180         }
181
182     }
183
184 }
185
186 void GroupManager::lazyCallback(int second)
187 {
188     sleep(second);
189     findPreparedRequest(candidateRequestForTimer);
190
191 }
192
193 OCStackResult GroupManager::findCandidateResources(std::vector< std::string > resourceTypes,
194         CandidateCallback callback, int waitsec)
195 {
196     if (resourceTypes.size() < 1)
197     {
198         return OC_STACK_ERROR;
199     }
200     if(callback == NULL)
201     {
202         return OC_STACK_ERROR;
203     }
204
205     std::sort(resourceTypes.begin(), resourceTypes.end());
206     resourceTypes.erase(std::unique(resourceTypes.begin(), resourceTypes.end()),
207             resourceTypes.end());
208
209     if (waitsec >= 0)
210     {
211         candidateRequestForTimer.insert(std::make_pair(resourceTypes, callback));
212     }
213     else
214     {
215         candidateRequest.insert(std::make_pair(resourceTypes, callback));
216     }
217
218     for (unsigned int i = 0; i < resourceTypes.size(); ++i)
219     {
220         std::string query = "coap://224.0.1.187:5298/oc/core?rt=";
221         // std::cout << "resourceTypes : " << resourceTypes.at(i) << std::endl;
222         query.append(resourceTypes.at(i));
223
224 #ifdef CA_INT
225         OCPlatform::findResource("", query.c_str(),
226                 OC_ETHERNET | OC_WIFI,
227                 std::function < void(std::shared_ptr < OCResource > resource)
228                         > (std::bind(&GroupManager::onFoundResource, this, std::placeholders::_1,
229                                 waitsec)));
230 #else
231         OCPlatform::findResource("", query.c_str(),
232                 std::function < void(std::shared_ptr < OCResource > resource)
233                         > (std::bind(&GroupManager::onFoundResource, this, std::placeholders::_1,
234                                 waitsec)));
235 #endif
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     /* //bug not found
316      if(rep.hasAttribute("name"))
317      {
318      std::cout << "\tRoom name: " << rep.getValue<std::string>("name") << std::endl;
319      }
320      */
321     std::vector< OCRepresentation > children = rep.getChildren();
322     
323     if(children.size() == 0 )
324     {
325         callback("", OC_STACK_ERROR);
326         return;
327     }
328
329     for (auto oit = children.begin(); oit != children.end(); ++oit)
330     {
331         std::cout << "\t\tChild Resource URI: " << oit->getUri() << std::endl;
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\thost : " << hostAddress << std::endl;
356         OCPlatform::OCPresenceHandle presenceHandle;
357
358 #ifdef CA_INT
359         OCStackResult result = OCPlatform::subscribePresence(presenceHandle, hostAddress,
360                 resourceType,
361                 OC_ETHERNET | OC_WIFI,
362                 std::function<
363                         void(OCStackResult result, const unsigned int nonce,
364                                 const std::string& hostAddress) >(
365                         std::bind(&GroupManager::collectionPresenceHandler, this,
366                                 std::placeholders::_1, std::placeholders::_2,
367                                 std::placeholders::_3, hostAddress, oit->getUri())));
368 #else
369         OCStackResult result = OCPlatform::subscribePresence(presenceHandle, hostAddress,
370                 resourceType,
371                 std::function<
372                         void(OCStackResult result, const unsigned int nonce,
373                                 const std::string& hostAddress) >(
374                         std::bind(&GroupManager::collectionPresenceHandler, this,
375                                 std::placeholders::_1, std::placeholders::_2,
376                                 std::placeholders::_3, hostAddress, oit->getUri())));
377 #endif
378
379         if (result == OC_STACK_OK)
380         {
381             std::cout << "\t\tOK!" << std::endl;
382             presenceCallbacks.insert(std::make_pair(oit->getUri(), callback));
383         }
384         else
385         {
386             callback("", OC_STACK_ERROR);
387         }
388
389     }
390 }
391
392 void GroupManager::onGetForPresence(const HeaderOptions& headerOptions,
393         const OCRepresentation& rep, const int eCode, CollectionPresenceCallback callback)
394 {
395     if (eCode == OC_STACK_OK)
396     {
397         std::cout << "GET request was successful" << std::endl;
398         std::cout << "Resource URI: " << rep.getUri() << std::endl;
399
400         checkCollectionRepresentation(rep, callback);
401
402     }
403     else
404     {
405         std::cout << "onGET Response error: " << eCode << std::endl;
406         callback("", OC_STACK_ERROR);
407         std::exit(-1);
408     }
409 }
410
411 OCStackResult GroupManager::subscribeCollectionPresence(
412         std::shared_ptr< OCResource > collectionResource, CollectionPresenceCallback callback)
413 {
414     if(callback == NULL || collectionResource == NULL)
415     {
416         return OC_STACK_ERROR;
417     }
418     
419     OCStackResult result = OC_STACK_OK;
420     //callback("core.room",OC_STACK_OK);
421
422     QueryParamsMap queryParam;
423
424     //parameter 1 = resourceType
425     collectionResource->get("", DEFAULT_INTERFACE, queryParam,
426             std::function<
427                     void(const HeaderOptions& headerOptions, const OCRepresentation& rep,
428                             const int eCode) >(
429                     std::bind(&GroupManager::onGetForPresence, this, std::placeholders::_1,
430                             std::placeholders::_2, std::placeholders::_3, callback)));
431
432     return result;
433 }
434
435 /*
436  Group Action
437  */
438
439 std::string GroupManager::getStringFromActionSet(const ActionSet *newActionSet)
440 {
441     std::string message = "";
442
443     if(newActionSet == NULL)
444         return message;
445
446     message = newActionSet->actionsetName;
447     message.append("*");
448     for (auto iterAction = newActionSet->listOfAction.begin();
449             iterAction != newActionSet->listOfAction.end(); iterAction++)
450     {
451         message.append("uri=");
452         message.append((*iterAction)->target);
453         message.append("|");
454
455         for (auto iterCapa = (*iterAction)->listOfCapability.begin();
456                 iterCapa != (*iterAction)->listOfCapability.end(); iterCapa++)
457         {
458             message.append((*iterCapa)->capability);
459             message.append("=");
460             message.append((*iterCapa)->status);
461
462             if (iterCapa + 1 != (*iterAction)->listOfCapability.end())
463                 message.append("|");
464         }
465
466         if (iterAction + 1 != newActionSet->listOfAction.end())
467         {
468             message.append("*");
469         }
470     }
471
472     return message;
473 }
474
475 ActionSet* GroupManager::getActionSetfromString(std::string desc)
476 {
477
478     char *token = NULL;
479     char *plainText = NULL;
480     char *plainPtr = NULL;
481
482     ActionSet *actionset = new ActionSet();
483     plainText = new char[(desc.length() + 1)];
484     strcpy(plainText, desc.c_str());
485
486     token = strtok_r(plainText, ACTION_DELIMITER, &plainPtr);
487
488     if (token != NULL)
489     {
490         actionset->actionsetName = std::string(token);
491         token = strtok_r(NULL, ACTION_DELIMITER, &plainPtr);
492     }
493     else
494     {
495         delete actionset;
496         delete[] plainText;
497         return NULL;
498     }
499
500     while (token)
501     {
502         char *descPtr = NULL;
503         char *desc = new char[(strlen(token) + 1)];
504
505         if (desc != NULL)
506         {
507             Action *action = NULL;
508             strcpy(desc, token);
509             token = strtok_r(desc, DESC_DELIMITER, &descPtr);
510
511             // cout << "desc :: " << token << endl;
512             while (token != NULL)
513             {
514                 char *attrPtr = NULL;
515                 char *attr = new char[(strlen(token) + 1)];
516
517                 strcpy(attr, token);
518
519                 // cout << "attr :: " << attr << endl;
520
521                 token = strtok_r(attr, ATTR_DELIMITER, &attrPtr);
522                 while (token != NULL)
523                 {
524                     if (strcmp(token, "uri") == 0)
525                     {
526                         token = strtok_r(NULL, ATTR_DELIMITER, &attrPtr);
527                         action = new Action();
528
529                         if (action != NULL)
530                         {
531                             action->target = std::string(token);
532                         }
533                         else
534                         {
535                             delete actionset;
536                             delete[] attr;
537                             delete desc;
538                             delete[] plainText;
539                             return NULL;
540                         }
541                     }
542                     else
543                     {
544                         Capability *capa = new Capability();
545                         capa->capability = std::string(token);
546                         token = strtok_r(NULL, ATTR_DELIMITER, &attrPtr);
547                         capa->status = std::string(token);
548
549                         if (action != NULL)
550                         {
551                             action->listOfCapability.push_back(capa);
552                         }
553                         else
554                         {
555                             delete capa;
556                             delete actionset;
557                             delete[] attr;
558                             delete[] plainText;
559                             delete desc;
560                             return NULL;
561                         }
562                     }
563
564                     token = strtok_r(NULL, ATTR_DELIMITER, &attrPtr);
565                 }
566
567                 delete[] attr;
568                 token = strtok_r(NULL, DESC_DELIMITER, &descPtr);
569             }
570
571             actionset->listOfAction.push_back(action);
572             //delete action;
573         }
574         else
575         {
576             delete actionset;
577             delete[] plainText;
578             return NULL;
579         }
580
581         delete[] desc;
582
583         token = strtok_r(NULL, ACTION_DELIMITER, &plainPtr);
584     }
585
586     delete plainText;
587     return actionset;
588 }
589
590 OCStackResult GroupManager::addActionSet(std::shared_ptr< OCResource > resource,
591         const ActionSet* newActionSet, PutCallback cb)
592 {
593     // BUILD message of ActionSet which it is included delimiter.
594     if ((resource != NULL) && (newActionSet != NULL))
595     {
596         std::string message = getStringFromActionSet(newActionSet);
597         OCRepresentation rep;
598
599         rep.setValue("ActionSet", message);
600
601         return resource->put(resource->getResourceTypes().front(), GROUP_INTERFACE, rep,
602                 QueryParamsMap(), cb);
603     }
604     else
605     {
606         return OC_STACK_ERROR;
607     }
608 }
609
610 OCStackResult GroupManager::executeActionSet(std::shared_ptr< OCResource > resource,
611         std::string actionsetName, PostCallback cb)
612 {
613     if (resource != NULL)
614     {
615         OCRepresentation rep;
616
617         rep.setValue("DoAction", actionsetName);
618         return resource->post(resource->getResourceTypes().front(), GROUP_INTERFACE, rep,
619                 QueryParamsMap(), cb);
620     }
621     else
622     {
623         return OC_STACK_ERROR;
624     }
625 }
626
627 OCStackResult GroupManager::getActionSet(std::shared_ptr< OCResource > resource,
628         std::string actionsetName, PostCallback cb)
629 {
630     if (resource != NULL)
631     {
632         OCRepresentation rep;
633
634         rep.setValue("GetActionSet", actionsetName);
635
636         return resource->post(resource->getResourceTypes().front(), GROUP_INTERFACE, rep,
637                 QueryParamsMap(), cb);
638     }
639     else
640     {
641         return OC_STACK_ERROR;
642     }
643 }
644
645 OCStackResult GroupManager::deleteActionSet(std::shared_ptr< OCResource > resource,
646         std::string actionsetName, PutCallback cb)
647 {
648     if (resource != NULL)
649     {
650         OCRepresentation rep;
651
652         rep.setValue("DelActionSet", actionsetName);
653
654         return resource->put(resource->getResourceTypes().front(), GROUP_INTERFACE, rep,
655                 QueryParamsMap(), cb);
656     }
657     else
658     {
659         return OC_STACK_ERROR;
660     }
661 }
662 }