23ffd309e728f5fd8b0a6504383cd1a94ca6dff2
[platform/upstream/iotivity.git] / service / resource-encapsulation / src / resourceCache / src / DataCache.cpp
1 //******************************************************************
2 //
3 // Copyright 2015 Samsung Electronics All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
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
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
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.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 #include <memory>
22 #include <cstdlib>
23 #include <functional>
24 #include <map>
25 #include <utility>
26 #include <ctime>
27
28 #include "DataCache.h"
29
30 #include "ResponseStatement.h"
31 #include "RCSResourceAttributes.h"
32 #include "ExpiryTimer.h"
33
34 #include "ocrandom.h"
35
36 namespace OIC
37 {
38     namespace Service
39     {
40
41         namespace
42         {
43             void verifyObserveCB(
44                 const HeaderOptions &_hos, const ResponseStatement &_rep,
45                 int _result, unsigned int _seq, std::weak_ptr<DataCache> rpPtr)
46             {
47                 std::shared_ptr<DataCache> ptr = rpPtr.lock();
48                 if (ptr)
49                 {
50                     ptr->onObserve(_hos, _rep, _result, _seq);
51                 }
52             }
53
54             ObserveCB verifiedObserveCB(std::weak_ptr<DataCache> rpPtr)
55             {
56                 return std::bind(verifyObserveCB,
57                                  std::placeholders::_1, std::placeholders::_2,
58                                  std::placeholders::_3, std::placeholders::_4, rpPtr);
59             }
60
61             void verifyGetCB(
62                 const HeaderOptions &_hos, const ResponseStatement &_rep,
63                 int _result, std::weak_ptr<DataCache> rpPtr)
64             {
65                 std::shared_ptr<DataCache> Ptr = rpPtr.lock();
66                 if (Ptr)
67                 {
68                     Ptr->onGet(_hos, _rep, _result);
69                 }
70             }
71
72             GetCB verifiedGetCB(std::weak_ptr<DataCache> rpPtr)
73             {
74                 return std::bind(verifyGetCB,
75                                  std::placeholders::_1, std::placeholders::_2,
76                                  std::placeholders::_3, rpPtr);
77             }
78         }
79
80         DataCache::DataCache()
81         {
82             subscriberList = std::unique_ptr<SubscriberInfo>(new SubscriberInfo());
83
84             sResource = nullptr;
85
86             state = CACHE_STATE::READY_YET;
87             mode = CACHE_MODE::FREQUENCY;
88
89             networkTimeOutHandle = 0;
90             pollingHandle = 0;
91             lastSequenceNum = 0;
92             isReady = false;
93         }
94
95         DataCache::~DataCache()
96         {
97             state = CACHE_STATE::DESTROYED;
98
99             if (subscriberList != nullptr)
100             {
101                 subscriberList->clear();
102                 subscriberList.release();
103             }
104
105             if (sResource->isObservable())
106             {
107                 try
108                 {
109                     sResource->cancelObserve();
110                 }
111                 catch (...)
112                 {
113                     // ignore the exception because data cache was released.
114                 }
115             }
116         }
117
118         void DataCache::initializeDataCache(PrimitiveResourcePtr pResource)
119         {
120             sResource = pResource;
121             pObserveCB = verifiedObserveCB(std::weak_ptr<DataCache>(shared_from_this()));
122             pGetCB = verifiedGetCB(std::weak_ptr<DataCache>(shared_from_this()));
123             pTimerCB = (TimerCB)(std::bind(&DataCache::onTimeOut, this, std::placeholders::_1));
124             pPollingCB = (TimerCB)(std::bind(&DataCache::onPollingOut, this, std::placeholders::_1));
125
126             sResource->requestGet(pGetCB);
127             if (sResource->isObservable())
128             {
129                 sResource->requestObserve(pObserveCB);
130             }
131             networkTimeOutHandle = networkTimer.post(CACHE_DEFAULT_EXPIRED_MILLITIME, pTimerCB);
132         }
133
134         CacheID DataCache::addSubscriber(CacheCB func, REPORT_FREQUENCY rf, long repeatTime)
135         {
136             Report_Info newItem;
137             newItem.rf = rf;
138             newItem.repeatTime = repeatTime;
139             newItem.timerID = 0;
140
141             newItem.reportID = generateCacheID();
142
143             std::lock_guard<std::mutex> lock(m_mutex);
144             if (subscriberList != nullptr)
145             {
146                 subscriberList->insert(
147                     std::make_pair(newItem.reportID, std::make_pair(newItem, func)));
148             }
149
150             return newItem.reportID;
151         }
152
153         CacheID DataCache::deleteSubscriber(CacheID id)
154         {
155             CacheID ret = 0;
156
157             SubscriberInfoPair pair = findSubscriber(id);
158
159             std::lock_guard<std::mutex> lock(m_mutex);
160             if (pair.first != 0)
161             {
162                 ret = pair.first;
163                 subscriberList->erase(pair.first);
164             }
165
166             return ret;
167         }
168
169         SubscriberInfoPair DataCache::findSubscriber(CacheID id)
170         {
171             SubscriberInfoPair ret;
172
173             std::lock_guard<std::mutex> lock(m_mutex);
174             for (auto &i : *subscriberList)
175             {
176                 if (i.first == id)
177                 {
178                     ret = std::make_pair(i.first, std::make_pair((Report_Info)i.second.first,
179                                          (CacheCB)i.second.second));
180                     break;
181                 }
182             }
183
184             return ret;
185         }
186
187         const PrimitiveResourcePtr DataCache::getPrimitiveResource() const
188         {
189             return sResource;
190         }
191
192         const RCSResourceAttributes DataCache::getCachedData() const
193         {
194             std::lock_guard<std::mutex> lock(att_mutex);
195             if (state != CACHE_STATE::READY)
196             {
197                 return RCSResourceAttributes();
198             }
199             return attributes;
200         }
201
202         bool DataCache::isCachedData() const
203         {
204             return isReady;
205         }
206
207         void DataCache::onObserve(const HeaderOptions & /*_hos*/,
208                                   const ResponseStatement &_rep, int _result, unsigned int _seq)
209         {
210
211             lastSequenceNum = _seq;
212
213             if (state != CACHE_STATE::READY)
214             {
215                 state = CACHE_STATE::READY;
216                 isReady = true;
217             }
218
219             if (mode != CACHE_MODE::OBSERVE)
220             {
221                 mode = CACHE_MODE::OBSERVE;
222             }
223
224             networkTimer.cancel(networkTimeOutHandle);
225             networkTimeOutHandle = networkTimer.post(CACHE_DEFAULT_EXPIRED_MILLITIME, pTimerCB);
226
227             notifyObservers(_rep.getAttributes(), _result);
228         }
229
230         void DataCache::onGet(const HeaderOptions & /*_hos*/,
231                               const ResponseStatement &_rep, int _result)
232         {
233             if (_result != OC_STACK_OK || _rep.getAttributes().empty())
234             {
235                 return;
236             }
237
238             if (state != CACHE_STATE::READY)
239             {
240                 state = CACHE_STATE::READY;
241                 isReady = true;
242             }
243
244             if (mode != CACHE_MODE::OBSERVE)
245             {
246                 networkTimer.cancel(networkTimeOutHandle);
247                 networkTimeOutHandle = networkTimer.post(
248                                            CACHE_DEFAULT_EXPIRED_MILLITIME, pTimerCB);
249
250                 pollingHandle = pollingTimer.post(CACHE_DEFAULT_REPORT_MILLITIME, pPollingCB);
251             }
252
253             notifyObservers(_rep.getAttributes(), _result);
254         }
255
256         void DataCache::notifyObservers(const RCSResourceAttributes Att, int eCode)
257         {
258             {
259                 std::lock_guard<std::mutex> lock(att_mutex);
260                 if (attributes == Att)
261                 {
262                     return;
263                 }
264                 attributes = Att;
265             }
266
267             std::lock_guard<std::mutex> lock(m_mutex);
268             for (auto &i : * subscriberList)
269             {
270                 if (i.second.first.rf == REPORT_FREQUENCY::UPTODATE)
271                 {
272                     i.second.second(this->sResource, Att, eCode);
273                 }
274             }
275         }
276
277         CACHE_STATE DataCache::getCacheState() const
278         {
279             return state;
280         }
281
282         void DataCache::onTimeOut(unsigned int /*timerID*/)
283         {
284             if (mode == CACHE_MODE::OBSERVE)
285             {
286                 sResource->cancelObserve();
287                 mode = CACHE_MODE::FREQUENCY;
288
289                 networkTimer.cancel(networkTimeOutHandle);
290                 networkTimeOutHandle = networkTimer.post(
291                                            CACHE_DEFAULT_EXPIRED_MILLITIME, pTimerCB);
292
293                 pollingHandle = pollingTimer.post(CACHE_DEFAULT_REPORT_MILLITIME, pPollingCB);
294                 return;
295             }
296
297             state = CACHE_STATE::LOST_SIGNAL;
298         }
299         void DataCache::onPollingOut(const unsigned int /*timerID*/)
300         {
301             if (sResource != nullptr)
302             {
303                 mode = CACHE_MODE::FREQUENCY;
304                 sResource->requestGet(pGetCB);
305             }
306             return;
307         }
308
309         CacheID DataCache::generateCacheID()
310         {
311             CacheID retID = 0;
312             while (1)
313             {
314                 if (findSubscriber(retID).first == 0 && retID != 0)
315                 {
316                     break;
317                 }
318
319                 retID = OCGetRandom();
320             }
321             return retID;
322         }
323
324         void DataCache::requestGet()
325         {
326             state = CACHE_STATE::UPDATING;
327             if (sResource != nullptr)
328             {
329                 sResource->requestGet(pGetCB);
330             }
331         }
332
333         bool DataCache::isEmptySubscriber() const
334         {
335             std::lock_guard<std::mutex> lock(m_mutex);
336             return (subscriberList != nullptr) ? subscriberList->empty() : true;
337         }
338     } // namespace Service
339 } // namespace OIC