2c862ed7c5224e5762bf23cb458aa4ecb929f1d7
[platform/upstream/iotivity.git] / service / simulator / src / server / simulator_resource_factory.cpp
1 /******************************************************************\r
2  *\r
3  * Copyright 2015 Samsung Electronics All Rights Reserved.\r
4  *\r
5  *\r
6  *\r
7  * Licensed under the Apache License, Version 2.0 (the "License");\r
8  * you may not use this file except in compliance with the License.\r
9  * You may obtain a copy of the License at\r
10  *\r
11  *      http://www.apache.org/licenses/LICENSE-2.0\r
12  *\r
13  * Unless required by applicable law or agreed to in writing, software\r
14  * distributed under the License is distributed on an "AS IS" BASIS,\r
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
16  * See the License for the specific language governing permissions and\r
17  * limitations under the License.\r
18  *\r
19  ******************************************************************/\r
20 \r
21 #include "simulator_resource_factory.h"\r
22 #include "simulator_single_resource_impl.h"\r
23 #include "simulator_collection_resource_impl.h"\r
24 #include "simulator_logger.h"\r
25 #include "logger.h"\r
26 \r
27 #define TAG "SIM_RESOURCE_FACTORY"\r
28 \r
29 SimulatorResourceFactory *SimulatorResourceFactory::getInstance()\r
30 {\r
31     static SimulatorResourceFactory s_instance;\r
32     return &s_instance;\r
33 }\r
34 \r
35 std::shared_ptr<SimulatorResource> SimulatorResourceFactory::createResource(\r
36     const std::string &configPath)\r
37 {\r
38     // Parse the RAML file\r
39     std::shared_ptr<RAML::RamlParser> ramlParser = std::make_shared<RAML::RamlParser>(configPath);\r
40     RAML::RamlPtr raml = ramlParser->getRamlPtr();\r
41 \r
42     // Get the first resource model from RAML\r
43     RAML::RamlResourcePtr ramlResource;\r
44     if (0 == raml->getResources().size()\r
45         || nullptr == (ramlResource = raml->getResources().begin()->second))\r
46     {\r
47         OC_LOG(ERROR, TAG, "Zero resources detected from RAML!");\r
48         return nullptr;\r
49     }\r
50 \r
51     return buildResource(ramlResource);\r
52 }\r
53 \r
54 std::vector<std::shared_ptr<SimulatorResource> > SimulatorResourceFactory::createResource(\r
55     const std::string &configPath, unsigned int count)\r
56 {\r
57     std::vector<std::shared_ptr<SimulatorResource>> resources;\r
58 \r
59     // Parse the RAML file\r
60     std::shared_ptr<RAML::RamlParser> ramlParser = std::make_shared<RAML::RamlParser>(configPath);\r
61     RAML::RamlPtr raml = ramlParser->getRamlPtr();\r
62 \r
63     // Get the first resource model from RAML\r
64     RAML::RamlResourcePtr ramlResource;\r
65     if (0 == raml->getResources().size()\r
66         || nullptr == (ramlResource = raml->getResources().begin()->second))\r
67     {\r
68         OC_LOG(ERROR, TAG, "Zero resources detected from RAML!");\r
69         return resources;\r
70     }\r
71 \r
72     while (count--)\r
73     {\r
74         std::shared_ptr<SimulatorResource> resource = buildResource(ramlResource);\r
75         if (!resource)\r
76         {\r
77             OC_LOG(ERROR, TAG, "Failed to create resource!");\r
78             return resources;\r
79         }\r
80 \r
81         resources.push_back(resource);\r
82     }\r
83 \r
84     return resources;\r
85 }\r
86 \r
87 std::shared_ptr<SimulatorSingleResource> SimulatorResourceFactory::createSingleResource(\r
88     const std::string &name, const std::string &uri, const std::string &resourceType)\r
89 {\r
90     SimulatorSingleResourceImpl *simpleResource = new SimulatorSingleResourceImpl();\r
91     simpleResource->setName(name);\r
92     simpleResource->setURI(uri);\r
93     simpleResource->setResourceType(resourceType);\r
94     return std::shared_ptr<SimulatorSingleResource>(simpleResource);\r
95 }\r
96 \r
97 std::shared_ptr<SimulatorCollectionResource> SimulatorResourceFactory::createCollectionResource(\r
98     const std::string &name, const std::string &uri, const std::string &resourceType)\r
99 {\r
100     SimulatorCollectionResourceImpl *collectionResource = new SimulatorCollectionResourceImpl();\r
101     collectionResource->setName(name);\r
102     collectionResource->setURI(uri);\r
103     collectionResource->setResourceType(resourceType);\r
104     return std::shared_ptr<SimulatorCollectionResource>(collectionResource);\r
105 }\r
106 \r
107 SimulatorResourceModel::Attribute SimulatorResourceFactory::buildAttribute(\r
108     std::shared_ptr<RAML::Properties> propertyElement)\r
109 {\r
110     std::string propName = propertyElement->getName();\r
111 \r
112     // Build representation attribute\r
113     SimulatorResourceModel::Attribute attribute(propName);\r
114     switch (propertyElement->getVariantType())\r
115     {\r
116         case RAML::VariantType::INT:\r
117             {\r
118                 attribute.setValue(propertyElement->getValue<int>());\r
119 \r
120                 // Convert suppoted values\r
121                 std::vector<int> allowedValues = propertyElement->getAllowedValuesInt();\r
122                 if (allowedValues.size() > 0)\r
123                 {\r
124                     SimulatorResourceModel::AttributeProperty attrProp(allowedValues);\r
125                     attribute.setProperty(attrProp);\r
126                 }\r
127             }\r
128             break;\r
129 \r
130         case RAML::VariantType::DOUBLE:\r
131             {\r
132                 attribute.setValue(propertyElement->getValue<double>());\r
133 \r
134                 // Convert suppoted values\r
135                 std::vector<double> allowedValues = propertyElement->getAllowedValuesDouble();\r
136                 if (allowedValues.size() > 0)\r
137                 {\r
138                     SimulatorResourceModel::AttributeProperty attrProp(allowedValues);\r
139                     attribute.setProperty(attrProp);\r
140                 }\r
141             }\r
142             break;\r
143 \r
144         case RAML::VariantType::BOOL:\r
145             {\r
146                 attribute.setValue(propertyElement->getValue<bool>());\r
147 \r
148                 std::vector<bool> allowedValues = {true, false};\r
149                 SimulatorResourceModel::AttributeProperty attrProp(allowedValues);\r
150                 attribute.setProperty(attrProp);\r
151             }\r
152             break;\r
153 \r
154         case RAML::VariantType::STRING:\r
155             {\r
156                 attribute.setValue(propertyElement->getValue<std::string>());\r
157 \r
158                 // Convert suppoted values\r
159                 std::vector<std::string> allowedValues = propertyElement->getAllowedValuesString();\r
160                 if (allowedValues.size() > 0)\r
161                 {\r
162                     SimulatorResourceModel::AttributeProperty attrProp(allowedValues);\r
163                     attribute.setProperty(attrProp);\r
164                 }\r
165             }\r
166             break;\r
167     }\r
168 \r
169     // Set the range property if its present\r
170     double min, max;\r
171     int multipleof;\r
172     propertyElement->getRange(min, max, multipleof);\r
173     if (min != INT_MIN && max != INT_MAX)\r
174     {\r
175         SimulatorResourceModel::AttributeProperty attrProp(min, max);\r
176         attribute.setProperty(attrProp);\r
177     }\r
178     return attribute;\r
179 }\r
180 \r
181 SimulatorResourceModel SimulatorResourceFactory::buildResourceModel(\r
182     std::shared_ptr<RAML::Items> item)\r
183 {\r
184     SimulatorResourceModel itemModel;\r
185     for ( auto &propElement : item->getProperties())\r
186     {\r
187         if (!propElement.second)\r
188             continue;\r
189 \r
190         std::string propName = propElement.second->getName();\r
191         if ("p" == propName || "n" == propName || "id" == propName)\r
192         {\r
193             continue;\r
194         }\r
195 \r
196         if ("array" == propElement.second->getType())\r
197         {\r
198             std::vector<SimulatorResourceModel> arrayResModel;\r
199             for ( auto &propertyItem : propElement.second->getItems())\r
200             {\r
201                 arrayResModel.push_back(buildResourceModel(propertyItem));\r
202             }\r
203             itemModel.add(propName, arrayResModel);\r
204         }\r
205         else\r
206         {\r
207             itemModel.add(buildAttribute(propElement.second));\r
208         }\r
209     }\r
210     return itemModel;\r
211 }\r
212 \r
213 RAML::RequestResponseBodyPtr SimulatorResourceFactory::getRAMLResponseBody(\r
214     std::shared_ptr<RAML::RamlResource> ramlResource, RAML::ActionType type, std::string responseCode)\r
215 {\r
216     // Get the resource representation schema from response body\r
217     RAML::ActionPtr action = ramlResource->getAction(type);\r
218     if (!action)\r
219     {\r
220         OC_LOG(ERROR, TAG, "Resource does not possess the request!");\r
221         return nullptr;\r
222     }\r
223 \r
224     RAML::ResponsePtr response = action->getResponse(responseCode);\r
225     if (!response)\r
226     {\r
227         OC_LOG(ERROR, TAG, "Resource does not provide valid GET response!");\r
228         return nullptr;\r
229     }\r
230 \r
231     RAML::RequestResponseBodyPtr responseBody = response->getResponseBody("application/json");\r
232     if (!responseBody)\r
233     {\r
234         OC_LOG(ERROR, TAG, "GET response is not of type \"application/json\" ");\r
235         return nullptr;\r
236     }\r
237 \r
238     return responseBody;\r
239 }\r
240 \r
241 SimulatorResourceModel SimulatorResourceFactory::buildModelFromResponseBody(\r
242     RAML::RequestResponseBodyPtr responseBody, std::string &resourceType,\r
243     std::vector<std::string> &interfaceType)\r
244 {\r
245     SimulatorResourceModel resModel;\r
246 \r
247     if (!responseBody)\r
248         return resModel;\r
249 \r
250     // Iterate throgh all resource property and extract information needed for simulating resource.\r
251     RAML::JsonSchemaPtr resourceProperties = responseBody->getSchema()->getProperties();\r
252 \r
253 \r
254     for ( auto &propertyElement : resourceProperties->getProperties())\r
255     {\r
256         if (!propertyElement.second)\r
257             continue;\r
258 \r
259         std::string propName = propertyElement.second->getName();\r
260 \r
261         // Resource type\r
262         if ("rt" == propName || "resourceType" == propName)\r
263         {\r
264             resourceType = propertyElement.second->getValueString();\r
265             continue;\r
266         }\r
267 \r
268         // Interface type\r
269         if ("if" == propName)\r
270         {\r
271             if ("string" == propertyElement.second->getType())\r
272             {\r
273                 interfaceType.push_back(propertyElement.second->getValueString());\r
274             }\r
275             else if ("array" == propertyElement.second->getType())\r
276             {\r
277                 for (auto &item : propertyElement.second->getItems())\r
278                 {\r
279                     if ("string" == item->getType())\r
280                     {\r
281                         interfaceType = item->getAllowedValuesString();\r
282                         break;\r
283                     }\r
284                 }\r
285             }\r
286             continue;\r
287         }\r
288 \r
289         // Other Standard properties which should not be part of resource model\r
290         if ("p" == propName || "n" == propName || "id" == propName)\r
291         {\r
292             continue;\r
293         }\r
294 \r
295         // Add the attribute to resource model\r
296         if ("array" == propertyElement.second->getType())\r
297         {\r
298             std::vector<SimulatorResourceModel> arrayResModel;\r
299             for ( auto &propertyItem : propertyElement.second->getItems())\r
300             {\r
301                 arrayResModel.push_back(buildResourceModel(propertyItem));\r
302             }\r
303             resModel.add(propName, arrayResModel);\r
304         }\r
305         else\r
306         {\r
307             resModel.add(buildAttribute(propertyElement.second));\r
308         }\r
309     }\r
310 \r
311     if ("array" == resourceProperties->getType())\r
312     {\r
313         std::vector<SimulatorResourceModel> arrayResModel;\r
314         for ( auto &propertyItem : resourceProperties->getItems())\r
315         {\r
316             arrayResModel.push_back(buildResourceModel(propertyItem));\r
317         }\r
318         resModel.add("links", arrayResModel);\r
319     }\r
320 \r
321     return resModel;\r
322 }\r
323 \r
324 std::shared_ptr<SimulatorResource> SimulatorResourceFactory::buildResource(\r
325     std::shared_ptr<RAML::RamlResource> ramlResource)\r
326 {\r
327     std::string name;\r
328     std::string uri;\r
329     std::string resourceType, rt;\r
330     std::vector<std::string> interfaceType, ifType;\r
331 \r
332     name = ramlResource->getDisplayName();\r
333     uri = ramlResource->getResourceUri();\r
334 \r
335     RAML::RequestResponseBodyPtr successResponseBody = getRAMLResponseBody(\r
336                 ramlResource, RAML::ActionType::GET, "200");\r
337     RAML::RequestResponseBodyPtr putErrorResponseBody = getRAMLResponseBody(\r
338                 ramlResource, RAML::ActionType::PUT, "403");\r
339     RAML::RequestResponseBodyPtr postErrorResponseBody = getRAMLResponseBody(\r
340                 ramlResource, RAML::ActionType::POST, "403");\r
341 \r
342     SimulatorResourceModel successResponseModel = buildModelFromResponseBody(\r
343                 successResponseBody, resourceType, interfaceType);\r
344     SimulatorResourceModel putErrorResponseModel = buildModelFromResponseBody(\r
345                 putErrorResponseBody, rt, ifType);\r
346     SimulatorResourceModel postErrorResponseModel = buildModelFromResponseBody(\r
347                 postErrorResponseBody, rt, ifType);\r
348 \r
349     // Create simple/collection resource\r
350     std::shared_ptr<SimulatorResource> simResource;\r
351     if (successResponseModel.containsAttribute("links"))\r
352     {\r
353         try\r
354         {\r
355             std::shared_ptr<SimulatorCollectionResourceImpl> collectionRes(\r
356                 new SimulatorCollectionResourceImpl());\r
357 \r
358             collectionRes->setName(name);\r
359             collectionRes->setResourceType(resourceType);\r
360             collectionRes->setInterface(interfaceType);\r
361             collectionRes->setURI(ResourceURIFactory::getInstance()->constructURI(uri));\r
362 \r
363             collectionRes->setResourceModel(successResponseModel);\r
364             simResource = std::dynamic_pointer_cast<SimulatorResource>(collectionRes);\r
365         }\r
366         catch (InvalidArgsException &e) {}\r
367     }\r
368     else\r
369     {\r
370         try\r
371         {\r
372             std::shared_ptr<SimulatorSingleResourceImpl> singleRes(\r
373                 new SimulatorSingleResourceImpl());\r
374 \r
375             singleRes->setName(name);\r
376             singleRes->setResourceType(resourceType);\r
377             singleRes->setInterface(interfaceType);\r
378             singleRes->setURI(ResourceURIFactory::getInstance()->constructURI(uri));\r
379 \r
380             singleRes->setResourceModel(successResponseModel);\r
381             singleRes->setPutErrorResponseModel(putErrorResponseModel);\r
382             singleRes->setPostErrorResponseModel(postErrorResponseModel);\r
383 \r
384             simResource = std::dynamic_pointer_cast<SimulatorResource>(singleRes);\r
385         }\r
386         catch (InvalidArgsException &e) {}\r
387     }\r
388 \r
389     return simResource;\r
390 }\r
391 \r
392 ResourceURIFactory *ResourceURIFactory::getInstance()\r
393 {\r
394     static ResourceURIFactory s_instance;\r
395     return &s_instance;\r
396 }\r
397 \r
398 ResourceURIFactory::ResourceURIFactory()\r
399     : m_id(0) {}\r
400 \r
401 std::string ResourceURIFactory::constructURI(const std::string &uri)\r
402 {\r
403     std::lock_guard<std::mutex> lock(m_lock);\r
404     if (isUnique(uri))\r
405     {\r
406         updateUri(uri);\r
407         return uri;\r
408     }\r
409     std::ostringstream os;\r
410     os << uri;\r
411     if (!uri.empty() && '/' != uri[uri.length() - 1])\r
412         os << '/';\r
413     os << m_id++;\r
414     updateUri(os.str());\r
415     return os.str();\r
416 }\r
417 \r
418 void ResourceURIFactory::updateUri(const std::string &uri)\r
419 {\r
420     m_uriList.insert(std::pair<std::string, bool>(uri, true));\r
421 }\r
422 \r
423 bool ResourceURIFactory::isUnique(const std::string &uri)\r
424 {\r
425     if (m_uriList.end() == m_uriList.find(uri))\r
426         return true;\r
427     else\r
428         return false;\r
429 }\r
430 \r