e774d68d02ba7c72ded64478af984c84dafe883e
[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             if (_result != OC_STACK_OK || _rep.getAttributes().empty() || lastSequenceNum > _seq)
212             {
213                 return;
214             }
215             else
216             {
217                 lastSequenceNum = _seq;
218             }
219
220             if (state != CACHE_STATE::READY)
221             {
222                 state = CACHE_STATE::READY;
223                 isReady = true;
224             }
225
226             if (mode != CACHE_MODE::OBSERVE)
227             {
228                 mode = CACHE_MODE::OBSERVE;
229             }
230
231             networkTimer.cancel(networkTimeOutHandle);
232             networkTimeOutHandle = networkTimer.post(CACHE_DEFAULT_EXPIRED_MILLITIME, pTimerCB);
233
234             notifyObservers(_rep.getAttributes());
235         }
236
237         void DataCache::onGet(const HeaderOptions & /*_hos*/,
238                               const ResponseStatement &_rep, int _result)
239         {
240             if (_result != OC_STACK_OK || _rep.getAttributes().empty())
241             {
242                 return;
243             }
244
245             if (state != CACHE_STATE::READY)
246             {
247                 state = CACHE_STATE::READY;
248                 isReady = true;
249             }
250
251             if (mode != CACHE_MODE::OBSERVE)
252             {
253                 networkTimer.cancel(networkTimeOutHandle);
254                 networkTimeOutHandle = networkTimer.post(
255                                            CACHE_DEFAULT_EXPIRED_MILLITIME, pTimerCB);
256
257                 pollingHandle = pollingTimer.post(CACHE_DEFAULT_REPORT_MILLITIME, pPollingCB);
258             }
259
260             notifyObservers(_rep.getAttributes());
261         }
262
263         void DataCache::notifyObservers(const RCSResourceAttributes Att)
264         {
265             {
266                 std::lock_guard<std::mutex> lock(att_mutex);
267                 if (attributes == Att)
268                 {
269                     return;
270                 }
271                 attributes = Att;
272             }
273
274             std::lock_guard<std::mutex> lock(m_mutex);
275             for (auto &i : * subscriberList)
276             {
277                 if (i.second.first.rf == REPORT_FREQUENCY::UPTODATE)
278                 {
279                     i.second.second(this->sResource, Att);
280                 }
281             }
282         }
283
284         CACHE_STATE DataCache::getCacheState() const
285         {
286             return state;
287         }
288
289         void DataCache::onTimeOut(unsigned int /*timerID*/)
290         {
291             if (mode == CACHE_MODE::OBSERVE)
292             {
293                 sResource->cancelObserve();
294                 mode = CACHE_MODE::FREQUENCY;
295
296                 networkTimer.cancel(networkTimeOutHandle);
297                 networkTimeOutHandle = networkTimer.post(
298                                            CACHE_DEFAULT_EXPIRED_MILLITIME, pTimerCB);
299
300                 pollingHandle = pollingTimer.post(CACHE_DEFAULT_REPORT_MILLITIME, pPollingCB);
301                 return;
302             }
303
304             state = CACHE_STATE::LOST_SIGNAL;
305         }
306         void DataCache::onPollingOut(const unsigned int /*timerID*/)
307         {
308             if (sResource != nullptr)
309             {
310                 mode = CACHE_MODE::FREQUENCY;
311                 sResource->requestGet(pGetCB);
312             }
313             return;
314         }
315
316         CacheID DataCache::generateCacheID()
317         {
318             CacheID retID = 0;
319             while (1)
320             {
321                 if (findSubscriber(retID).first == 0 && retID != 0)
322                 {
323                     break;
324                 }
325
326                 retID = OCGetRandom();
327             }
328             return retID;
329         }
330
331         void DataCache::requestGet()
332         {
333             state = CACHE_STATE::UPDATING;
334             if (sResource != nullptr)
335             {
336                 sResource->requestGet(pGetCB);
337             }
338         }
339
340         bool DataCache::isEmptySubscriber() const
341         {
342             std::lock_guard<std::mutex> lock(m_mutex);
343             return (subscriberList != nullptr) ? subscriberList->empty() : true;
344         }
345     } // namespace Service
346 } // namespace OIC