1 //******************************************************************
3 // Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
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 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
22 /// This sample provides steps to define an interface for a resource
23 /// (properties and methods) and host this resource on the server.
30 #include <condition_variable>
32 #include "OCPlatform.h"
37 namespace PH = std::placeholders;
39 static const char* SVR_DB_FILE_NAME = "./oic_svr_db_server.dat";
41 void * ChangeLightRepresentation (void *param);
42 void * handleSlowResponse (void *param, std::shared_ptr<OCResourceRequest> pRequest);
44 // Specifies where to notify all observers or list of observers
45 // false: notifies all observers
46 // true: notifies list of observers
47 bool isListOfObservers = false;
49 // Specifies secure or non-secure
50 // false: non-secure resource
51 // true: secure resource
52 bool isSecure = false;
54 /// Specifies whether Entity handler is going to do slow response or not
55 bool isSlowResponse = false;
57 // Forward declaring the entityHandler
59 /// This class represents a single resource named 'lightResource'. This resource has
60 /// two simple properties named 'state' and 'power'
66 /// Access this property from a TB client
70 std::string m_lightUri;
71 OCResourceHandle m_resourceHandle;
72 OCRepresentation m_lightRep;
73 ObservationIds m_interestedObservers;
78 :m_name("John's light"), m_state(false), m_power(0), m_lightUri("/a/light"),
79 m_resourceHandle(nullptr) {
80 // Initialize representation
81 m_lightRep.setUri(m_lightUri);
83 m_lightRep.setValue("state", m_state);
84 m_lightRep.setValue("power", m_power);
85 m_lightRep.setValue("name", m_name);
88 /* Note that this does not need to be a member function: for classes you do not have
89 access to, you can accomplish this with a free function: */
91 /// This function internally calls registerResource API.
95 std::string resourceURI = m_lightUri;
96 //resource type name. In this case, it is light
97 std::string resourceTypeName = "core.light";
98 // resource interface.
99 std::string resourceInterface = DEFAULT_INTERFACE;
101 // OCResourceProperty is defined ocstack.h
102 uint8_t resourceProperty;
105 resourceProperty = OC_DISCOVERABLE | OC_OBSERVABLE | OC_SECURE;
109 resourceProperty = OC_DISCOVERABLE | OC_OBSERVABLE;
111 EntityHandler cb = std::bind(&LightResource::entityHandler, this,PH::_1);
113 // This will internally create and register the resource.
114 OCStackResult result = OCPlatform::registerResource(
115 m_resourceHandle, resourceURI, resourceTypeName,
116 resourceInterface, cb, resourceProperty);
118 if (OC_STACK_OK != result)
120 cout << "Resource creation was unsuccessful\n";
124 OCStackResult createResource1()
126 // URI of the resource
127 std::string resourceURI = "/a/light1";
128 // resource type name. In this case, it is light
129 std::string resourceTypeName = "core.light";
130 // resource interface.
131 std::string resourceInterface = DEFAULT_INTERFACE;
133 // OCResourceProperty is defined ocstack.h
134 uint8_t resourceProperty;
137 resourceProperty = OC_DISCOVERABLE | OC_OBSERVABLE | OC_SECURE;
141 resourceProperty = OC_DISCOVERABLE | OC_OBSERVABLE;
143 EntityHandler cb = std::bind(&LightResource::entityHandler, this,PH::_1);
145 OCResourceHandle resHandle;
147 // This will internally create and register the resource.
148 OCStackResult result = OCPlatform::registerResource(
149 resHandle, resourceURI, resourceTypeName,
150 resourceInterface, cb, resourceProperty);
152 if (OC_STACK_OK != result)
154 cout << "Resource creation was unsuccessful\n";
160 OCResourceHandle getHandle()
162 return m_resourceHandle;
165 // Puts representation.
166 // Gets values from the representation and
167 // updates the internal state
168 void put(OCRepresentation& rep)
171 if (rep.getValue("state", m_state))
173 cout << "\t\t\t\t" << "state: " << m_state << endl;
177 cout << "\t\t\t\t" << "state not found in the representation" << endl;
180 if (rep.getValue("power", m_power))
182 cout << "\t\t\t\t" << "power: " << m_power << endl;
186 cout << "\t\t\t\t" << "power not found in the representation" << endl;
191 cout << e.what() << endl;
196 // Post representation.
197 // Post can create new resource or simply act like put.
198 // Gets values from the representation and
199 // updates the internal state
200 OCRepresentation post(OCRepresentation& rep)
202 static int first = 1;
204 // for the first time it tries to create a resource
209 if(OC_STACK_OK == createResource1())
211 OCRepresentation rep1;
212 rep1.setValue("createduri", std::string("/a/light1"));
218 // from second time onwards it just puts
224 // gets the updated representation.
225 // Updates the representation with latest internal state before
227 OCRepresentation get()
229 m_lightRep.setValue("state", m_state);
230 m_lightRep.setValue("power", m_power);
235 void addType(const std::string& type) const
237 OCStackResult result = OCPlatform::bindTypeToResource(m_resourceHandle, type);
238 if (OC_STACK_OK != result)
240 cout << "Binding TypeName to Resource was unsuccessful\n";
244 void addInterface(const std::string& interface) const
246 OCStackResult result = OCPlatform::bindInterfaceToResource(m_resourceHandle, interface);
247 if (OC_STACK_OK != result)
249 cout << "Binding TypeName to Resource was unsuccessful\n";
254 // This is just a sample implementation of entity handler.
255 // Entity handler can be implemented in several ways by the manufacturer
256 OCEntityHandlerResult entityHandler(std::shared_ptr<OCResourceRequest> request)
258 cout << "\tIn Server CPP entity handler:\n";
259 OCEntityHandlerResult ehResult = OC_EH_ERROR;
262 // Get the request type and request flag
263 std::string requestType = request->getRequestType();
264 int requestFlag = request->getRequestHandlerFlag();
266 if(requestFlag & RequestHandlerFlag::RequestFlag)
268 cout << "\t\trequestFlag : Request\n";
269 auto pResponse = std::make_shared<OC::OCResourceResponse>();
270 pResponse->setRequestHandle(request->getRequestHandle());
271 pResponse->setResourceHandle(request->getResourceHandle());
273 // Check for query params (if any)
274 QueryParamsMap queries = request->getQueryParameters();
276 if (!queries.empty())
278 std::cout << "\nQuery processing upto entityHandler" << std::endl;
280 for (auto it : queries)
282 std::cout << "Query key: " << it.first << " value : " << it.second
286 // If the request type is GET
287 if(requestType == "GET")
289 cout << "\t\t\trequestType : GET\n";
290 if(isSlowResponse) // Slow response case
292 static int startedThread = 0;
295 std::thread t(handleSlowResponse, (void *)this, request);
299 ehResult = OC_EH_SLOW;
301 else // normal response case.
303 pResponse->setErrorCode(200);
304 pResponse->setResponseResult(OC_EH_OK);
305 pResponse->setResourceRepresentation(get());
306 if(OC_STACK_OK == OCPlatform::sendResponse(pResponse))
312 else if(requestType == "PUT")
314 cout << "\t\t\trequestType : PUT\n";
315 OCRepresentation rep = request->getResourceRepresentation();
317 // Do related operations related to PUT request
318 // Update the lightResource
320 pResponse->setErrorCode(200);
321 pResponse->setResponseResult(OC_EH_OK);
322 pResponse->setResourceRepresentation(get());
323 if(OC_STACK_OK == OCPlatform::sendResponse(pResponse))
328 else if(requestType == "POST")
330 cout << "\t\t\trequestType : POST\n";
332 OCRepresentation rep = request->getResourceRepresentation();
334 // Do related operations related to POST request
335 OCRepresentation rep_post = post(rep);
336 pResponse->setResourceRepresentation(rep_post);
337 pResponse->setErrorCode(200);
338 if(rep_post.hasAttribute("createduri"))
340 pResponse->setResponseResult(OC_EH_RESOURCE_CREATED);
341 pResponse->setNewResourceUri(rep_post.getValue<std::string>("createduri"));
345 pResponse->setResponseResult(OC_EH_OK);
348 if(OC_STACK_OK == OCPlatform::sendResponse(pResponse))
353 else if(requestType == "DELETE")
355 cout << "Delete request received" << endl;
359 if(requestFlag & RequestHandlerFlag::ObserverFlag)
361 ObservationInfo observationInfo = request->getObservationInfo();
362 if(ObserveAction::ObserveRegister == observationInfo.action)
364 m_interestedObservers.push_back(observationInfo.obsId);
366 else if(ObserveAction::ObserveUnregister == observationInfo.action)
368 m_interestedObservers.erase(std::remove(
369 m_interestedObservers.begin(),
370 m_interestedObservers.end(),
371 observationInfo.obsId),
372 m_interestedObservers.end());
377 cout << "\t\trequestFlag : Observer\n";
379 static int startedThread = 0;
381 // Observation happens on a different thread in ChangeLightRepresentation function.
382 // If we have not created the thread already, we will create one here.
385 pthread_create (&threadId, NULL, ChangeLightRepresentation, (void *)this);
393 std::cout << "Request invalid" << std::endl;
401 // ChangeLightRepresentaion is an observation function,
402 // which notifies any changes to the resource to stack
403 // via notifyObservers
404 void * ChangeLightRepresentation (void *param)
406 LightResource* lightPtr = (LightResource*) param;
408 // This function continuously monitors for the changes
415 // If under observation if there are any changes to the light resource
416 // we call notifyObservors
418 // For demostration we are changing the power value and notifying.
419 lightPtr->m_power += 10;
421 cout << "\nPower updated to : " << lightPtr->m_power << endl;
422 cout << "Notifying observers with resource handle: " << lightPtr->getHandle() << endl;
424 OCStackResult result = OC_STACK_OK;
426 if(isListOfObservers)
428 std::shared_ptr<OCResourceResponse> resourceResponse =
429 {std::make_shared<OCResourceResponse>()};
431 resourceResponse->setErrorCode(200);
432 resourceResponse->setResourceRepresentation(lightPtr->get(), DEFAULT_INTERFACE);
434 result = OCPlatform::notifyListOfObservers( lightPtr->getHandle(),
435 lightPtr->m_interestedObservers,
440 result = OCPlatform::notifyAllObservers(lightPtr->getHandle());
443 if(OC_STACK_NO_OBSERVERS == result)
445 cout << "No More observers, stopping notifications" << endl;
454 void * handleSlowResponse (void *param, std::shared_ptr<OCResourceRequest> pRequest)
456 // This function handles slow response case
457 LightResource* lightPtr = (LightResource*) param;
458 // Induce a case for slow response by using sleep
459 std::cout << "SLOW response" << std::endl;
462 auto pResponse = std::make_shared<OC::OCResourceResponse>();
463 pResponse->setRequestHandle(pRequest->getRequestHandle());
464 pResponse->setResourceHandle(pRequest->getResourceHandle());
465 pResponse->setResourceRepresentation(lightPtr->get());
466 pResponse->setErrorCode(200);
467 pResponse->setResponseResult(OC_EH_OK);
469 // Set the slow response flag back to false
470 isSlowResponse = false;
471 OCPlatform::sendResponse(pResponse);
477 std::cout << std::endl;
478 std::cout << "Usage : simpleserver <value>\n";
479 std::cout << " Default - Non-secure resource and notify all observers\n";
480 std::cout << " 1 - Non-secure resource and notify list of observers\n\n";
481 std::cout << " 2 - Secure resource and notify all observers\n";
482 std::cout << " 3 - Secure resource and notify list of observers\n\n";
483 std::cout << " 4 - Non-secure resource, GET slow response, notify all observers\n";
486 static FILE* client_open(const char* /*path*/, const char *mode)
488 return fopen(SVR_DB_FILE_NAME, mode);
491 int main(int argc, char* argv[])
494 OCPersistentStorage ps {client_open, fread, fwrite, fclose, unlink };
498 isListOfObservers = false;
503 int value = atoi(argv[1]);
507 isListOfObservers = true;
511 isListOfObservers = false;
515 isListOfObservers = true;
519 isSlowResponse = true;
530 // Create PlatformConfig object
532 OC::ServiceType::InProc,
533 OC::ModeType::Server,
534 "0.0.0.0", // By setting to "0.0.0.0", it binds to all available interfaces
535 0, // Uses randomly available port
536 OC::QualityOfService::LowQos,
540 OCPlatform::Configure(cfg);
543 // Create the instance of the resource class
544 // (in this case instance of class 'LightResource').
545 LightResource myLight;
547 // Invoke createResource function of class light.
548 myLight.createResource();
549 std::cout << "Created resource." << std::endl;
551 myLight.addType(std::string("core.brightlight"));
552 myLight.addInterface(std::string(LINK_INTERFACE));
553 std::cout << "Added Interface and Type" << std::endl;
556 // A condition variable will free the mutex it is given, then do a non-
557 // intensive block until 'notify' is called on it. In this case, since we
558 // don't ever call cv.notify, this should be a non-processor intensive version
561 std::condition_variable cv;
562 std::unique_lock<std::mutex> lock(blocker);
563 std::cout <<"Waiting" << std::endl;
564 cv.wait(lock, []{return false;});
566 catch(OCException &e)
568 std::cout << "OCException in main : " << e.what() << endl;
571 // No explicit call to stop the platform.
572 // When OCPlatform::destructor is invoked, internally we do platform cleanup