1 /******************************************************************
3 * Copyright 2015 Samsung Electronics All Rights Reserved.
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 ******************************************************************/
21 #include "simulator_collection_resource_impl.h"
22 #include "simulator_utils.h"
23 #include "oc_interface_details.h"
24 #include "simulator_logger.h"
27 #define TAG "SIMULATOR_COLLECTION_RESOURCE"
29 SimulatorCollectionResourceImpl::SimulatorCollectionResourceImpl()
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);
35 // Add empty vector of OIC Links
36 std::vector<SimulatorResourceModel> links;
37 m_resModel.add("links", links);
39 m_resourceHandle = nullptr;
42 bool SimulatorCollectionResourceImpl::isCollection() const
47 void SimulatorCollectionResourceImpl::setName(const std::string &name)
49 VALIDATE_INPUT(name.empty(), "Name is empty!")
53 void SimulatorCollectionResourceImpl::setURI(const std::string &uri)
55 VALIDATE_INPUT(uri.empty(), "Uri is empty!")
57 std::lock_guard<std::recursive_mutex> lock(m_objectLock);
60 throw SimulatorException(SIMULATOR_OPERATION_NOT_ALLOWED,
61 "URI can not be set when resource is started!");
67 void SimulatorCollectionResourceImpl::setResourceType(const std::string &resourceType)
69 VALIDATE_INPUT(resourceType.empty(), "Resource type is empty!")
71 std::lock_guard<std::recursive_mutex> lock(m_objectLock);
74 throw SimulatorException(SIMULATOR_OPERATION_NOT_ALLOWED,
75 "Resource type can not be set when resource is started!");
78 m_resourceType = resourceType;
81 void SimulatorCollectionResourceImpl::setInterface(const std::string &interfaceType)
83 VALIDATE_INPUT(interfaceType.empty(), "Interface type list is empty!")
85 std::lock_guard<std::recursive_mutex> lock(m_objectLock);
88 throw SimulatorException(SIMULATOR_OPERATION_NOT_ALLOWED,
89 "Resource interface can not be reset when resource is started!");
92 m_interfaces = {interfaceType};
95 void SimulatorCollectionResourceImpl::setInterface(const std::vector<std::string> &interfaceTypes)
97 VALIDATE_INPUT(interfaceTypes.empty(), "Interface type list is empty!")
99 std::lock_guard<std::recursive_mutex> lock(m_objectLock);
100 if (m_resourceHandle)
102 throw SimulatorException(SIMULATOR_OPERATION_NOT_ALLOWED,
103 "Resource interface can not be reset when resource is started!");
106 m_interfaces = interfaceTypes;
107 auto lastElement = std::unique(m_interfaces.begin(), m_interfaces.end());
108 m_interfaces.erase(lastElement, m_interfaces.end());
111 void SimulatorCollectionResourceImpl::addInterface(const std::string &interfaceType)
113 VALIDATE_INPUT(interfaceType.empty(), "Interface type is empty!")
115 if (interfaceType == OC::LINK_INTERFACE
116 || interfaceType == OC::BATCH_INTERFACE
117 || interfaceType == OC::DEFAULT_INTERFACE)
119 if (m_interfaces.end() != std::find(m_interfaces.begin(), m_interfaces.end(), interfaceType))
121 SIM_LOG(ILogger::ERROR, "Resource already supporting this Interface: " << interfaceType);
125 std::lock_guard<std::recursive_mutex> lock(m_objectLock);
126 typedef OCStackResult (*bindInterfaceToResource)(const OCResourceHandle &,
127 const std::string &);
129 invokeocplatform(static_cast<bindInterfaceToResource>(
130 OC::OCPlatform::bindInterfaceToResource), m_resourceHandle,
135 throw NoSupportException("Invalid interface type for a collection type resource!");
138 m_interfaces.push_back(interfaceType);
141 void SimulatorCollectionResourceImpl::setObservable(bool state)
143 std::lock_guard<std::recursive_mutex> lock(m_objectLock);
144 if (m_resourceHandle)
146 throw SimulatorException(SIMULATOR_OPERATION_NOT_ALLOWED,
147 "Observation state can not be changed when resource is started!");
151 m_property = static_cast<OCResourceProperty>(m_property | OC_OBSERVABLE);
153 m_property = static_cast<OCResourceProperty>(m_property ^ OC_OBSERVABLE);
156 void SimulatorCollectionResourceImpl::setDiscoverable(bool state)
158 std::lock_guard<std::recursive_mutex> lock(m_objectLock);
159 if (m_resourceHandle)
161 throw SimulatorException(SIMULATOR_OPERATION_NOT_ALLOWED,
162 "Discoverable state can not be changed when resource is started!");
166 m_property = static_cast<OCResourceProperty>(m_property | OC_DISCOVERABLE);
168 m_property = static_cast<OCResourceProperty>(m_property ^ OC_DISCOVERABLE);
171 void SimulatorCollectionResourceImpl::setObserverCallback(ObserverCallback callback)
173 VALIDATE_CALLBACK(callback)
174 m_observeCallback = callback;
177 void SimulatorCollectionResourceImpl::setModelChangeCallback(ResourceModelUpdateCallback callback)
179 VALIDATE_CALLBACK(callback)
180 m_modelCallback = callback;
183 bool SimulatorCollectionResourceImpl::isObservable() const
185 return ((m_property & OC_OBSERVABLE) == OC_OBSERVABLE);
188 bool SimulatorCollectionResourceImpl::isDiscoverable() const
190 return ((m_property & OC_DISCOVERABLE) == OC_DISCOVERABLE);
193 bool SimulatorCollectionResourceImpl::isStarted() const
195 return (nullptr != m_resourceHandle);
198 void SimulatorCollectionResourceImpl::start()
200 std::lock_guard<std::recursive_mutex> lock(m_objectLock);
201 if (m_resourceHandle)
203 SIM_LOG(ILogger::INFO, "[" << m_name << "] " << "Resource already started!")
207 if (m_uri.empty() || m_resourceType.empty())
209 throw SimulatorException(SIMULATOR_ERROR, "Incomplete data to start resource!");
212 typedef OCStackResult (*RegisterResource)(OCResourceHandle &, std::string &, const std::string &,
213 const std::string &, OC::EntityHandler, uint8_t);
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);
220 for (size_t index = 1; m_interfaces.size() > 1 && index < m_interfaces.size(); index++)
222 typedef OCStackResult (*bindInterfaceToResource)(const OCResourceHandle &,
223 const std::string &);
227 invokeocplatform(static_cast<bindInterfaceToResource>(
228 OC::OCPlatform::bindInterfaceToResource), m_resourceHandle,
229 m_interfaces[index]);
231 catch (SimulatorException &e)
239 void SimulatorCollectionResourceImpl::stop()
241 std::lock_guard<std::recursive_mutex> lock(m_objectLock);
242 if (!m_resourceHandle)
244 SIM_LOG(ILogger::INFO, "[" << m_name << "] " << "Resource is not started yet!")
248 // Unregister the resource from stack
249 typedef OCStackResult (*UnregisterResource)(const OCResourceHandle &);
251 invokeocplatform(static_cast<UnregisterResource>(OC::OCPlatform::unregisterResource),
254 m_resourceHandle = nullptr;
257 SimulatorResourceModel SimulatorCollectionResourceImpl::getResourceModel()
259 std::lock_guard<std::mutex> lock(m_modelLock);
263 std::vector<ObserverInfo> SimulatorCollectionResourceImpl::getObservers() const
265 return m_observersList;
268 void SimulatorCollectionResourceImpl::notify(int observerID)
270 std::lock_guard<std::recursive_mutex> lock(m_objectLock);
271 if (!m_resourceHandle)
274 OC::ObservationIds observers {static_cast<OCObservationId>(observerID)};
275 sendNotification(observers);
278 void SimulatorCollectionResourceImpl::notifyAll()
280 std::lock_guard<std::recursive_mutex> lock(m_objectLock);
281 if (!m_resourceHandle)
284 if (!m_observersList.size())
287 OC::ObservationIds observers;
288 for (auto &observer : m_observersList)
289 observers.push_back(observer.id);
290 sendNotification(observers);
293 std::vector<std::string> SimulatorCollectionResourceImpl::getSupportedResources()
295 return m_supportedTypes;
298 void SimulatorCollectionResourceImpl::addChildResource(const SimulatorResourceSP &resource)
300 VALIDATE_INPUT(!resource, "Invalid child resource!")
302 std::lock_guard<std::mutex> lock(m_childResourcesLock);
303 if (m_childResources.end() != m_childResources.find(resource->getURI()))
305 throw SimulatorException(SIMULATOR_ERROR, "Child resource with same URI is already exisit!");
308 m_childResources[resource->getURI()] = resource;
311 // Notify application and observers
313 m_modelCallback(m_uri, m_resModel);
317 void SimulatorCollectionResourceImpl::removeChildResource(const SimulatorResourceSP &resource)
319 VALIDATE_INPUT(!resource, "Invalid child resource!")
321 std::lock_guard<std::mutex> lock(m_childResourcesLock);
322 if (m_childResources.end() == m_childResources.find(resource->getURI()))
324 throw SimulatorException(SIMULATOR_ERROR, "Child resource not found in collection!");
327 removeLink(resource->getURI());
328 m_childResources.erase(m_childResources.find(resource->getURI()));
330 // Notify application and observers
332 m_modelCallback(m_uri, m_resModel);
336 void SimulatorCollectionResourceImpl::removeChildResource(const std::string &uri)
338 VALIDATE_INPUT(uri.empty(), "Uri is empty!")
340 std::lock_guard<std::mutex> lock(m_childResourcesLock);
341 if (m_childResources.end() == m_childResources.find(uri))
343 throw SimulatorException(SIMULATOR_ERROR, "Child resource not found in collection!");
347 m_childResources.erase(m_childResources.find(uri));
349 // Notify application and observers
351 m_modelCallback(m_uri, m_resModel);
355 std::vector<SimulatorResourceSP> SimulatorCollectionResourceImpl::getChildResources()
357 std::lock_guard<std::mutex> lock(m_childResourcesLock);
359 std::vector<SimulatorResourceSP> result;
360 for (auto &entry : m_childResources)
361 result.push_back(entry.second);
366 void SimulatorCollectionResourceImpl::setResourceModel(const SimulatorResourceModel &resModel)
368 std::lock_guard<std::mutex> lock(m_modelLock);
369 m_resModel = resModel;
372 void SimulatorCollectionResourceImpl::setResourceModelSchema(
373 const std::shared_ptr<SimulatorResourceModelSchema> &resModelSchema)
375 std::lock_guard<std::mutex> lock(m_modelSchemaLock);
376 m_resModelSchema = resModelSchema;
379 void SimulatorCollectionResourceImpl::setRequestModel(
380 const std::unordered_map<std::string, std::shared_ptr<RequestModel>> &requestModels)
382 m_requestModels = requestModels;
385 OCEntityHandlerResult SimulatorCollectionResourceImpl::handleRequests(
386 std::shared_ptr<OC::OCResourceRequest> request)
390 OIC_LOG(ERROR, TAG, "Request received from stack is null!");
394 // Handle GET, PUT, POST and DELETE requests
395 if (OC::RequestHandlerFlag::RequestFlag & request->getRequestHandlerFlag())
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)
404 // Check if resource support GET request
405 if (m_requestModels.end() == m_requestModels.find(request->getRequestType()))
407 SIM_LOG(ILogger::INFO, "Resource does not support GET request!")
408 return sendResponse(request, 405, OC_EH_ERROR);
411 // Handling interface query parameter "if"
412 auto interfaceType = m_interfaces[0];
413 auto requestQueryParams = request->getQueryParameters();
414 if (requestQueryParams.end() != requestQueryParams.find("if"))
416 interfaceType = requestQueryParams["if"];
419 if (!isValidInterface(interfaceType, request->getRequestType()))
421 SIM_LOG(ILogger::INFO, "Invalid interface type: " << interfaceType)
425 // Handover the request to appropriate interface handler
426 std::shared_ptr<OC::OCResourceResponse> response;
427 if (interfaceType == OC::DEFAULT_INTERFACE)
429 response = requestOnBaseLineInterface(request);
431 else if (interfaceType == OC::LINK_INTERFACE)
433 response = requestOnLinkListInterface(request);
435 else if (interfaceType == OC::BATCH_INTERFACE)
437 response = requestOnBatchInterface(request);
440 // Send response if the request handled by resource
443 if (OC_STACK_OK != OC::OCPlatform::sendResponse(response))
448 SIM_LOG(ILogger::ERROR, "[" << m_name << "] " << "Unsupported request received!")
453 if (OC::RequestHandlerFlag::ObserverFlag & request->getRequestHandlerFlag())
457 SIM_LOG(ILogger::INFO, "[" << m_uri << "] Resource is not observable, sending error response!")
461 OC::ObservationInfo observationInfo = request->getObservationInfo();
462 if (OC::ObserveAction::ObserveRegister == observationInfo.action)
464 SIM_LOG(ILogger::INFO, "[" << m_uri << "] OBSERVE REGISTER request received");
466 ObserverInfo info {observationInfo.obsId, observationInfo.address, observationInfo.port};
467 m_observersList.push_back(info);
469 if (m_observeCallback)
470 m_observeCallback(m_uri, ObservationStatus::REGISTER, info);
472 else if (OC::ObserveAction::ObserveUnregister == observationInfo.action)
474 SIM_LOG(ILogger::INFO, "[" << m_uri << "] OBSERVE UNREGISTER request received");
477 for (auto iter = m_observersList.begin(); iter != m_observersList.end(); iter++)
479 if ((info = *iter), info.id == observationInfo.obsId)
481 m_observersList.erase(iter);
486 if (m_observeCallback)
487 m_observeCallback(m_uri, ObservationStatus::UNREGISTER, info);
494 std::shared_ptr<OC::OCResourceResponse> SimulatorCollectionResourceImpl::requestOnBaseLineInterface(
495 std::shared_ptr<OC::OCResourceRequest> request)
497 std::shared_ptr<OC::OCResourceResponse> response;
498 if ("GET" == request->getRequestType())
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)
513 response->setRequestHandle(request->getRequestHandle());
514 response->setResourceHandle(request->getResourceHandle());
520 std::shared_ptr<OC::OCResourceResponse> SimulatorCollectionResourceImpl::requestOnLinkListInterface(
521 std::shared_ptr<OC::OCResourceRequest> request)
523 std::lock_guard<std::mutex> lock(m_childResourcesLock);
524 std::shared_ptr<OC::OCResourceResponse> response;
526 if ("GET" == request->getRequestType())
528 // Construct the representation
529 OC::OCRepresentation ocRep;
530 std::vector<OC::OCRepresentation> links;
531 for (auto &entry : m_childResources)
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);
540 ocRep.setValue("links", links);
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)
556 std::shared_ptr<OC::OCResourceResponse> SimulatorCollectionResourceImpl::requestOnBatchInterface(
557 std::shared_ptr<OC::OCResourceRequest>)
562 void SimulatorCollectionResourceImpl::sendNotification(OC::ObservationIds &observers)
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);
569 OC::OCRepresentation ocRep = m_resModel.asOCRepresentation();
570 response->setResourceRepresentation(ocRep, OC::DEFAULT_INTERFACE);
572 typedef OCStackResult (*NotifyListOfObservers)(OCResourceHandle, OC::ObservationIds &,
573 const std::shared_ptr<OC::OCResourceResponse>);
575 invokeocplatform(static_cast<NotifyListOfObservers>(OC::OCPlatform::notifyListOfObservers),
576 m_resourceHandle, observers, response);
579 void SimulatorCollectionResourceImpl::addLink(const SimulatorResourceSP &resource)
581 std::lock_guard<std::mutex> lock(m_modelLock);
582 if (!m_resModel.contains("links"))
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]);
591 // Add OIC Link if it is not present
593 std::vector<SimulatorResourceModel> links =
594 m_resModel.get<std::vector<SimulatorResourceModel>>("links");
595 for (auto &link : links)
597 std::string linkURI = link.get<std::string>("href");
598 if (linkURI == resource->getURI())
607 links.push_back(newLink);
608 m_resModel.update("links", links);
612 void SimulatorCollectionResourceImpl::removeLink(std::string uri)
614 std::lock_guard<std::mutex> lock(m_modelLock);
615 if (!m_resModel.contains("links"))
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++)
623 std::string linkURI = links[i].get<std::string>("href");
626 links.erase(links.begin() + i);
627 m_resModel.update("links", links);
633 OCEntityHandlerResult SimulatorCollectionResourceImpl::sendResponse(
634 const std::shared_ptr<OC::OCResourceRequest> &request, const int errorCode,
635 OCEntityHandlerResult responseResult)
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))
650 bool SimulatorCollectionResourceImpl::isValidInterface(const std::string &interfaceType,
651 const std::string &requestType)
653 // Is this OIC defined interface ?
655 OCInterfaceDetails::getInstance()->isRequestSupported(interfaceType, requestType))
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))