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