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