Imported Upstream version 1.1.0
[platform/upstream/iotivity.git] / service / simulator / src / server / simulator_collection_resource_impl.cpp
1 /******************************************************************
2  *
3  * Copyright 2015 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 #include "simulator_collection_resource_impl.h"
22 #include "simulator_utils.h"
23 #include "oc_interface_details.h"
24 #include "simulator_logger.h"
25 #include "logger.h"
26
27 #define TAG "SIMULATOR_COLLECTION_RESOURCE"
28
29 SimulatorCollectionResourceImpl::SimulatorCollectionResourceImpl()
30 {
31     m_type = SimulatorResource::Type::COLLECTION_RESOURCE;
32     m_interfaces.push_back(OC::LINK_INTERFACE);
33     m_property = static_cast<OCResourceProperty>(OC_DISCOVERABLE | OC_OBSERVABLE);
34
35     // Add empty vector of OIC Links
36     std::vector<SimulatorResourceModel> links;
37     m_resModel.add("links", links);
38
39     m_resourceHandle = nullptr;
40 }
41
42 bool SimulatorCollectionResourceImpl::isCollection() const
43 {
44     return true;
45 }
46
47 void SimulatorCollectionResourceImpl::setName(const std::string &name)
48 {
49     VALIDATE_INPUT(name.empty(), "Name is empty!")
50     m_name = name;
51 }
52
53 void SimulatorCollectionResourceImpl::setURI(const std::string &uri)
54 {
55     VALIDATE_INPUT(uri.empty(), "Uri is empty!")
56
57     std::lock_guard<std::recursive_mutex> lock(m_objectLock);
58     if (m_resourceHandle)
59     {
60         throw SimulatorException(SIMULATOR_OPERATION_NOT_ALLOWED,
61                                  "URI can not be set when resource is started!");
62     }
63
64     m_uri = uri;
65 }
66
67 void SimulatorCollectionResourceImpl::setResourceType(const std::string &resourceType)
68 {
69     VALIDATE_INPUT(resourceType.empty(), "Resource type is empty!")
70
71     std::lock_guard<std::recursive_mutex> lock(m_objectLock);
72     if (m_resourceHandle)
73     {
74         throw SimulatorException(SIMULATOR_OPERATION_NOT_ALLOWED,
75                                  "Resource type can not be set when resource is started!");
76     }
77
78     m_resourceType = resourceType;
79 }
80
81 void SimulatorCollectionResourceImpl::setInterface(const std::string &interfaceType)
82 {
83     VALIDATE_INPUT(interfaceType.empty(), "Interface type list is empty!")
84
85     std::lock_guard<std::recursive_mutex> lock(m_objectLock);
86     if (m_resourceHandle)
87     {
88         throw SimulatorException(SIMULATOR_OPERATION_NOT_ALLOWED,
89                                  "Resource interface can not be reset when resource is started!");
90     }
91
92     m_interfaces = {interfaceType};
93 }
94
95 void SimulatorCollectionResourceImpl::setInterface(const std::vector<std::string> &interfaceTypes)
96 {
97     VALIDATE_INPUT(interfaceTypes.empty(), "Interface type list is empty!")
98
99     std::lock_guard<std::recursive_mutex> lock(m_objectLock);
100     if (m_resourceHandle)
101     {
102         throw SimulatorException(SIMULATOR_OPERATION_NOT_ALLOWED,
103                                  "Resource interface can not be reset when resource is started!");
104     }
105
106     m_interfaces = interfaceTypes;
107     auto lastElement = std::unique(m_interfaces.begin(), m_interfaces.end());
108     m_interfaces.erase(lastElement, m_interfaces.end());
109 }
110
111 void SimulatorCollectionResourceImpl::addInterface(const std::string &interfaceType)
112 {
113     VALIDATE_INPUT(interfaceType.empty(), "Interface type is empty!")
114
115     if (interfaceType == OC::LINK_INTERFACE
116         || interfaceType == OC::BATCH_INTERFACE
117         || interfaceType == OC::DEFAULT_INTERFACE)
118     {
119         if (m_interfaces.end() != std::find(m_interfaces.begin(), m_interfaces.end(), interfaceType))
120         {
121             SIM_LOG(ILogger::ERROR, "Resource already supporting this Interface: " << interfaceType);
122             return;
123         }
124
125         std::lock_guard<std::recursive_mutex> lock(m_objectLock);
126         typedef OCStackResult (*bindInterfaceToResource)(const OCResourceHandle &,
127                 const std::string &);
128
129         invokeocplatform(static_cast<bindInterfaceToResource>(
130                              OC::OCPlatform::bindInterfaceToResource), m_resourceHandle,
131                          interfaceType);
132     }
133     else
134     {
135         throw NoSupportException("Invalid interface type for a collection type resource!");
136     }
137
138     m_interfaces.push_back(interfaceType);
139 }
140
141 void SimulatorCollectionResourceImpl::setObservable(bool state)
142 {
143     std::lock_guard<std::recursive_mutex> lock(m_objectLock);
144     if (m_resourceHandle)
145     {
146         throw SimulatorException(SIMULATOR_OPERATION_NOT_ALLOWED,
147                                  "Observation state can not be changed when resource is started!");
148     }
149
150     if (state)
151         m_property = static_cast<OCResourceProperty>(m_property | OC_OBSERVABLE);
152     else
153         m_property = static_cast<OCResourceProperty>(m_property ^ OC_OBSERVABLE);
154 }
155
156 void SimulatorCollectionResourceImpl::setDiscoverable(bool state)
157 {
158     std::lock_guard<std::recursive_mutex> lock(m_objectLock);
159     if (m_resourceHandle)
160     {
161         throw SimulatorException(SIMULATOR_OPERATION_NOT_ALLOWED,
162                                  "Discoverable state can not be changed when resource is started!");
163     }
164
165     if (state)
166         m_property = static_cast<OCResourceProperty>(m_property | OC_DISCOVERABLE);
167     else
168         m_property = static_cast<OCResourceProperty>(m_property ^ OC_DISCOVERABLE);
169 }
170
171 void SimulatorCollectionResourceImpl::setObserverCallback(ObserverCallback callback)
172 {
173     VALIDATE_CALLBACK(callback)
174     m_observeCallback = callback;
175 }
176
177 void SimulatorCollectionResourceImpl::setModelChangeCallback(ResourceModelUpdateCallback callback)
178 {
179     VALIDATE_CALLBACK(callback)
180     m_modelCallback = callback;
181 }
182
183 bool SimulatorCollectionResourceImpl::isObservable() const
184 {
185     return ((m_property & OC_OBSERVABLE) == OC_OBSERVABLE);
186 }
187
188 bool SimulatorCollectionResourceImpl::isDiscoverable() const
189 {
190     return ((m_property & OC_DISCOVERABLE) == OC_DISCOVERABLE);
191 }
192
193 bool SimulatorCollectionResourceImpl::isStarted() const
194 {
195     return (nullptr != m_resourceHandle);
196 }
197
198 void SimulatorCollectionResourceImpl::start()
199 {
200     std::lock_guard<std::recursive_mutex> lock(m_objectLock);
201     if (m_resourceHandle)
202     {
203         SIM_LOG(ILogger::INFO, "[" << m_name << "] " << "Resource already started!")
204         return;
205     }
206
207     if (m_uri.empty() || m_resourceType.empty())
208     {
209         throw SimulatorException(SIMULATOR_ERROR, "Incomplete data to start resource!");
210     }
211
212     typedef OCStackResult (*RegisterResource)(OCResourceHandle &, std::string &, const std::string &,
213             const std::string &, OC::EntityHandler, uint8_t);
214
215     invokeocplatform(static_cast<RegisterResource>(OC::OCPlatform::registerResource),
216                      m_resourceHandle, m_uri, m_resourceType, m_interfaces[0],
217                      std::bind(&SimulatorCollectionResourceImpl::handleRequests,
218                                this, std::placeholders::_1), m_property);
219
220     for (size_t index = 1; m_interfaces.size() > 1 && index < m_interfaces.size(); index++)
221     {
222         typedef OCStackResult (*bindInterfaceToResource)(const OCResourceHandle &,
223                 const std::string &);
224
225         try
226         {
227             invokeocplatform(static_cast<bindInterfaceToResource>(
228                                  OC::OCPlatform::bindInterfaceToResource), m_resourceHandle,
229                              m_interfaces[index]);
230         }
231         catch (SimulatorException &e)
232         {
233             stop();
234             throw;
235         }
236     }
237 }
238
239 void SimulatorCollectionResourceImpl::stop()
240 {
241     std::lock_guard<std::recursive_mutex> lock(m_objectLock);
242     if (!m_resourceHandle)
243     {
244         SIM_LOG(ILogger::INFO, "[" << m_name << "] " << "Resource is not started yet!")
245         return;
246     }
247
248     // Unregister the resource from stack
249     typedef OCStackResult (*UnregisterResource)(const OCResourceHandle &);
250
251     invokeocplatform(static_cast<UnregisterResource>(OC::OCPlatform::unregisterResource),
252                      m_resourceHandle);
253
254     m_resourceHandle = nullptr;
255 }
256
257 SimulatorResourceModel SimulatorCollectionResourceImpl::getResourceModel()
258 {
259     std::lock_guard<std::mutex> lock(m_modelLock);
260     return m_resModel;
261 }
262
263 std::vector<ObserverInfo> SimulatorCollectionResourceImpl::getObservers() const
264 {
265     return m_observersList;
266 }
267
268 void SimulatorCollectionResourceImpl::notify(int observerID)
269 {
270     std::lock_guard<std::recursive_mutex> lock(m_objectLock);
271     if (!m_resourceHandle)
272         return;
273
274     OC::ObservationIds observers {static_cast<OCObservationId>(observerID)};
275     sendNotification(observers);
276 }
277
278 void SimulatorCollectionResourceImpl::notifyAll()
279 {
280     std::lock_guard<std::recursive_mutex> lock(m_objectLock);
281     if (!m_resourceHandle)
282         return;
283
284     if (!m_observersList.size())
285         return;
286
287     OC::ObservationIds observers;
288     for (auto &observer : m_observersList)
289         observers.push_back(observer.id);
290     sendNotification(observers);
291 }
292
293 std::vector<std::string> SimulatorCollectionResourceImpl::getSupportedResources()
294 {
295     return m_supportedTypes;
296 }
297
298 void SimulatorCollectionResourceImpl::addChildResource(const SimulatorResourceSP &resource)
299 {
300     VALIDATE_INPUT(!resource, "Invalid child resource!")
301
302     std::lock_guard<std::mutex> lock(m_childResourcesLock);
303     if (m_childResources.end() != m_childResources.find(resource->getURI()))
304     {
305         throw SimulatorException(SIMULATOR_ERROR, "Child resource with same URI is already exisit!");
306     }
307
308     m_childResources[resource->getURI()] = resource;
309     addLink(resource);
310
311     // Notify application and observers
312     if (m_modelCallback)
313         m_modelCallback(m_uri, m_resModel);
314     notifyAll();
315 }
316
317 void SimulatorCollectionResourceImpl::removeChildResource(const SimulatorResourceSP &resource)
318 {
319     VALIDATE_INPUT(!resource, "Invalid child resource!")
320
321     std::lock_guard<std::mutex> lock(m_childResourcesLock);
322     if (m_childResources.end() == m_childResources.find(resource->getURI()))
323     {
324         throw SimulatorException(SIMULATOR_ERROR, "Child resource not found in collection!");
325     }
326
327     removeLink(resource->getURI());
328     m_childResources.erase(m_childResources.find(resource->getURI()));
329
330     // Notify application and observers
331     if (m_modelCallback)
332         m_modelCallback(m_uri, m_resModel);
333     notifyAll();
334 }
335
336 void SimulatorCollectionResourceImpl::removeChildResource(const std::string &uri)
337 {
338     VALIDATE_INPUT(uri.empty(), "Uri is empty!")
339
340     std::lock_guard<std::mutex> lock(m_childResourcesLock);
341     if (m_childResources.end() == m_childResources.find(uri))
342     {
343         throw SimulatorException(SIMULATOR_ERROR, "Child resource not found in collection!");
344     }
345
346     removeLink(uri);
347     m_childResources.erase(m_childResources.find(uri));
348
349     // Notify application and observers
350     if (m_modelCallback)
351         m_modelCallback(m_uri, m_resModel);
352     notifyAll();
353 }
354
355 std::vector<SimulatorResourceSP> SimulatorCollectionResourceImpl::getChildResources()
356 {
357     std::lock_guard<std::mutex> lock(m_childResourcesLock);
358
359     std::vector<SimulatorResourceSP> result;
360     for (auto &entry : m_childResources)
361         result.push_back(entry.second);
362
363     return result;
364 }
365
366 void SimulatorCollectionResourceImpl::setResourceModel(const SimulatorResourceModel &resModel)
367 {
368     std::lock_guard<std::mutex> lock(m_modelLock);
369     m_resModel = resModel;
370 }
371
372 void SimulatorCollectionResourceImpl::setResourceModelSchema(
373     const std::shared_ptr<SimulatorResourceModelSchema> &resModelSchema)
374 {
375     std::lock_guard<std::mutex> lock(m_modelSchemaLock);
376     m_resModelSchema = resModelSchema;
377 }
378
379 void SimulatorCollectionResourceImpl::setRequestModel(
380     const std::unordered_map<std::string, std::shared_ptr<RequestModel>> &requestModels)
381 {
382     m_requestModels = requestModels;
383 }
384
385 OCEntityHandlerResult SimulatorCollectionResourceImpl::handleRequests(
386     std::shared_ptr<OC::OCResourceRequest> request)
387 {
388     if (!request)
389     {
390         OIC_LOG(ERROR, TAG, "Request received from stack is null!");
391         return OC_EH_ERROR;
392     }
393
394     // Handle GET, PUT, POST and DELETE requests
395     if (OC::RequestHandlerFlag::RequestFlag & request->getRequestHandlerFlag())
396     {
397         {
398             OC::OCRepresentation rep = request->getResourceRepresentation();
399             std::string payload = getPayloadString(rep);
400             SIM_LOG(ILogger::INFO, "[" << m_name << "] " << request->getRequestType()
401                     << " request received. \n**Payload details**\n" << payload)
402         }
403
404         // Check if resource support GET request
405         if (m_requestModels.end() == m_requestModels.find(request->getRequestType()))
406         {
407             SIM_LOG(ILogger::INFO, "Resource does not support GET request!")
408             return sendResponse(request, 405, OC_EH_ERROR);
409         }
410
411         // Handling interface query parameter "if"
412         auto interfaceType = m_interfaces[0];
413         auto requestQueryParams = request->getQueryParameters();
414         if (requestQueryParams.end() != requestQueryParams.find("if"))
415         {
416             interfaceType = requestQueryParams["if"];
417         }
418
419         if (!isValidInterface(interfaceType, request->getRequestType()))
420         {
421             SIM_LOG(ILogger::INFO, "Invalid interface type: " << interfaceType)
422             return OC_EH_ERROR;
423         }
424
425         // Handover the request to appropriate interface handler
426         std::shared_ptr<OC::OCResourceResponse> response;
427         if (interfaceType == OC::DEFAULT_INTERFACE)
428         {
429             response = requestOnBaseLineInterface(request);
430         }
431         else if (interfaceType == OC::LINK_INTERFACE)
432         {
433             response = requestOnLinkListInterface(request);
434         }
435         else if (interfaceType == OC::BATCH_INTERFACE)
436         {
437             response = requestOnBatchInterface(request);
438         }
439
440         // Send response if the request handled by resource
441         if (response)
442         {
443             if (OC_STACK_OK != OC::OCPlatform::sendResponse(response))
444                 return OC_EH_ERROR;
445         }
446         else
447         {
448             SIM_LOG(ILogger::ERROR, "[" << m_name << "] " << "Unsupported request received!")
449             return OC_EH_ERROR;
450         }
451     }
452
453     if (OC::RequestHandlerFlag::ObserverFlag & request->getRequestHandlerFlag())
454     {
455         if (!isObservable())
456         {
457             SIM_LOG(ILogger::INFO, "[" << m_uri << "] Resource is not observable, sending error response!")
458             return OC_EH_ERROR;
459         }
460
461         OC::ObservationInfo observationInfo = request->getObservationInfo();
462         if (OC::ObserveAction::ObserveRegister == observationInfo.action)
463         {
464             SIM_LOG(ILogger::INFO, "[" << m_uri << "] OBSERVE REGISTER request received");
465
466             ObserverInfo info {observationInfo.obsId, observationInfo.address, observationInfo.port};
467             m_observersList.push_back(info);
468
469             if (m_observeCallback)
470                 m_observeCallback(m_uri, ObservationStatus::REGISTER, info);
471         }
472         else if (OC::ObserveAction::ObserveUnregister == observationInfo.action)
473         {
474             SIM_LOG(ILogger::INFO, "[" << m_uri << "] OBSERVE UNREGISTER request received");
475
476             ObserverInfo info;
477             for (auto iter = m_observersList.begin(); iter != m_observersList.end(); iter++)
478             {
479                 if ((info = *iter), info.id == observationInfo.obsId)
480                 {
481                     m_observersList.erase(iter);
482                     break;
483                 }
484             }
485
486             if (m_observeCallback)
487                 m_observeCallback(m_uri, ObservationStatus::UNREGISTER, info);
488         }
489     }
490
491     return OC_EH_OK;
492 }
493
494 std::shared_ptr<OC::OCResourceResponse> SimulatorCollectionResourceImpl::requestOnBaseLineInterface(
495     std::shared_ptr<OC::OCResourceRequest> request)
496 {
497     std::shared_ptr<OC::OCResourceResponse> response;
498     if ("GET" == request->getRequestType())
499     {
500         // Construct the representation
501         OC::OCRepresentation ocRep = m_resModel.asOCRepresentation();
502         response = std::make_shared<OC::OCResourceResponse>();
503         response->setErrorCode(200);
504         response->setResponseResult(OC_EH_OK);
505         response->setResourceRepresentation(ocRep);
506         std::string resPayload = getPayloadString(ocRep);
507         SIM_LOG(ILogger::INFO, "[" << m_uri <<
508                 "] Sending response for GET request. \n**Payload details**" << resPayload)
509     }
510
511     if (response)
512     {
513         response->setRequestHandle(request->getRequestHandle());
514         response->setResourceHandle(request->getResourceHandle());
515     }
516
517     return response;
518 }
519
520 std::shared_ptr<OC::OCResourceResponse> SimulatorCollectionResourceImpl::requestOnLinkListInterface(
521     std::shared_ptr<OC::OCResourceRequest> request)
522 {
523     std::lock_guard<std::mutex> lock(m_childResourcesLock);
524     std::shared_ptr<OC::OCResourceResponse> response;
525
526     if ("GET" == request->getRequestType())
527     {
528         // Construct the representation
529         OC::OCRepresentation ocRep;
530         std::vector<OC::OCRepresentation> links;
531         for (auto &entry : m_childResources)
532         {
533             OC::OCRepresentation oicLink;
534             oicLink.setValue("href", entry.second->getURI());
535             oicLink.setValue("rt", entry.second->getResourceType());
536             oicLink.setValue("if", entry.second->getInterface()[0]);
537             links.push_back(oicLink);
538         }
539
540         ocRep.setValue("links", links);
541
542         response = std::make_shared<OC::OCResourceResponse>();
543         response->setRequestHandle(request->getRequestHandle());
544         response->setResourceHandle(request->getResourceHandle());
545         response->setErrorCode(200);
546         response->setResponseResult(OC_EH_OK);
547         response->setResourceRepresentation(ocRep);
548         std::string resPayload = getPayloadString(ocRep);
549         SIM_LOG(ILogger::INFO, "[" << m_uri <<
550                 "] Sending response for GET request. \n**Payload details**" << resPayload)
551     }
552
553     return nullptr;
554 }
555
556 std::shared_ptr<OC::OCResourceResponse> SimulatorCollectionResourceImpl::requestOnBatchInterface(
557     std::shared_ptr<OC::OCResourceRequest>)
558 {
559     return nullptr;
560 }
561
562 void SimulatorCollectionResourceImpl::sendNotification(OC::ObservationIds &observers)
563 {
564     std::lock_guard<std::recursive_mutex> lock(m_objectLock);
565     std::shared_ptr<OC::OCResourceResponse> response(new OC::OCResourceResponse());
566     response->setErrorCode(200);
567     response->setResponseResult(OC_EH_OK);
568
569     OC::OCRepresentation ocRep = m_resModel.asOCRepresentation();
570     response->setResourceRepresentation(ocRep, OC::DEFAULT_INTERFACE);
571
572     typedef OCStackResult (*NotifyListOfObservers)(OCResourceHandle, OC::ObservationIds &,
573             const std::shared_ptr<OC::OCResourceResponse>);
574
575     invokeocplatform(static_cast<NotifyListOfObservers>(OC::OCPlatform::notifyListOfObservers),
576                      m_resourceHandle, observers, response);
577 }
578
579 void SimulatorCollectionResourceImpl::addLink(const SimulatorResourceSP &resource)
580 {
581     std::lock_guard<std::mutex> lock(m_modelLock);
582     if (!m_resModel.contains("links"))
583         return;
584
585     // Create new OIC Link
586     SimulatorResourceModel newLink;
587     newLink.add("href", resource->getURI());
588     newLink.add("rt", resource->getResourceType());
589     newLink.add("if", resource->getInterface()[0]);
590
591     // Add OIC Link if it is not present
592     bool found = false;
593     std::vector<SimulatorResourceModel> links =
594         m_resModel.get<std::vector<SimulatorResourceModel>>("links");
595     for (auto &link : links)
596     {
597         std::string linkURI = link.get<std::string>("href");
598         if (linkURI == resource->getURI())
599         {
600             found = true;
601             break;
602         }
603     }
604
605     if (false ==  found)
606     {
607         links.push_back(newLink);
608         m_resModel.update("links", links);
609     }
610 }
611
612 void SimulatorCollectionResourceImpl::removeLink(std::string uri)
613 {
614     std::lock_guard<std::mutex> lock(m_modelLock);
615     if (!m_resModel.contains("links"))
616         return;
617
618     // Add OIC Link if it is not present
619     std::vector<SimulatorResourceModel> links =
620         m_resModel.get<std::vector<SimulatorResourceModel>>("links");
621     for (size_t i = 0; i < links.size(); i++)
622     {
623         std::string linkURI = links[i].get<std::string>("href");
624         if (linkURI == uri)
625         {
626             links.erase(links.begin() + i);
627             m_resModel.update("links", links);
628             break;
629         }
630     }
631 }
632
633 OCEntityHandlerResult SimulatorCollectionResourceImpl::sendResponse(
634     const std::shared_ptr<OC::OCResourceRequest> &request, const int errorCode,
635     OCEntityHandlerResult responseResult)
636 {
637     std::shared_ptr<OC::OCResourceResponse> response(new OC::OCResourceResponse());
638     response->setRequestHandle(request->getRequestHandle());
639     response->setResourceHandle(request->getResourceHandle());
640     response->setErrorCode(errorCode);
641     response->setResponseResult(responseResult);
642     if (OC_STACK_OK != OC::OCPlatform::sendResponse(response))
643     {
644         return OC_EH_ERROR;
645     }
646
647     return OC_EH_OK;
648 }
649
650 bool SimulatorCollectionResourceImpl::isValidInterface(const std::string &interfaceType,
651         const std::string &requestType)
652 {
653     // Is this OIC defined interface ?
654     if (false ==
655         OCInterfaceDetails::getInstance()->isRequestSupported(interfaceType, requestType))
656     {
657         return false;
658     }
659
660     // Does resource support this interface ?
661     std::lock_guard<std::recursive_mutex> lock(m_objectLock);
662     if (m_interfaces.end() ==
663         std::find(m_interfaces.begin(), m_interfaces.end(), interfaceType))
664     {
665         return false;
666     }
667
668     return true;
669 }