Implement reconnection and ping-pong between cloud services. Make
[iotivity.git] / cloud / interface / src / main / java / org / iotivity / cloud / ciserver / resources / RouteResource.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.Arrays;
26 import java.util.HashMap;
27 import java.util.List;
28
29 import org.iotivity.cloud.base.OICConstants;
30 import org.iotivity.cloud.base.connector.ConnectorPool;
31 import org.iotivity.cloud.base.device.CoapDevice;
32 import org.iotivity.cloud.base.device.Device;
33 import org.iotivity.cloud.base.device.IRequestChannel;
34 import org.iotivity.cloud.base.device.IResponseEventHandler;
35 import org.iotivity.cloud.base.exception.ServerException;
36 import org.iotivity.cloud.base.exception.ServerException.InternalServerErrorException;
37 import org.iotivity.cloud.base.protocols.IRequest;
38 import org.iotivity.cloud.base.protocols.IResponse;
39 import org.iotivity.cloud.base.protocols.MessageBuilder;
40 import org.iotivity.cloud.base.protocols.coap.CoapResponse;
41 import org.iotivity.cloud.base.protocols.enums.ContentFormat;
42 import org.iotivity.cloud.base.protocols.enums.RequestMethod;
43 import org.iotivity.cloud.base.protocols.enums.ResponseStatus;
44 import org.iotivity.cloud.base.resource.Resource;
45 import org.iotivity.cloud.ciserver.Constants;
46 import org.iotivity.cloud.ciserver.DeviceServerSystem.CoapDevicePool;
47 import org.iotivity.cloud.util.Cbor;
48
49 /**
50  *
51  * This class provides a set of APIs to send requests about message to another
52  * device
53  *
54  */
55 public class RouteResource extends Resource {
56
57     private CoapDevicePool                mDevicePool = null;
58     private Cbor<HashMap<String, Object>> mCbor       = new Cbor<>();
59
60     public RouteResource(CoapDevicePool devicePool) {
61         super(Arrays.asList(Constants.PREFIX_OIC, Constants.REQ_DEVICE_ROUTE));
62         mDevicePool = devicePool;
63     }
64
65     private IRequestChannel getTargetDeviceChannel(IRequest request)
66             throws ServerException {
67
68         CoapDevice targetDevice = (CoapDevice) mDevicePool
69                 .queryDevice(getDeviceId(request));
70
71         if (targetDevice == null) {
72             return null;
73         }
74
75         // Do request and receive response
76         return targetDevice.getRequestChannel();
77     }
78
79     private String extractTargetUriPath(IRequest request) {
80         List<String> uriPathSegment = request.getUriPathSegments();
81
82         // Remove prefix path
83         if (uriPathSegment != null) {
84             for (String path : getUriPathSegments()) {
85                 uriPathSegment.remove(path);
86             }
87             uriPathSegment.remove(0);
88
89             StringBuilder uriPath = new StringBuilder();
90             for (String path : uriPathSegment) {
91                 uriPath.append("/" + path);
92             }
93
94             return uriPath.toString();
95         }
96         throw new InternalServerErrorException(
97                 "Can not extract TargetUriPath from uriPath!");
98     }
99
100     private IResponse convertReponseUri(IResponse response, String di) {
101
102         String convertedUri = new String();
103
104         CoapResponse coapResponse = (CoapResponse) response;
105
106         StringBuilder uriPath = new StringBuilder();
107         for (String path : getUriPathSegments()) {
108             uriPath.append("/" + path);
109         }
110
111         String resUriPath = coapResponse.getUriPath();
112
113         if (resUriPath != null && !resUriPath.isEmpty()) {
114             convertedUri = uriPath.toString() + "/" + di
115                     + coapResponse.getUriPath();
116         }
117
118         return MessageBuilder.modifyResponse(response, convertedUri, null,
119                 null);
120     }
121
122     private String getDeviceId(IRequest request) {
123         List<String> uriPathSegment = request.getUriPathSegments();
124         if (uriPathSegment == null)
125             throw new InternalServerErrorException(
126                     "Can not find deviceId from uriPath!");
127
128         return uriPathSegment.get(getUriPathSegments().size());
129     }
130
131     /**
132      *
133      * This class provides a set of APIs to handling message contains link
134      * interface.
135      *
136      */
137     class LinkInterfaceHandler implements IResponseEventHandler {
138         private Cbor<List<HashMap<String, Object>>> mCbor      = new Cbor<>();
139         private String                              mTargetDI  = null;
140         private Device                              mSrcDevice = null;
141         private IRequest                            mRequest   = null;
142
143         public LinkInterfaceHandler(String targetDI, Device srcDevice,
144                 IRequest request) {
145             mTargetDI = targetDI;
146             mSrcDevice = srcDevice;
147             mRequest = request;
148         }
149
150         private void convertHref(List<HashMap<String, Object>> linkPayload) {
151
152             StringBuilder uriPath = new StringBuilder();
153             for (String path : getUriPathSegments()) {
154                 uriPath.append("/" + path);
155             }
156
157             for (HashMap<String, Object> link : linkPayload) {
158                 link.put("href", uriPath.toString() + "/" + mTargetDI
159                         + link.get("href"));
160             }
161         }
162
163         @Override
164         public void onResponseReceived(IResponse response) {
165             List<HashMap<String, Object>> linkPayload = null;
166             if (response.getStatus().equals(ResponseStatus.CONTENT)) {
167                 linkPayload = mCbor.parsePayloadFromCbor(response.getPayload(),
168                         ArrayList.class);
169                 if (linkPayload == null) {
170                     mSrcDevice.sendResponse(MessageBuilder.createResponse(
171                             mRequest, ResponseStatus.NOT_FOUND));
172                 }
173                 convertHref(linkPayload);
174             }
175             mSrcDevice.sendResponse(MessageBuilder.modifyResponse(
176                     convertReponseUri(response, mTargetDI),
177                     ContentFormat.APPLICATION_CBOR, linkPayload != null
178                             ? mCbor.encodingPayloadToCbor(linkPayload) : null));
179         }
180     }
181
182     class DefaultResponseHandler implements IResponseEventHandler {
183         private String mTargetDI  = null;
184         private Device mSrcDevice = null;
185
186         public DefaultResponseHandler(String targetDI, Device srcDevice) {
187             mTargetDI = targetDI;
188             mSrcDevice = srcDevice;
189         }
190
191         @Override
192         public void onResponseReceived(IResponse response) {
193
194             mSrcDevice.sendResponse(convertReponseUri(response, mTargetDI));
195         }
196     }
197
198     class AccountReceiveHandler implements IResponseEventHandler {
199         private IRequest mRequest   = null;
200         private Device   mSrcDevice = null;
201
202         public AccountReceiveHandler(Device srcDevice, IRequest request) {
203             mRequest = request;
204             mSrcDevice = srcDevice;
205         }
206
207         @Override
208         public void onResponseReceived(IResponse response) {
209             switch (response.getStatus()) {
210                 case CONTENT:
211                     HashMap<String, Object> payloadData = mCbor
212                             .parsePayloadFromCbor(response.getPayload(),
213                                     HashMap.class);
214                     checkPayloadException(Constants.RESP_GRANT_POLICY,
215                             payloadData);
216                     String gp = (String) payloadData
217                             .get(Constants.RESP_GRANT_POLICY);
218                     verifyRequest(mSrcDevice, mRequest, gp);
219                     break;
220
221                 default:
222                     mSrcDevice.sendResponse(response);
223             }
224
225         }
226     }
227
228     private void verifyRequest(Device srcDevice, IRequest request,
229             String grantPermisson) {
230         switch (grantPermisson) {
231             case Constants.RESP_ACL_DENIED:
232                 srcDevice.sendResponse(MessageBuilder.createResponse(request,
233                         ResponseStatus.UNAUTHORIZED));
234                 break;
235
236             case Constants.RESP_ACL_ALLOWED:
237                 IRequestChannel requestChannel = getTargetDeviceChannel(
238                         request);
239
240                 if (requestChannel == null) {
241                     srcDevice.sendResponse(MessageBuilder
242                             .createResponse(request, ResponseStatus.NOT_FOUND));
243                     break;
244                 }
245
246                 IResponseEventHandler responseHandler = new DefaultResponseHandler(
247                         getDeviceId(request), srcDevice);
248                 if (request.getUriQuery() != null && request.getUriQuery()
249                         .contains(Constants.LINK_INTERFACE)) {
250                     responseHandler = new LinkInterfaceHandler(
251                             getDeviceId(request), srcDevice, request);
252                 }
253
254                 String uriPath = extractTargetUriPath(request);
255                 IRequest requestToResource = MessageBuilder
256                         .modifyRequest(request, uriPath, null, null, null);
257
258                 requestChannel.sendRequest(requestToResource, responseHandler);
259                 break;
260         }
261     }
262
263     @Override
264     public void onDefaultRequestReceived(Device srcDevice, IRequest request)
265             throws ServerException {
266         // verify Permission
267         StringBuffer uriQuery = new StringBuffer();
268         uriQuery.append(Constants.REQ_SEARCH_USER_ID + "="
269                 + srcDevice.getUserId() + ";");
270         uriQuery.append(
271                 Constants.REQ_DEVICE_ID + "=" + getDeviceId(request) + ";");
272         uriQuery.append(
273                 Constants.REQ_REQUEST_METHOD + "=" + request.getMethod() + ";");
274         uriQuery.append(Constants.REQ_REQUEST_URI + "="
275                 + extractTargetUriPath(request));
276
277         IRequest verifyRequest = MessageBuilder.createRequest(RequestMethod.GET,
278                 OICConstants.ACL_VERIFY_FULL_URI, uriQuery.toString());
279
280         ConnectorPool.getConnection("account").sendRequest(verifyRequest,
281                 new AccountReceiveHandler(srcDevice, request));
282     }
283 }