Merge "Merge branch '1.1-rel'"
[platform/upstream/iotivity.git] / cloud / interface / src / main / java / org / iotivity / cloud / ciserver / resources / KeepAliveResource.java
1 /*
2  *******************************************************************
3  *
4  * Copyright 2016 Samsung Electronics All Rights Reserved.
5  *
6  *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
21  */
22 package org.iotivity.cloud.ciserver.resources;
23
24 import java.util.ArrayList;
25 import java.util.Collections;
26 import java.util.HashMap;
27 import java.util.Iterator;
28 import java.util.Map;
29 import java.util.Set;
30 import java.util.Timer;
31 import java.util.TimerTask;
32
33 import org.iotivity.cloud.base.Resource;
34 import org.iotivity.cloud.base.SessionManager;
35 import org.iotivity.cloud.base.protocols.coap.CoapRequest;
36 import org.iotivity.cloud.base.protocols.coap.CoapResponse;
37 import org.iotivity.cloud.base.protocols.coap.enums.CoapStatus;
38 import org.iotivity.cloud.ciserver.Constants;
39 import org.iotivity.cloud.util.Cbor;
40 import org.iotivity.cloud.util.Logger;
41
42 import io.netty.channel.ChannelHandlerContext;
43
44 /**
45  *
46  * This class provides a set of APIs to use KeepAlive Resource for ensuring the
47  * connection.
48  *
49  */
50 public class KeepAliveResource extends Resource {
51
52     private int[]                                intervals;
53     private HashMap<ChannelHandlerContext, Long> connectPool;
54     private Timer                                timer;
55     private Cbor<HashMap<String, Integer>>       cbor;
56     private SessionManager                       sessionManager = null;
57
58     public void setIntervals(int[] intervals) {
59         this.intervals = intervals;
60     }
61
62     public int[] getIntervals() {
63         return this.intervals;
64     }
65
66     public KeepAliveResource(SessionManager sessionManager, int[] intervals) {
67         setUri(Constants.KEEP_ALIVE_URI);
68         setIntervals(intervals);
69         this.sessionManager = sessionManager;
70         connectPool = new HashMap<ChannelHandlerContext, Long>();
71         timer = new Timer();
72         cbor = new Cbor<HashMap<String, Integer>>();
73     }
74
75     public void startSessionChecker() {
76         timer.schedule(new KeepAliveTask(), 30000, 60000);
77     }
78
79     public void stopSessionChecker() {
80         timer.cancel();
81     }
82
83     /**
84      * API for receiving message(message to keepalive resource)
85      *
86      * @param ctx
87      *            ChannelHandlerContext of request message
88      * @param request
89      *            CoAP request message
90      */
91     @Override
92     public void onRequestReceived(ChannelHandlerContext ctx,
93             CoapRequest request) {
94
95         CoapResponse response = null;
96
97         switch (request.getRequestMethod()) {
98             // First message to KeepAlive from resource
99             case GET:
100                 if (intervals != null) {
101                     response = makePingConfigMessage(request);
102                     connectPool.put(ctx, System.currentTimeMillis()
103                             + (intervals[0] * (long) 60000));
104                 }
105                 break;
106             // interval Message to KeepAlive After receiving GET Message
107             case PUT:
108                 HashMap<String, Integer> payloadData = null;
109                 payloadData = cbor.parsePayloadFromCbor(request.getPayload(),
110                         HashMap.class);
111
112                 Logger.d("Receive payloadData : " + payloadData);
113                 if (payloadData != null) {
114                     if (payloadData.containsKey("in")) {
115                         Logger.d("interval : " + payloadData.get("in"));
116
117                         connectPool.put(ctx, System.currentTimeMillis()
118                                 + (payloadData.get("in") * (long) 60000));
119                     }
120                 }
121                 response = makeResponse(request);
122                 break;
123
124             case POST:
125                 break;
126
127             case DELETE:
128                 break;
129         }
130
131         ctx.writeAndFlush(response);
132     }
133
134     /**
135      * API for making response to Resource
136      *
137      * @param request
138      *            ChannelHandlerContext of request message
139      */
140     private CoapResponse makeResponse(CoapRequest request) {
141         CoapResponse response = new CoapResponse(CoapStatus.VALID);
142         response.setToken(request.getToken());
143
144         return response;
145     }
146
147     /**
148      * API for making interval and first response to Resource
149      *
150      * @param request
151      *            ChannelHandlerContext of request message
152      */
153     private CoapResponse makePingConfigMessage(CoapRequest request) {
154         CoapResponse response = new CoapResponse(CoapStatus.CONTENT);
155         response.setToken(request.getToken());
156
157         HashMap<String, int[]> payloadData = new HashMap<String, int[]>();
158         payloadData.put("inarray", intervals);
159
160         byte[] cborData = cbor.encodingPayloadToCbor(payloadData);
161
162         response.setPayload(cborData);
163
164         Logger.d("Send payloadData : " + payloadData);
165
166         return response;
167     }
168
169     /**
170      * API for managing session
171      */
172     public class KeepAliveTask extends TimerTask {
173
174         @Override
175         public void run() {
176             Map<ChannelHandlerContext, Long> map = Collections
177                     .synchronizedMap(connectPool);
178             Set<ChannelHandlerContext> keySet = map.keySet();
179             ArrayList<ChannelHandlerContext> deleteList = new ArrayList<ChannelHandlerContext>();
180             Iterator<ChannelHandlerContext> iterator = null;
181             synchronized (map) {
182                 iterator = keySet.iterator();
183                 Long currentTime = System.currentTimeMillis();
184                 // check interval
185                 while (iterator.hasNext()) {
186                     ChannelHandlerContext key = iterator.next();
187                     if (map.containsKey(key)) {
188                         if (map.get(key) != null) {
189                             Long lifeTime = (Long) map.get(key);
190                             if (lifeTime != null) {
191                                 Logger.d("KeepAliveTask Operating : "
192                                         + key.channel().toString() + ", Time : "
193                                         + (lifeTime - currentTime));
194                                 if (lifeTime < currentTime) {
195                                     deleteList.add(key);
196                                 }
197                             }
198                         }
199                     }
200                 }
201
202             }
203             iterator = deleteList.iterator();
204             // remove session
205             while (iterator.hasNext()) {
206                 ChannelHandlerContext key = iterator.next();
207                 Logger.d("KeepAliveTask Remove");
208                 connectPool.remove(key);
209                 sessionManager.removeSessionByChannel(key);
210                 key.close();
211             }
212         }
213     }
214 }