Added Simulator Resource Model Support to read collection resource.
[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 bool SimulatorCollectionResourceImpl::isObservable()
151 {
152     return (m_property & OC_OBSERVABLE);
153 }
154
155 bool SimulatorCollectionResourceImpl::isStarted()
156 {
157     return (nullptr != m_resourceHandle);
158 }
159
160 void SimulatorCollectionResourceImpl::start()
161 {
162     std::lock_guard<std::recursive_mutex> lock(m_objectLock);
163     if (m_resourceHandle)
164     {
165         throw SimulatorException(SIMULATOR_ERROR, "Collection already registered!");
166     }
167
168     if (m_uri.empty() || m_resourceType.empty())
169     {
170         throw SimulatorException(SIMULATOR_ERROR, "Found incomplete data to start resource!");
171     }
172
173     typedef OCStackResult (*RegisterResource)(OCResourceHandle &, std::string &, const std::string &,
174             const std::string &, OC::EntityHandler, uint8_t);
175
176     invokeocplatform(static_cast<RegisterResource>(OC::OCPlatform::registerResource),
177                      m_resourceHandle, m_uri, m_resourceType, m_interfaces[0],
178                      std::bind(&SimulatorCollectionResourceImpl::handleRequests,
179                                this, std::placeholders::_1), m_property);
180
181     for (size_t index = 1; m_interfaces.size() > 1 && index < m_interfaces.size(); index++)
182     {
183         typedef OCStackResult (*bindInterfaceToResource)(const OCResourceHandle &,
184                 const std::string &);
185
186         try
187         {
188             invokeocplatform(static_cast<bindInterfaceToResource>(
189                                  OC::OCPlatform::bindInterfaceToResource), m_resourceHandle,
190                              m_interfaces[index]);
191         }
192         catch (SimulatorException &e)
193         {
194             stop();
195             throw;
196         }
197     }
198 }
199
200 void SimulatorCollectionResourceImpl::stop()
201 {
202     std::lock_guard<std::recursive_mutex> lock(m_objectLock);
203     if (!m_resourceHandle)
204         return;
205
206     typedef OCStackResult (*UnregisterResource)(const OCResourceHandle &);
207
208     invokeocplatform(static_cast<UnregisterResource>(OC::OCPlatform::unregisterResource),
209                      m_resourceHandle);
210
211     m_resourceHandle = nullptr;
212 }
213
214 SimulatorResourceModel SimulatorCollectionResourceImpl::getResourceModel()
215 {
216     std::lock_guard<std::mutex> lock(m_modelLock);
217     return m_resModel;
218 }
219
220 void SimulatorCollectionResourceImpl::setResourceModel(const SimulatorResourceModel &resModel)
221 {
222     std::lock_guard<std::mutex> lock(m_modelLock);
223     m_resModel = resModel;
224 }
225
226 std::vector<ObserverInfo> SimulatorCollectionResourceImpl::getObserversList()
227 {
228     return m_observersList;
229 }
230
231 void SimulatorCollectionResourceImpl::notify(int id)
232 {
233     std::lock_guard<std::recursive_mutex> lock(m_objectLock);
234     if (!m_resourceHandle)
235         return;
236
237     OC::ObservationIds observers {static_cast<OCObservationId>(id)};
238     sendNotification(observers);
239 }
240
241 void SimulatorCollectionResourceImpl::notifyAll()
242 {
243     std::lock_guard<std::recursive_mutex> lock(m_objectLock);
244     if (!m_resourceHandle)
245         return;
246
247     if (!m_observersList.size())
248         return;
249
250     OC::ObservationIds observers;
251     for (auto &observer : m_observersList)
252         observers.push_back(observer.id);
253     sendNotification(observers);
254 }
255
256 std::vector<std::string> SimulatorCollectionResourceImpl::getSupportedResources()
257 {
258     return m_supportedTypes;
259 }
260
261 void SimulatorCollectionResourceImpl::addChildResource(SimulatorResourceSP &resource)
262 {
263     VALIDATE_INPUT(!resource, "Invalid child resource!")
264
265     std::lock_guard<std::mutex> lock(m_childResourcesLock);
266     if (m_childResources.end() != m_childResources.find(resource->getURI()))
267     {
268         throw SimulatorException(SIMULATOR_ERROR, "Child resource with same URI is already exisit!");
269     }
270
271     m_childResources[resource->getURI()] = resource;
272 }
273
274 void SimulatorCollectionResourceImpl::removeChildResource(SimulatorResourceSP &resource)
275 {
276     VALIDATE_INPUT(!resource, "Invalid child resource!")
277
278     std::lock_guard<std::mutex> lock(m_childResourcesLock);
279     if (m_childResources.end() == m_childResources.find(resource->getURI()))
280     {
281         throw SimulatorException(SIMULATOR_ERROR, "Child resource not found in collection!");
282     }
283
284     m_childResources.erase(m_childResources.find(resource->getURI()));
285 }
286
287 void SimulatorCollectionResourceImpl::removeChildResource(const std::string &uri)
288 {
289     VALIDATE_INPUT(uri.empty(), "Uri is empty!")
290
291     std::lock_guard<std::mutex> lock(m_childResourcesLock);
292     if (m_childResources.end() == m_childResources.find(uri))
293     {
294         throw SimulatorException(SIMULATOR_ERROR, "Child resource not found in collection!");
295     }
296
297     m_childResources.erase(m_childResources.find(uri));
298 }
299
300 std::vector<SimulatorResourceSP> SimulatorCollectionResourceImpl::getChildResources()
301 {
302     std::lock_guard<std::mutex> lock(m_childResourcesLock);
303
304     std::vector<SimulatorResourceSP> result;
305     for (auto &entry : m_childResources)
306         result.push_back(entry.second);
307
308     return result;
309 }
310
311 OCEntityHandlerResult SimulatorCollectionResourceImpl::handleRequests(
312     std::shared_ptr<OC::OCResourceRequest> request)
313 {
314     if (!request)
315         return OC_EH_ERROR;
316
317     if (OC::RequestHandlerFlag::RequestFlag & request->getRequestHandlerFlag())
318     {
319         {
320             OC::OCRepresentation rep = request->getResourceRepresentation();
321             std::string payload = getPayloadString(rep);
322             SIM_LOG(ILogger::INFO, "[" << m_name << "] " << request->getRequestType()
323                     << " request received. \n**Payload details**\n" << payload)
324         }
325
326         // Handover the request to appropriate interface handler
327         std::string interfaceType(OC::DEFAULT_INTERFACE);
328         OC::QueryParamsMap queryParams = request->getQueryParameters();
329         if (queryParams.end() != queryParams.find("if"))
330             interfaceType = queryParams["if"];
331
332         std::shared_ptr<OC::OCResourceResponse> response;
333         if (interfaceType == OC::DEFAULT_INTERFACE)
334         {
335             response = requestOnBaseLineInterface(request);
336         }
337         else if (interfaceType == OC::LINK_INTERFACE)
338         {
339             response = requestOnLinkListInterface(request);
340         }
341         else if (interfaceType == OC::BATCH_INTERFACE)
342         {
343             response = requestOnBatchInterface(request);
344         }
345
346         // Send response if the request handled by resource
347         if (response)
348         {
349             if (OC_STACK_OK != OC::OCPlatform::sendResponse(response))
350                 return OC_EH_ERROR;
351         }
352         else
353         {
354             SIM_LOG(ILogger::ERROR, "[" << m_name << "] " << "Unsupported request received!")
355             return OC_EH_ERROR;
356         }
357     }
358
359     if (OC::RequestHandlerFlag::ObserverFlag & request->getRequestHandlerFlag())
360     {
361         if (!isObservable())
362         {
363             SIM_LOG(ILogger::INFO, "[" << m_uri << "] OBSERVE request received")
364             SIM_LOG(ILogger::INFO, "[" << m_uri << "] Sending error as resource is in unobservable state!")
365             return OC_EH_ERROR;
366         }
367
368         OC::ObservationInfo observationInfo = request->getObservationInfo();
369         if (OC::ObserveAction::ObserveRegister == observationInfo.action)
370         {
371             SIM_LOG(ILogger::INFO, "[" << m_uri << "] OBSERVE REGISTER request received");
372
373             ObserverInfo info {observationInfo.obsId, observationInfo.address, observationInfo.port};
374             m_observersList.push_back(info);
375
376             if (m_observeCallback)
377                 m_observeCallback(m_uri, ObservationStatus::REGISTER, info);
378         }
379         else if (OC::ObserveAction::ObserveUnregister == observationInfo.action)
380         {
381             SIM_LOG(ILogger::INFO, "[" << m_uri << "] OBSERVE UNREGISTER request received");
382
383             ObserverInfo info;
384             for (auto iter = m_observersList.begin(); iter != m_observersList.end(); iter++)
385             {
386                 if ((info = *iter), info.id == observationInfo.obsId)
387                 {
388                     m_observersList.erase(iter);
389                     break;
390                 }
391             }
392
393             if (m_observeCallback)
394                 m_observeCallback(m_uri, ObservationStatus::UNREGISTER, info);
395         }
396     }
397
398     return OC_EH_OK;
399 }
400
401 std::shared_ptr<OC::OCResourceResponse> SimulatorCollectionResourceImpl::requestOnBaseLineInterface(
402     std::shared_ptr<OC::OCResourceRequest> request)
403 {
404     std::shared_ptr<OC::OCResourceResponse> response;
405     if ("GET" == request->getRequestType())
406     {
407         // Construct the representation
408         OC::OCRepresentation ocRep = prepareRepresentation();
409         response = std::make_shared<OC::OCResourceResponse>();
410         response->setErrorCode(200);
411         response->setResponseResult(OC_EH_OK);
412         response->setResourceRepresentation(ocRep);
413         std::string resPayload = getPayloadString(ocRep);
414         SIM_LOG(ILogger::INFO, "[" << m_uri <<
415                 "] Sending response for GET request. \n**Payload details**" << resPayload)
416     }
417
418     // TODO: Handle PUT, POST and DELETE requests
419
420     if (response)
421     {
422         response->setRequestHandle(request->getRequestHandle());
423         response->setResourceHandle(request->getResourceHandle());
424     }
425
426     return response;
427 }
428
429 std::shared_ptr<OC::OCResourceResponse> SimulatorCollectionResourceImpl::requestOnLinkListInterface(
430     std::shared_ptr<OC::OCResourceRequest> request)
431 {
432     std::lock_guard<std::mutex> lock(m_childResourcesLock);
433     std::shared_ptr<OC::OCResourceResponse> response;
434     if ("GET" == request->getRequestType())
435     {
436         // Construct the representation
437         OC::OCRepresentation ocRep;
438         std::vector<OC::OCRepresentation> links;
439         int index = 0;
440         for (auto &entry : m_childResources)
441         {
442             links[index].setValue("href", entry.second->getURI());
443             links[index].setValue("rt", entry.second->getResourceType());
444             links[index].setValue("if", entry.second->getInterface()[0]);
445         }
446
447         ocRep.setValue("links", links);
448
449         response = std::make_shared<OC::OCResourceResponse>();
450         response->setRequestHandle(request->getRequestHandle());
451         response->setResourceHandle(request->getResourceHandle());
452         response->setErrorCode(200);
453         response->setResponseResult(OC_EH_OK);
454         response->setResourceRepresentation(ocRep);
455         std::string resPayload = getPayloadString(ocRep);
456         SIM_LOG(ILogger::INFO, "[" << m_uri <<
457                 "] Sending response for GET request. \n**Payload details**" << resPayload)
458     }
459
460     return nullptr;
461 }
462
463 std::shared_ptr<OC::OCResourceResponse> SimulatorCollectionResourceImpl::requestOnBatchInterface(
464     std::shared_ptr<OC::OCResourceRequest>)
465 {
466     // TODO: Handle this interface
467     return nullptr;
468 }
469
470 void SimulatorCollectionResourceImpl::sendNotification(OC::ObservationIds &observers)
471 {
472     std::lock_guard<std::recursive_mutex> lock(m_objectLock);
473     std::shared_ptr<OC::OCResourceResponse> response(new OC::OCResourceResponse());
474     response->setErrorCode(200);
475     response->setResponseResult(OC_EH_OK);
476     response->setResourceRepresentation(prepareRepresentation(), OC::DEFAULT_INTERFACE);
477
478     typedef OCStackResult (*NotifyListOfObservers)(OCResourceHandle, OC::ObservationIds &,
479             const std::shared_ptr<OC::OCResourceResponse>);
480
481     invokeocplatform(static_cast<NotifyListOfObservers>(OC::OCPlatform::notifyListOfObservers),
482                      m_resourceHandle, observers, response);
483 }
484
485 OC::OCRepresentation SimulatorCollectionResourceImpl::prepareRepresentation()
486 {
487     OC::OCRepresentation ocRep;
488
489     ocRep.setValue("n", getName());
490     ocRep.setResourceTypes({m_resourceType});
491     ocRep.setResourceInterfaces(m_interfaces);
492
493     // Add "rts" attribute
494     std::ostringstream supportedTypes;
495     for (auto &type : m_supportedTypes)
496     {
497         if (!supportedTypes.str().empty())
498             supportedTypes << " ,";
499         supportedTypes << type;
500     }
501     ocRep.setValue("rts", supportedTypes.str());
502
503     // Add "links" attribute
504     std::vector<OC::OCRepresentation> links;
505     int index = 0;
506     for (auto &entry : m_childResources)
507     {
508         links[index].setValue("href", entry.second->getURI());
509         links[index].setValue("rt", entry.second->getResourceType());
510         links[index].setValue("if", entry.second->getInterface()[0]);
511     }
512
513     ocRep.setValue("links", links);
514
515     return ocRep;
516 }