Imported Upstream version 1.1.0
[platform/upstream/iotivity.git] / cloud / resourcedirectory / src / main / java / org / iotivity / cloud / rdserver / resources / ResourceDirectoryResource.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.rdserver.resources;
23
24 import java.nio.ByteBuffer;
25 import java.nio.charset.StandardCharsets;
26 import java.util.ArrayList;
27 import java.util.HashMap;
28 import java.util.LinkedHashMap;
29 import java.util.List;
30 import java.util.StringTokenizer;
31
32 import org.iotivity.cloud.base.Resource;
33 import org.iotivity.cloud.base.protocols.coap.CoapRequest;
34 import org.iotivity.cloud.base.protocols.coap.CoapResponse;
35 import org.iotivity.cloud.base.protocols.coap.enums.CoapOption;
36 import org.iotivity.cloud.base.protocols.coap.enums.CoapStatus;
37 import org.iotivity.cloud.rdserver.Constants;
38 import org.iotivity.cloud.rdserver.MongoDB;
39 import org.iotivity.cloud.util.Cbor;
40 import org.iotivity.cloud.util.JSONUtil;
41 import org.iotivity.cloud.util.Logger;
42
43 import io.netty.channel.ChannelHandlerContext;
44
45 /**
46  *
47  * This class provides a set of APIs relating Resource Directory
48  *
49  */
50 public class ResourceDirectoryResource extends Resource {
51
52     private Cbor<ArrayList<Object>> cbor;
53     private MongoDB                 mongoDB;
54
55     public ResourceDirectoryResource() {
56         setUri(Constants.RD_URI);
57         cbor = new Cbor<ArrayList<Object>>();
58         try {
59             mongoDB = new MongoDB(Constants.RD_DB_NAME);
60             mongoDB.createTable(Constants.RD_TABLE);
61         } catch (Exception e) {
62             // TODO Auto-generated catch block
63             e.printStackTrace();
64         }
65     }
66
67     @Override
68     public void onRequestReceived(ChannelHandlerContext ctx,
69             CoapRequest request) {
70
71         Logger.d("ResourceDirectoryResource IN");
72
73         if (ctx == null || request == null) {
74             Logger.d("ctx or request msg is null");
75         }
76
77         else {
78             switch (request.getRequestMethod()) {
79                 case GET:
80                     Logger.d("Request message is GET message");
81                     try {
82                         handleGetRequest(ctx, request);
83                     } catch (Exception e) {
84                         e.printStackTrace();
85                     }
86                     break;
87
88                 case PUT:
89                     Logger.d("Request message is PUT message");
90                     break;
91
92                 case POST:
93                     Logger.d("Request message is POST message");
94                     try {
95                         handlePostRequest(ctx, request);
96                     } catch (Exception e) {
97                         e.printStackTrace();
98                     }
99                     break;
100
101                 case DELETE:
102                     Logger.d("Request message is DELETE message");
103                     try {
104                         handleDeleteRequest(ctx, request);
105                     } catch (Exception e) {
106                         e.printStackTrace();
107                     }
108                     break;
109             }
110         }
111     }
112
113     private CoapResponse makePublishResponse(CoapRequest request)
114             throws Exception {
115         CoapResponse response = new CoapResponse(CoapStatus.CREATED);
116         response.setToken(request.getToken());
117         return response;
118     }
119
120     private CoapResponse makeDeleteResponse(CoapRequest request)
121             throws Exception {
122         CoapResponse response = new CoapResponse(CoapStatus.DELETED);
123         response.setToken(request.getToken());
124         return response;
125     }
126
127     private CoapResponse makeDiscoveryResponse(CoapRequest request,
128             ArrayList<PublishPayloadFormat> foundResource) throws Exception {
129
130         CoapResponse response = new CoapResponse(CoapStatus.CONTENT);
131         response.setToken(request.getToken());
132
133         // make payload
134         ArrayList<HashMap<Object, Object>> discoverPayload = new ArrayList<HashMap<Object, Object>>();
135
136         for (PublishPayloadFormat pubPayload : foundResource) {
137
138             LinksPayloadFormat links = pubPayload.links.get(0);
139             LinkedHashMap<Object, Object> discoverLinks = new LinkedHashMap<Object, Object>();
140             discoverLinks.put(Constants.RS_HREF, links.getHref());
141             discoverLinks.put(Constants.RS_RESOURCE_TYPE, links.getRt().get(0));
142             discoverLinks.put(Constants.RS_INTERFACE, links.getItf().get(0));
143             HashMap<Object, Object> pres = new HashMap<Object, Object>();
144             pres.put(Constants.RS_BITMAP, pubPayload.getBitmap());
145             discoverLinks.put("p", pres);
146
147             ArrayList<Object> linksArray = null;
148             for (HashMap<Object, Object> segmentPayload : discoverPayload) {
149                 // exist di
150                 if (segmentPayload.get(Constants.RS_DEVICE_ID)
151                         .equals(pubPayload.getDi())) {
152                     linksArray = new ArrayList<Object>();
153                     linksArray = (ArrayList<Object>) segmentPayload
154                             .get("links");
155                     linksArray.add(discoverLinks);
156                     segmentPayload.put("links", linksArray);
157                 }
158             }
159             if (linksArray == null) {
160                 HashMap<Object, Object> discoverRes = new HashMap<Object, Object>();
161                 linksArray = new ArrayList<Object>();
162                 discoverRes.put(Constants.RS_DEVICE_ID, pubPayload.getDi());
163                 linksArray.add(discoverLinks);
164                 discoverRes.put("links", linksArray);
165                 discoverPayload.add(discoverRes);
166             }
167         }
168
169         // TODO : device id is decoded to byte in IoTivity. So, temporarily we
170         // cast the type of device id to byte.
171         for (HashMap<Object, Object> segmentPayload : discoverPayload) {
172             String stringDi = segmentPayload.get(Constants.RS_DEVICE_ID)
173                     .toString();
174             segmentPayload.put(Constants.RS_DEVICE_ID,
175                     stringDi.getBytes(StandardCharsets.UTF_8));
176         }
177
178         Logger.i("discoverPayload :" + discoverPayload.toString());
179
180         byte[] bytes = ByteBuffer.allocate(4).putInt(60).array();
181         response.addOption(CoapOption.CONTENT_FORMAT.getvalue(), bytes);
182
183         byte[] encodedPaylod = cbor.encodingPayloadToCbor(discoverPayload);
184         response.setPayload(encodedPaylod);
185
186         return response;
187
188     }
189
190     private HashMap<String, String> extractFiltersFromQuery(List<String> query)
191             throws Exception {
192
193         if (query == null) {
194             throw new IllegalArgumentException("query is null!");
195         }
196
197         HashMap<String, String> filters = new HashMap<String, String>();
198         for (String queryPara : query) {
199             StringTokenizer keyValuePair = new StringTokenizer(queryPara, "=");
200             if (keyValuePair.countTokens() < 2) {
201                 // query error
202                 filters = null;
203             } else {
204                 String key = keyValuePair.nextToken();
205                 String value = keyValuePair.nextToken();
206                 if (key.equals(Constants.RS_INTERFACE)) {
207                     filters.put(Constants.RS_INTERFACE, value);
208                 } else if (key.equals(Constants.RS_RESOURCE_TYPE)) {
209                     filters.put(Constants.RS_RESOURCE_TYPE, value);
210                 } else if (key.equals(Constants.RS_DEVICE_ID)) {
211                     filters.put(Constants.RS_DEVICE_ID, value);
212                 } else if (key.equals(Constants.RS_INS)) {
213                     filters.put(Constants.RS_INS, value);
214                 } else if (key.equals(Constants.RS_SEARCH_TYPE)) {
215                     filters.put(Constants.RS_SEARCH_TYPE, value);
216                 }
217             }
218         }
219
220         return filters;
221     }
222
223     /**
224      * API for handling GET message(message to discovery resources)
225      *
226      * @param ctx
227      *            ChannelHandlerContext of request message
228      * @param request
229      *            CoAP request message
230      * @throws Exception
231      */
232     public void handleGetRequest(ChannelHandlerContext ctx, CoapRequest request)
233             throws Exception {
234         HashMap<String, String> filters = extractFiltersFromQuery(
235                 request.getUriQuerySegments());
236
237         ArrayList<PublishPayloadFormat> foundResource = null;
238
239         if (filters == null) {
240             throw new IllegalArgumentException("filters is null");
241         } else if (filters.get(Constants.RS_SEARCH_TYPE) == null) {
242             Logger.d("st is null, so this is the get msg about public devices");
243             if (filters.get(Constants.RS_INTERFACE) != null) {
244                 foundResource = mongoDB.readResource(Constants.RS_INTERFACE,
245                         filters.get(Constants.RS_INTERFACE),
246                         Constants.RD_TABLE);
247             } else if (filters.get(Constants.RS_RESOURCE_TYPE) != null) {
248                 foundResource = mongoDB.readResource(Constants.RS_RESOURCE_TYPE,
249                         filters.get(Constants.RS_RESOURCE_TYPE),
250                         Constants.RD_TABLE);
251             } else {
252                 throw new IllegalArgumentException("rt & if is null");
253             }
254
255             CoapResponse response = makeDiscoveryResponse(request,
256                     foundResource);
257             ctx.writeAndFlush(response);
258
259         } else {
260             if (filters.get(Constants.RS_SEARCH_TYPE)
261                     .equals(Constants.RS_SEARCH_TYPE_DEVICE_LIST)) {
262                 Logger.d(
263                         "st is not null, so this is the get msg about private devices");
264                 // parse payload
265                 byte[] payload = request.getPayload();
266                 ArrayList<String> deviceList = JSONUtil.parseJSON(payload,
267                         Constants.RS_DEVICE_LIST_KEY);
268                 if (deviceList == null) {
269                     throw new IllegalArgumentException("deviceList is null");
270                 }
271
272                 if (filters.get(Constants.RS_INTERFACE) != null) {
273                     foundResource = new ArrayList<PublishPayloadFormat>();
274                     for (String deviceId : deviceList) {
275                         foundResource.addAll(mongoDB.readResourceAboutDid(
276                                 deviceId, Constants.RS_INTERFACE,
277                                 filters.get(Constants.RS_INTERFACE),
278                                 Constants.RD_TABLE));
279                     }
280                 } else if (filters.get(Constants.RS_RESOURCE_TYPE) != null) {
281                     foundResource = new ArrayList<PublishPayloadFormat>();
282                     for (String deviceId : deviceList) {
283                         foundResource.addAll(mongoDB.readResourceAboutDid(
284                                 deviceId, Constants.RS_RESOURCE_TYPE,
285                                 filters.get(Constants.RS_RESOURCE_TYPE),
286                                 Constants.RD_TABLE));
287                     }
288                 } else {
289                     throw new IllegalArgumentException("rt & if is null");
290                 }
291
292                 CoapResponse response = makeDiscoveryResponse(request,
293                         foundResource);
294                 ctx.writeAndFlush(response);
295             } else {
296                 throw new IllegalArgumentException("value of st is not corret");
297             }
298         }
299     }
300
301     /**
302      * API for handling POST message(message to publish or update resources)
303      *
304      * @param ctx
305      *            ChannelHandlerContext of request message
306      * @param request
307      *            CoAP request message
308      * @throws Exception
309      */
310     public void handlePostRequest(ChannelHandlerContext ctx,
311             CoapRequest request) throws Exception {
312
313         HashMap<String, String> filters = extractFiltersFromQuery(
314                 request.getUriQuerySegments());
315
316         if (filters == null) {
317             throw new IllegalArgumentException("filters is null");
318         } else if (filters.get(Constants.RS_RESOURCE_TYPE) == null) {
319             throw new IllegalArgumentException("rt is null");
320         } else if (filters.get(Constants.RS_RESOURCE_TYPE)
321                 .equals(Constants.RS_RESOURCE_TYPE_RDPUBLISH)) {
322             Logger.d("This request is publish msg!");
323
324             PublishPayloadFormat pubPayload = new PublishPayloadFormat();
325
326             ArrayList<Object> payloadData = cbor.parsePayloadFromCbor(
327                     request.getPayload(), ArrayList.class);
328
329             if (payloadData == null) {
330                 throw new IllegalArgumentException("parsed payload is null");
331             } else {
332                 Logger.i("payloadData: " + payloadData.toString());
333             }
334
335             HashMap<Object, Object> tags = (HashMap<Object, Object>) payloadData
336                     .get(0);
337
338             if (tags == null) {
339                 throw new IllegalArgumentException("tags is null!");
340             }
341
342             Object di = tags.get(Constants.RS_DEVICE_ID);
343             if (di != null) {
344                 pubPayload.setDi(di.toString());
345                 Logger.i("di : " + pubPayload.getDi());
346             } else {
347                 throw new IllegalArgumentException("device id is null!");
348             }
349
350             Object deviceName = tags.get(Constants.RS_DEVICE_NAME);
351             if (deviceName != null) {
352                 pubPayload.setDeviceName(deviceName.toString());
353                 Logger.i("device name : " + pubPayload.getDeviceName());
354             }
355
356             Object baseUri = tags.get(Constants.RS_BASE_URI);
357             if (baseUri != null) {
358                 pubPayload.setBaseUri(baseUri.toString());
359                 Logger.i("baseURI : " + pubPayload.getBaseUri());
360             }
361
362             Object bitMap = tags.get(Constants.RS_BITMAP);
363             if (bitMap != null) {
364                 pubPayload.setBitmap((int) bitMap);
365                 Logger.i("bm : " + pubPayload.getBitmap());
366             }
367
368             Object hostingPort = tags.get(Constants.RS_HOSTING_PORT);
369             if (hostingPort != null) {
370                 pubPayload.setPort((int) hostingPort);
371                 Logger.i("port : " + pubPayload.getPort());
372             }
373
374             Object ins = tags.get(Constants.RS_INS);
375             if (ins != null) {
376                 pubPayload.setIns((int) ins);
377                 Logger.i("ins : " + pubPayload.getIns());
378             }
379
380             Object rts = tags.get(Constants.RS_RTS);
381             if (rts != null) {
382                 pubPayload.setRts(rts.toString());
383                 Logger.i("rts : " + pubPayload.getRts());
384             }
385
386             Object drel = tags.get(Constants.RS_DREL);
387             if (drel != null) {
388                 pubPayload.setDrel(drel.toString());
389                 Logger.i("drel : " + pubPayload.getDrel());
390             }
391
392             // Object ttl = tags.get(Constants.RS_TTL);
393             // if (ttl != null) {
394             // pubPayload.setTtl((int) ttl);
395             // Logger.i("ttl : " + pubPayload.getTtl());
396             // }
397
398             ArrayList<LinkedHashMap<Object, Object>> publishLinks = (ArrayList<LinkedHashMap<Object, Object>>) payloadData
399                     .get(1);
400
401             if (publishLinks == null) {
402                 throw new IllegalArgumentException("publishLinks is null!");
403             }
404
405             for (LinkedHashMap<Object, Object> o : publishLinks) {
406
407                 LinksPayloadFormat storeLinks = new LinksPayloadFormat();
408
409                 Object href = o.get(Constants.RS_HREF);
410                 if (href != null) {
411                     String prefix = "/" + pubPayload.getDi();
412                     storeLinks.setHref(prefix + href.toString());
413                     Logger.i("href : " + storeLinks.getHref());
414                 }
415
416                 if (o.get(Constants.RS_RESOURCE_TYPE) != null) {
417                     Object obj = o.get(Constants.RS_RESOURCE_TYPE);
418                     if (obj != null) {
419                         storeLinks.setRt((ArrayList<String>) obj);
420                     }
421                     Object rt = storeLinks.getRt();
422                     if (rt != null) {
423                         Logger.i("rt : " + storeLinks.getRt().toString());
424                     }
425                 }
426
427                 if (o.get(Constants.RS_INTERFACE) != null) {
428                     storeLinks.setItf(
429                             (ArrayList<String>) o.get(Constants.RS_INTERFACE));
430                     Object itf = storeLinks.getItf();
431                     if (itf != null) {
432                         Logger.i("if : " + storeLinks.getItf().toString());
433                     }
434                 }
435
436                 Object rel = o.get(Constants.RS_REL);
437                 if (rel != null) {
438                     storeLinks.setRel(rel.toString());
439                     Logger.i("rel : " + storeLinks.getRel());
440                 }
441
442                 if (o.get(Constants.RS_OBS) != null) {
443                     Object obj = o.get(Constants.RS_OBS);
444                     if (obj != null) {
445                         storeLinks.setObs((boolean) obj);
446                     }
447                     Logger.i("obs : " + storeLinks.isObs());
448                 }
449
450                 if (o.get(Constants.RS_TITLE) != null) {
451                     Object obj = o.get(Constants.RS_TITLE);
452                     if (obj != null) {
453                         storeLinks.setTitle(obj.toString());
454                     }
455                     Logger.i("title : " + storeLinks.getTitle());
456                 }
457
458                 if (o.get(Constants.RS_URI) != null) {
459                     Object obj = o.get(Constants.RS_URI);
460                     if (obj != null) {
461                         storeLinks.setUri(obj.toString());
462                     }
463                     Logger.i("uri : " + storeLinks.getUri());
464                 }
465
466                 if (o.get(Constants.RS_INS) != null) {
467                     Object obj = o.get(Constants.RS_INS);
468                     if (obj != null) {
469                         storeLinks.setIns((int) obj);
470                     }
471                     Logger.i("ins : " + storeLinks.getIns());
472                 }
473
474                 if (o.get(Constants.RS_MEDIA_TYPE) != null) {
475                     Object obj = o.get(Constants.RS_MEDIA_TYPE);
476                     if (obj != null) {
477                         storeLinks.setMt((ArrayList<String>) obj);
478                     }
479                     Object mt = storeLinks.getMt();
480                     if (mt != null) {
481                         Logger.i("mt : " + mt.toString());
482                     }
483                 }
484
485                 pubPayload.links.add(storeLinks);
486             }
487
488             mongoDB.createResource(pubPayload, Constants.RD_TABLE);
489
490             CoapResponse response = makePublishResponse(request);
491             ctx.writeAndFlush(response);
492
493         } else {
494             throw new IllegalArgumentException("rt is not correct");
495         }
496     }
497
498     /**
499      * API for handling Delete message(message to delete published resources)
500      *
501      * @param ctx
502      *            ChannelHandlerContext of request message
503      * @param request
504      *            CoAP request message
505      * @throws Exception
506      */
507     public void handleDeleteRequest(ChannelHandlerContext ctx,
508             CoapRequest request) throws Exception {
509         HashMap<String, String> filters = extractFiltersFromQuery(
510                 request.getUriQuerySegments());
511
512         if (filters == null) {
513             throw new IllegalArgumentException("filters is null");
514         } else if (filters.get(Constants.RS_DEVICE_ID) == null) {
515             throw new IllegalArgumentException("di is null");
516         } else {
517             if (filters.get(Constants.RS_INS) == null) {
518                 mongoDB.deleteResourceAboutDid(
519                         filters.get(Constants.RS_DEVICE_ID),
520                         Constants.RD_TABLE);
521             } else {
522                 mongoDB.deleteResourceAboutDidAndIns(
523                         filters.get(Constants.RS_DEVICE_ID),
524                         filters.get(Constants.RS_INS), Constants.RD_TABLE);
525             }
526             CoapResponse response = makeDeleteResponse(request);
527             ctx.writeAndFlush(response);
528         }
529     }
530 }