Merge branch 'upstream' into tizen
[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 #include "request_model_builder.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     if (!ramlParser)\r
42     {\r
43         OIC_LOG(ERROR, TAG, "RAML parser returned NULL!");\r
44         return nullptr;\r
45     }\r
46 \r
47     RAML::RamlPtr raml = ramlParser->getRamlPtr();\r
48     if (!raml)\r
49     {\r
50         OIC_LOG(ERROR, TAG, "RAML pointer is NULL!");\r
51         return nullptr;\r
52     }\r
53 \r
54     // Get the first resource model from RAML\r
55     RAML::RamlResourcePtr ramlResource;\r
56     if (0 == raml->getResources().size()\r
57         || nullptr == (ramlResource = raml->getResources().begin()->second))\r
58     {\r
59         OIC_LOG(ERROR, TAG, "Zero resources detected from RAML!");\r
60         return nullptr;\r
61     }\r
62 \r
63     return buildResource(ramlResource);\r
64 }\r
65 \r
66 std::vector<std::shared_ptr<SimulatorResource> > SimulatorResourceFactory::createResource(\r
67     const std::string &configPath, unsigned int count)\r
68 {\r
69     std::vector<std::shared_ptr<SimulatorResource>> resources;\r
70 \r
71     // Parse the RAML file\r
72     std::shared_ptr<RAML::RamlParser> ramlParser = std::make_shared<RAML::RamlParser>(configPath);\r
73     if (!ramlParser)\r
74     {\r
75         OIC_LOG(ERROR, TAG, "RAML parser returned NULL!");\r
76         return resources;\r
77     }\r
78 \r
79     RAML::RamlPtr raml = ramlParser->getRamlPtr();\r
80     if (!raml)\r
81     {\r
82         OIC_LOG(ERROR, TAG, "RAML pointer is NULL!");\r
83         return resources;\r
84     }\r
85 \r
86     // Get the first resource model from RAML\r
87     RAML::RamlResourcePtr ramlResource;\r
88     if (0 == raml->getResources().size()\r
89         || nullptr == (ramlResource = raml->getResources().begin()->second))\r
90     {\r
91         OIC_LOG(ERROR, TAG, "Zero resources detected from RAML!");\r
92         return resources;\r
93     }\r
94 \r
95     while (count--)\r
96     {\r
97         std::shared_ptr<SimulatorResource> resource = buildResource(ramlResource);\r
98         if (!resource)\r
99         {\r
100             OIC_LOG(ERROR, TAG, "Failed to create resource!");\r
101             return resources;\r
102         }\r
103 \r
104         resources.push_back(resource);\r
105     }\r
106 \r
107     return resources;\r
108 }\r
109 \r
110 std::shared_ptr<SimulatorSingleResource> SimulatorResourceFactory::createSingleResource(\r
111     const std::string &name, const std::string &uri, const std::string &resourceType)\r
112 {\r
113     SimulatorSingleResourceImpl *simpleResource = new SimulatorSingleResourceImpl();\r
114     simpleResource->setName(name);\r
115     simpleResource->setURI(uri);\r
116     simpleResource->setResourceType(resourceType);\r
117     return std::shared_ptr<SimulatorSingleResource>(simpleResource);\r
118 }\r
119 \r
120 std::shared_ptr<SimulatorCollectionResource> SimulatorResourceFactory::createCollectionResource(\r
121     const std::string &name, const std::string &uri, const std::string &resourceType)\r
122 {\r
123     SimulatorCollectionResourceImpl *collectionResource = new SimulatorCollectionResourceImpl();\r
124     collectionResource->setName(name);\r
125     collectionResource->setURI(uri);\r
126     collectionResource->setResourceType(resourceType);\r
127     return std::shared_ptr<SimulatorCollectionResource>(collectionResource);\r
128 }\r
129 \r
130 std::shared_ptr<SimulatorResource> SimulatorResourceFactory::buildResource(\r
131     const std::shared_ptr<RAML::RamlResource> &ramlResource)\r
132 {\r
133     // Build resource request and respone model schema\r
134     RequestModelBuilder requestModelBuilder;\r
135     std::unordered_map<std::string, RequestModelSP> requestModels =\r
136         requestModelBuilder.build(ramlResource);\r
137 \r
138     // Build SimulatorResourceModel from "GET" response schema\r
139     if (requestModels.end() == requestModels.find("GET"))\r
140     {\r
141         OIC_LOG(ERROR, TAG, "Resource's RAML does not have GET request model!");\r
142         return nullptr;\r
143     }\r
144 \r
145     RequestModelSP getRequestModel = requestModels["GET"];\r
146     ResponseModelSP getResponseModel = getRequestModel->getResponseModel(200);\r
147     if (!getResponseModel)\r
148     {\r
149         OIC_LOG(ERROR, TAG, "Resource's RAML does not have response for GET request!");\r
150         return nullptr;\r
151     }\r
152 \r
153     std::shared_ptr<SimulatorResourceModelSchema> responseSchema =\r
154         getResponseModel->getSchema();\r
155     if (!responseSchema)\r
156     {\r
157         OIC_LOG(ERROR, TAG, "Failed to get schema from response model!");\r
158         return nullptr;\r
159     }\r
160 \r
161     SimulatorResourceModel resourceModel = responseSchema->buildResourceModel();\r
162 \r
163     // Remove the common properties from  resource Model\r
164     std::string resourceURI = ramlResource->getResourceUri();\r
165     std::string resourceName = ramlResource->getDisplayName();\r
166     std::string resourceType;\r
167 \r
168     // Extracting resource type.\r
169     if (resourceModel.contains("rt"))\r
170     {\r
171         resourceType = resourceModel.get<std::string>("rt");\r
172         resourceModel.remove("rt");\r
173     }\r
174     else if (resourceModel.contains("resourceType"))\r
175     {\r
176         resourceType = resourceModel.get<std::string>("resourceType");\r
177         resourceModel.remove("resourceType");\r
178     }\r
179 \r
180     // Construct resource type from uri\r
181     if(resourceType.empty())\r
182     {\r
183         std::ostringstream rtString;\r
184         rtString << "oic.r.";\r
185 \r
186         size_t pos = resourceURI.rfind("/");\r
187         if (pos == std::string::npos)\r
188             pos = -1;\r
189 \r
190         std::string rtName = resourceURI.substr(pos+1);\r
191         std::transform(rtName.begin(), rtName.end(), rtName.begin(), ::tolower);\r
192         rtString << rtName;\r
193         resourceType = rtString.str();\r
194     }\r
195 \r
196     // Extracting interface type.\r
197     std::vector<std::string> interfaceTypes;\r
198     if (resourceModel.contains("if"))\r
199     {\r
200         SimulatorResourceModel::TypeInfo typeInfo = resourceModel.getType("if");\r
201         if(AttributeValueType::STRING == typeInfo.type())\r
202         {\r
203             interfaceTypes.push_back(resourceModel.get<std::string>("if"));\r
204         }\r
205         else if(AttributeValueType::VECTOR == typeInfo.type()\r
206             && AttributeValueType::STRING == typeInfo.baseType()\r
207             && typeInfo.depth() == 1)\r
208         {\r
209             interfaceTypes = resourceModel.get<std::vector<std::string>>("if");\r
210             if (interfaceTypes.size() > 1)\r
211                 interfaceTypes.erase(interfaceTypes.begin()+1, interfaceTypes.end());\r
212         }\r
213 \r
214         resourceModel.remove("if");\r
215     }\r
216 \r
217     for (auto &requestModel : requestModels)\r
218     {\r
219         if (requestModel.second)\r
220         {\r
221             addInterfaceFromQueryParameter((requestModel.second)->getQueryParams("if"),\r
222                 interfaceTypes);\r
223         }\r
224     }\r
225 \r
226     // Remove properties which are not part of resource representation\r
227     resourceModel.remove("p");\r
228     resourceModel.remove("n");\r
229     resourceModel.remove("id");\r
230 \r
231     // Create simple/collection resource\r
232     std::shared_ptr<SimulatorResource> simResource;\r
233     if (resourceModel.contains("links"))\r
234     {\r
235         std::shared_ptr<SimulatorCollectionResourceImpl> collectionRes(\r
236             new SimulatorCollectionResourceImpl());\r
237 \r
238         collectionRes->setName(resourceName);\r
239         collectionRes->setResourceType(resourceType);\r
240         if (interfaceTypes.size() > 0)\r
241             collectionRes->setInterface(interfaceTypes);\r
242         collectionRes->setURI(ResourceURIFactory::getInstance()->makeUniqueURI(resourceURI));\r
243 \r
244         // Set the resource model and its schema to simulated resource\r
245         collectionRes->setResourceModel(resourceModel);\r
246         collectionRes->setResourceModelSchema(responseSchema);\r
247         collectionRes->setRequestModel(requestModels);\r
248 \r
249         simResource = collectionRes;\r
250     }\r
251     else\r
252     {\r
253         std::shared_ptr<SimulatorSingleResourceImpl> singleRes(\r
254             new SimulatorSingleResourceImpl());\r
255 \r
256         singleRes->setName(resourceName);\r
257         singleRes->setResourceType(resourceType);\r
258         if (interfaceTypes.size() > 0)\r
259             singleRes->setInterface(interfaceTypes);\r
260         singleRes->setURI(ResourceURIFactory::getInstance()->makeUniqueURI(resourceURI));\r
261 \r
262         // Set the resource model and its schema to simulated resource\r
263         singleRes->setResourceModel(resourceModel);\r
264         singleRes->setResourceModelSchema(responseSchema);\r
265         singleRes->setRequestModel(requestModels);\r
266 \r
267         simResource = singleRes;\r
268     }\r
269 \r
270     return simResource;\r
271 }\r
272 \r
273 void SimulatorResourceFactory::addInterfaceFromQueryParameter(\r
274     std::vector<std::string> queryParamValue, std::vector<std::string> &interfaceTypes)\r
275 {\r
276     for (auto &interfaceType : queryParamValue)\r
277     {\r
278         if (interfaceTypes.end() ==\r
279             std::find(interfaceTypes.begin(), interfaceTypes.end(), interfaceType))\r
280         {\r
281             interfaceTypes.push_back(interfaceType);\r
282         }\r
283     }\r
284 }\r
285 \r
286 ResourceURIFactory *ResourceURIFactory::getInstance()\r
287 {\r
288     static ResourceURIFactory s_instance;\r
289     return &s_instance;\r
290 }\r
291 \r
292 ResourceURIFactory::ResourceURIFactory()\r
293     : m_id(0) {}\r
294 \r
295 std::string ResourceURIFactory::makeUniqueURI(const std::string &uri)\r
296 {\r
297     std::lock_guard<std::mutex> lock(m_lock);\r
298     if (isUnique(uri))\r
299     {\r
300         updateUri(uri);\r
301         return uri;\r
302     }\r
303     std::ostringstream os;\r
304     os << uri;\r
305     if (!uri.empty() && '/' != uri[uri.length() - 1])\r
306         os << '/';\r
307     os << m_id++;\r
308     updateUri(os.str());\r
309     return os.str();\r
310 }\r
311 \r
312 void ResourceURIFactory::updateUri(const std::string &uri)\r
313 {\r
314     m_uriList.insert(std::pair<std::string, bool>(uri, true));\r
315 }\r
316 \r
317 bool ResourceURIFactory::isUnique(const std::string &uri)\r
318 {\r
319     if (m_uriList.end() == m_uriList.find(uri))\r
320         return true;\r
321     else\r
322         return false;\r
323 }\r
324 \r