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