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