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