19bc538814105d5dc4ac7365e0f5ad7e0dd6e3ed
[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 "RamlParser.h"\r
25 #include "simulator_logger.h"\r
26 #include "logger.h"\r
27 \r
28 #define TAG "SIM_RESOURCE_FACTORY"\r
29 \r
30 SimulatorResourceFactory *SimulatorResourceFactory::getInstance()\r
31 {\r
32     static SimulatorResourceFactory s_instance;\r
33     return &s_instance;\r
34 }\r
35 \r
36 std::shared_ptr<SimulatorResource> SimulatorResourceFactory::createResource(\r
37     const std::string &configPath)\r
38 {\r
39     // Parse the RAML file\r
40     std::shared_ptr<RAML::RamlParser> ramlParser = std::make_shared<RAML::RamlParser>(configPath);\r
41     RAML::RamlPtr raml = ramlParser->getRamlPtr();\r
42 \r
43     // Get the first resource model from RAML\r
44     RAML::RamlResourcePtr ramlResource;\r
45     if (0 == raml->getResources().size()\r
46         || nullptr == (ramlResource = raml->getResources().begin()->second))\r
47     {\r
48         OC_LOG(ERROR, TAG, "Zero resources detected from RAML!");\r
49         return nullptr;\r
50     }\r
51 \r
52     return buildResource(ramlResource);\r
53 }\r
54 \r
55 std::vector<std::shared_ptr<SimulatorResource> > SimulatorResourceFactory::createResource(\r
56     const std::string &configPath, unsigned int count)\r
57 {\r
58     std::vector<std::shared_ptr<SimulatorResource>> resources;\r
59 \r
60     // Parse the RAML file\r
61     std::shared_ptr<RAML::RamlParser> ramlParser = std::make_shared<RAML::RamlParser>(configPath);\r
62     RAML::RamlPtr raml = ramlParser->getRamlPtr();\r
63 \r
64     // Get the first resource model from RAML\r
65     RAML::RamlResourcePtr ramlResource;\r
66     if (0 == raml->getResources().size()\r
67         || nullptr == (ramlResource = raml->getResources().begin()->second))\r
68     {\r
69         OC_LOG(ERROR, TAG, "Zero resources detected from RAML!");\r
70         return resources;\r
71     }\r
72 \r
73     while (count--)\r
74     {\r
75         std::shared_ptr<SimulatorResource> resource = buildResource(ramlResource);\r
76         if (!resource)\r
77         {\r
78             OC_LOG(ERROR, TAG, "Failed to create resource!");\r
79             return resources;\r
80         }\r
81 \r
82         resources.push_back(resource);\r
83     }\r
84 \r
85     return resources;\r
86 }\r
87 \r
88 std::shared_ptr<SimulatorSingleResource> SimulatorResourceFactory::createSingleResource(\r
89     const std::string &name, const std::string &uri, const std::string &resourceType)\r
90 {\r
91     SimulatorSingleResourceImpl *simpleResource = new SimulatorSingleResourceImpl();\r
92     simpleResource->setName(name);\r
93     simpleResource->setURI(uri);\r
94     simpleResource->setResourceType(resourceType);\r
95     return std::shared_ptr<SimulatorSingleResource>(simpleResource);\r
96 }\r
97 \r
98 std::shared_ptr<SimulatorCollectionResource> SimulatorResourceFactory::createCollectionResource(\r
99     const std::string &name, const std::string &uri, const std::string &resourceType)\r
100 {\r
101     SimulatorCollectionResourceImpl *collectionResource = new SimulatorCollectionResourceImpl();\r
102     collectionResource->setName(name);\r
103     collectionResource->setURI(uri);\r
104     collectionResource->setResourceType(resourceType);\r
105     return std::shared_ptr<SimulatorCollectionResource>(collectionResource);\r
106 }\r
107 \r
108 SimulatorResourceModel::Attribute SimulatorResourceFactory::buildAttribute(\r
109     std::shared_ptr<RAML::Properties> propertyElement)\r
110 {\r
111     std::string propName = propertyElement->getName();\r
112 \r
113     // Build representation attribute\r
114     SimulatorResourceModel::Attribute attribute(propName);\r
115     switch (propertyElement->getVariantType())\r
116     {\r
117         case RAML::VariantType::INT:\r
118             {\r
119                 attribute.setValue(propertyElement->getValue<int>());\r
120 \r
121                 // Convert suppoted values\r
122                 std::vector<int> allowedValues = propertyElement->getAllowedValuesInt();\r
123                 if (allowedValues.size() > 0)\r
124                 {\r
125                     SimulatorResourceModel::AttributeProperty attrProp(allowedValues);\r
126                     attribute.setProperty(attrProp);\r
127                 }\r
128             }\r
129             break;\r
130 \r
131         case RAML::VariantType::DOUBLE:\r
132             {\r
133                 attribute.setValue(propertyElement->getValue<double>());\r
134 \r
135                 // Convert suppoted values\r
136                 std::vector<double> allowedValues = propertyElement->getAllowedValuesDouble();\r
137                 if (allowedValues.size() > 0)\r
138                 {\r
139                     SimulatorResourceModel::AttributeProperty attrProp(allowedValues);\r
140                     attribute.setProperty(attrProp);\r
141                 }\r
142             }\r
143             break;\r
144 \r
145         case RAML::VariantType::BOOL:\r
146             {\r
147                 attribute.setValue(propertyElement->getValue<bool>());\r
148 \r
149                 std::vector<bool> allowedValues = {true, false};\r
150                 SimulatorResourceModel::AttributeProperty attrProp(allowedValues);\r
151                 attribute.setProperty(attrProp);\r
152             }\r
153             break;\r
154 \r
155         case RAML::VariantType::STRING:\r
156             {\r
157                 attribute.setValue(propertyElement->getValue<std::string>());\r
158 \r
159                 // Convert suppoted values\r
160                 std::vector<std::string> allowedValues = propertyElement->getAllowedValuesString();\r
161                 if (allowedValues.size() > 0)\r
162                 {\r
163                     SimulatorResourceModel::AttributeProperty attrProp(allowedValues);\r
164                     attribute.setProperty(attrProp);\r
165                 }\r
166             }\r
167             break;\r
168     }\r
169 \r
170     // Set the range property if its present\r
171     double min, max;\r
172     int multipleof;\r
173     propertyElement->getRange(min, max, multipleof);\r
174     if (min != INT_MIN && max != INT_MAX)\r
175     {\r
176         SimulatorResourceModel::AttributeProperty attrProp(min, max);\r
177         attribute.setProperty(attrProp);\r
178     }\r
179     return attribute;\r
180 }\r
181 \r
182 SimulatorResourceModel SimulatorResourceFactory::buildResourceModel(\r
183     std::shared_ptr<RAML::Items> item)\r
184 {\r
185     SimulatorResourceModel itemModel;\r
186     for ( auto &propElement : item->getProperties())\r
187     {\r
188         if (!propElement.second)\r
189             continue;\r
190 \r
191         std::string propName = propElement.second->getName();\r
192         if ("rt" == propName || "resourceType" == propName || "if" == propName ||\r
193             "p" == propName || "n" == propName || "id" == propName )\r
194         {\r
195             continue;\r
196         }\r
197 \r
198         if ("array" == propElement.second->getType())\r
199         {\r
200             std::vector<SimulatorResourceModel> arrayResModel;\r
201             for ( auto &propertyItem : propElement.second->getItems())\r
202             {\r
203                 arrayResModel.push_back(buildResourceModel(propertyItem));\r
204             }\r
205             itemModel.add(propName, arrayResModel);\r
206         }\r
207         else\r
208         {\r
209             itemModel.add(buildAttribute(propElement.second));\r
210         }\r
211     }\r
212     return itemModel;\r
213 }\r
214 \r
215 std::shared_ptr<SimulatorResource> SimulatorResourceFactory::buildResource(\r
216     std::shared_ptr<RAML::RamlResource> ramlResource)\r
217 {\r
218     std::string name;\r
219     std::string uri;\r
220     std::string resourceType;\r
221     std::vector<std::string> interfaceType;\r
222 \r
223     name = ramlResource->getDisplayName();\r
224     uri = ramlResource->getResourceUri();\r
225 \r
226     // Get the resource representation schema from GET response body\r
227     RAML::ActionPtr action = ramlResource->getAction(RAML::ActionType::GET);\r
228     if (!action)\r
229     {\r
230         OC_LOG(ERROR, TAG, "Resource does not possess the GET request!");\r
231         return nullptr;\r
232     }\r
233 \r
234     RAML::ResponsePtr getResponse = action->getResponse("200");\r
235     if (!getResponse)\r
236     {\r
237         OC_LOG(ERROR, TAG, "Resource does not provide valid GET response!");\r
238         return nullptr;\r
239     }\r
240 \r
241     RAML::RequestResponseBodyPtr responseBody = getResponse->getResponseBody("application/json");\r
242     if (!responseBody)\r
243     {\r
244         OC_LOG(ERROR, TAG, "GET response is not of type \"application/json\" ");\r
245         return nullptr;\r
246     }\r
247 \r
248     // Iterate throgh all resource property and extract information needed for simulating resource\r
249     RAML::JsonSchemaPtr resourceProperties = responseBody->getSchema()->getProperties();\r
250     SimulatorResourceModel resModel;\r
251     for ( auto &propertyElement : resourceProperties->getProperties())\r
252     {\r
253         if (!propertyElement.second)\r
254             continue;\r
255 \r
256         std::string propName = propertyElement.second->getName();\r
257 \r
258         // Resource type\r
259         if ("rt" == propName || "resourceType" == propName)\r
260         {\r
261             resourceType = propertyElement.second->getValueString();\r
262             continue;\r
263         }\r
264 \r
265         // Interface type\r
266         if ("if" == propName)\r
267         {\r
268             if ("string" == propertyElement.second->getType())\r
269             {\r
270                 interfaceType.push_back(propertyElement.second->getValueString());\r
271             }\r
272             else if ("array" == propertyElement.second->getType())\r
273             {\r
274                 for (auto &item : propertyElement.second->getItems())\r
275                 {\r
276                     if ("string" == item->getType())\r
277                     {\r
278                         interfaceType = item->getAllowedValuesString();\r
279                         break;\r
280                     }\r
281                 }\r
282             }\r
283             continue;\r
284         }\r
285 \r
286         // Other Standard properties which should not be part of resource model\r
287         if ("p" == propName || "n" == propName || "id" == propName)\r
288         {\r
289             continue;\r
290         }\r
291 \r
292         // Add the attribute to resource model\r
293         if ("array" == propertyElement.second->getType())\r
294         {\r
295             std::vector<SimulatorResourceModel> arrayResModel;\r
296             for ( auto &propertyItem : propertyElement.second->getItems())\r
297             {\r
298                 arrayResModel.push_back(buildResourceModel(propertyItem));\r
299             }\r
300             resModel.add(propName, arrayResModel);\r
301         }\r
302         else\r
303         {\r
304             resModel.add(buildAttribute(propertyElement.second));\r
305         }\r
306     }\r
307 \r
308     if ("array" == resourceProperties->getType())\r
309     {\r
310         std::vector<SimulatorResourceModel> arrayResModel;\r
311         for ( auto &propertyItem : resourceProperties->getItems())\r
312         {\r
313             arrayResModel.push_back(buildResourceModel(propertyItem));\r
314         }\r
315         resModel.add("links", arrayResModel);\r
316     }\r
317     // Create simple/collection resource\r
318     std::shared_ptr<SimulatorResource> simResource;\r
319     if (resModel.containsAttribute("links"))\r
320     {\r
321         try\r
322         {\r
323             std::shared_ptr<SimulatorCollectionResourceImpl> collectionRes(\r
324                 new SimulatorCollectionResourceImpl());\r
325 \r
326             collectionRes->setName(name);\r
327             collectionRes->setResourceType(resourceType);\r
328             collectionRes->setInterface(interfaceType);\r
329             if (ResourceURIFactory::getInstance()->isUnique(uri))\r
330                 collectionRes->setURI(uri);\r
331             else\r
332                 collectionRes->setURI(ResourceURIFactory::getInstance()->constructURI(uri));\r
333 \r
334             collectionRes->setResourceModel(resModel);\r
335             simResource = std::dynamic_pointer_cast<SimulatorResource>(collectionRes);\r
336         }\r
337         catch (InvalidArgsException &e) {}\r
338     }\r
339     else\r
340     {\r
341         try\r
342         {\r
343             std::shared_ptr<SimulatorSingleResourceImpl> singleRes(\r
344                 new SimulatorSingleResourceImpl());\r
345 \r
346             singleRes->setName(name);\r
347             singleRes->setResourceType(resourceType);\r
348             singleRes->setInterface(interfaceType);\r
349             if (ResourceURIFactory::getInstance()->isUnique(uri))\r
350                 singleRes->setURI(uri);\r
351             else\r
352                 singleRes->setURI(ResourceURIFactory::getInstance()->constructURI(uri));\r
353 \r
354             singleRes->setResourceModel(resModel);\r
355             simResource = std::dynamic_pointer_cast<SimulatorResource>(singleRes);\r
356         }\r
357         catch (InvalidArgsException &e) {}\r
358     }\r
359 \r
360     return simResource;\r
361 }\r
362 \r
363 ResourceURIFactory *ResourceURIFactory::getInstance()\r
364 {\r
365     static ResourceURIFactory s_instance;\r
366     return &s_instance;\r
367 }\r
368 \r
369 ResourceURIFactory::ResourceURIFactory()\r
370     : m_id(0) {}\r
371 \r
372 std::string ResourceURIFactory::constructURI(const std::string &uri)\r
373 {\r
374     std::ostringstream os;\r
375     os << uri;\r
376     if (!uri.empty() && '/' != uri[uri.length() - 1])\r
377         os << '/';\r
378     os << m_id++;\r
379     return os.str();\r
380 }\r
381 \r
382 bool ResourceURIFactory::isUnique(const std::string &uri)\r
383 {\r
384     if (m_uriList.end() == m_uriList.find(uri))\r
385         return true;\r
386     else\r
387         return false;\r
388 }\r
389 \r