Imported Upstream version 0.9.2
[platform/upstream/iotivity.git] / android / examples / guiclient / src / main / java / org / iotivity / guiclient / OcResourceInfo.java
1 //******************************************************************
2 //
3 // Copyright 2014 Intel Corporation.
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 package org.iotivity.guiclient;
22
23 import android.util.Log;
24
25 import org.iotivity.base.ErrorCode;
26 import org.iotivity.base.OcException;
27 import org.iotivity.base.OcHeaderOption;
28 import org.iotivity.base.OcRepresentation;
29 import org.iotivity.base.OcResource;
30
31 import java.io.Serializable;
32 import java.util.ArrayList;
33 import java.util.HashMap;
34 import java.util.List;
35
36 import static org.iotivity.guiclient.OcAttributeInfo.OC_ATTRIBUTE_TYPE.AMBIENT_LIGHT_SENSOR_READING;
37 import static org.iotivity.guiclient.OcAttributeInfo.OC_ATTRIBUTE_TYPE.LIGHT_DIMMER;
38 import static org.iotivity.guiclient.OcAttributeInfo.OC_ATTRIBUTE_TYPE.LIGHT_SWITCH;
39 import static org.iotivity.guiclient.OcProtocolStrings.AMBIENT_LIGHT_RESOURCE_KEY;
40 import static org.iotivity.guiclient.OcProtocolStrings.AMBIENT_LIGHT_RESOURCE_URI;
41 import static org.iotivity.guiclient.OcProtocolStrings.LIGHT_DIMMER_RESOURCE_KEY;
42 import static org.iotivity.guiclient.OcProtocolStrings.LIGHT_RESOURCE_URI;
43 import static org.iotivity.guiclient.OcProtocolStrings.LIGHT_RESOURCE_URI2;
44 import static org.iotivity.guiclient.OcProtocolStrings.LIGHT_RESOURCE_URI3;
45 import static org.iotivity.guiclient.OcProtocolStrings.LIGHT_SWITCH_RESOURCE_KEY;
46 import static org.iotivity.guiclient.OcProtocolStrings.PLATFORM_LED_RESOURCE_KEY;
47 import static org.iotivity.guiclient.OcProtocolStrings.PLATFORM_LED_RESOURCE_URI;
48 import static org.iotivity.guiclient.OcProtocolStrings.ROOM_TEMPERATURE_RESOURCE_URI;
49
50 /**
51  * OcResourceInfo is a wrapper object for the OcResource object. It implements the Resource-
52  * specific callbacks, and abstracts the IoTivity implementation details from the application.
53  *
54  * In order to use OcResourceInfo, an application should implement the OcResourceInfoListener
55  * interface, which is called when the OcResourceInfo changes in any meaningful way.
56  */
57 public class OcResourceInfo
58         implements OcResource.OnGetListener, OcResource.OnPutListener, Serializable {
59     /**
60      * Hardcoded TAG... if project never uses proguard then
61      * MyOcClient.class.getName() is the better way.
62      */
63     private static final String TAG = "OcResourceInfo";
64
65     private static final boolean LOCAL_LOGV = true; // set to false to compile out verbose logging
66
67     /**
68      * These are the resource types supported by OcResourceInfo.  They should have corresponding
69      * URI strings in the OcProtocolStrings interface.
70      */
71     public enum OC_RESOURCE_TYPE {
72         AMBIENT_LIGHT_SENSOR,
73         LIGHT,
74         PLATFORM_LED,
75         ROOM_TEMPERATURE_SENSOR;
76
77         private static final OC_RESOURCE_TYPE[] values = OC_RESOURCE_TYPE.values();
78
79         public static OC_RESOURCE_TYPE fromInt(int i) {
80             return values[i];
81         }
82     }
83
84     private List<OcAttributeInfo> mAttributes;
85     private final String mHost;
86     private final int mId;
87     private static int mIdInitializer = 0;
88     private List<OcResourceInfoListener> mListeners;
89     private final OcResource mResource;
90     private final OC_RESOURCE_TYPE mType;
91     private final String mUri;
92
93     public interface OcResourceInfoListener {
94         public void onResourceInfoChanged(OcResourceInfo resourceInfo);
95     }
96
97
98     public OcResourceInfo(OcResource resource, OcResourceInfoListener changeListener) {
99         if (LOCAL_LOGV) Log.v(TAG, "OcResourceInfo() constructor");
100
101         this.mAttributes = new ArrayList<>();
102         this.mHost = resource.getHost();
103         this.mId = OcResourceInfo.mIdInitializer++; // give a unique Id from other OcResourceInfos
104         this.mListeners = new ArrayList<>();
105         this.mListeners.add(changeListener);
106         this.mResource = resource;
107         this.mType = this.getResourceTypeFromUri(resource.getUri());
108         this.mUri = resource.getUri();
109
110     }
111
112     public void registerListener(OcResourceInfoListener changeListener) {
113         if(null == this.mListeners) {
114             Log.e(TAG, "registerListener(): null mListeners List");
115         } else {
116             boolean alreadyRegistered = false;
117             for(OcResourceInfoListener rl : this.mListeners) {
118                 if(changeListener == rl) {
119                     alreadyRegistered = true;
120                 }
121             }
122             if(!alreadyRegistered) {
123                 this.mListeners.add(changeListener);
124             }
125         }
126     }
127
128     public OC_RESOURCE_TYPE getType() {
129         return this.mType;
130     }
131
132     public String getHost() {
133         return this.mHost;
134     }
135
136     public String getUri() {
137         return this.mUri;
138     }
139
140     @Override
141     public void onGetFailed(Throwable throwable) {
142         if (throwable instanceof OcException) {
143             OcException ocEx = (OcException) throwable;
144             ErrorCode errCode = ocEx.getErrorCode();
145             //do something based on errorCode
146         }
147         Log.e(TAG, throwable.toString());
148     }
149
150     @Override
151     public void onPutFailed(Throwable throwable) {
152         if (throwable instanceof OcException) {
153             OcException ocEx = (OcException) throwable;
154             ErrorCode errCode = ocEx.getErrorCode();
155             //do something based on errorCode
156         }
157         Log.e(TAG, throwable.toString());
158     }
159
160     public List<OcAttributeInfo> getAttributes() {
161         return this.mAttributes;
162     }
163
164     public void doOcGet() {
165         if(null != this.mResource) {
166             try {
167                 this.mResource.get(new HashMap<String, String>(), this);
168             } catch (OcException e) {
169                 e.printStackTrace();
170                 Log.e(TAG, e.getMessage());
171             }
172         } else {
173             Log.e(TAG, "doOcGet(): null mResource");
174         }
175     }
176
177     public void doOcPut(OcAttributeInfo attribute) {
178         if (LOCAL_LOGV) Log.v(TAG, "doOcPut()");
179
180         if(attribute.isReadOnly()) {
181             Log.w(TAG, String.format("doOcPut(): %s attribute is read only; skipping put!",
182                     attribute.getType()));
183         } else {
184             if (null != this.mResource) {
185                 try {
186                     OcRepresentation representation = new OcRepresentation();
187                     switch (attribute.getType()) {
188                         case AMBIENT_LIGHT_SENSOR_READING:
189                             break;
190                         case LIGHT_DIMMER:
191                             representation.setValueInt(LIGHT_DIMMER_RESOURCE_KEY,
192                                     attribute.getValueInt());
193                             // This 'sw' logic is here because the current IoTivity Light forces
194                             // the switch to "false" if the switch val is not specified.
195                             boolean sw = true;
196                             for(OcAttributeInfo ai : this.mAttributes) {
197                                 if(ai.getType() == LIGHT_SWITCH) {
198                                     sw = ai.getValueBool();
199                                 }
200                             }
201                             representation.setValueBool(LIGHT_SWITCH_RESOURCE_KEY, sw);
202                             break;
203                         case LIGHT_SWITCH:
204                             representation.setValueBool(LIGHT_SWITCH_RESOURCE_KEY,
205                                     attribute.getValueBool());
206                             break;
207                         case PLATFORM_LED_SWITCH:
208                             representation.setValueInt(PLATFORM_LED_RESOURCE_KEY,
209                                     attribute.getValueInt());
210                             break;
211                         case ROOM_TEMPERATURE_SENSOR_READING:
212                             break;
213                         default:
214                             break;
215                     }
216                     this.mResource.put(representation, new HashMap<String, String>(), this);
217                 } catch (OcException e) {
218                     e.printStackTrace();
219                     Log.e(TAG, e.getMessage());
220                 }
221             } else {
222                 Log.e(TAG, "doOcGet(): null mResource");
223             }
224         }
225     }
226
227     private static Object onGetCompletedLock = new Object();
228     @Override
229 //    public void onGetCompleted(HeaderOptions headerOptions, OcRepresentation ocRepresentation) {
230     public void onGetCompleted(List<OcHeaderOption> headerOptionList,
231                                OcRepresentation ocRepresentation) {
232         synchronized (onGetCompletedLock) {
233             if (LOCAL_LOGV) Log.v(TAG, "enter -> onGetCompleted()");
234             if (LOCAL_LOGV) Log.v(TAG, String.format("\tthis = %s", this.toString()));
235             if (LOCAL_LOGV) Log.v(TAG, String.format("\tthis.mType = %s", this.mType));
236
237             this.mAttributes.clear();
238             switch(this.mType) {
239                 case AMBIENT_LIGHT_SENSOR:
240                     int ambientLightVal = ocRepresentation.getValueInt(AMBIENT_LIGHT_RESOURCE_KEY);
241                     if (LOCAL_LOGV) Log.v(TAG,
242                             String.format("%s int value of %s attribute = %d",
243                                     mType, AMBIENT_LIGHT_RESOURCE_KEY, ambientLightVal));
244                     OcAttributeInfo ambientAttribute = new OcAttributeInfo(
245                             AMBIENT_LIGHT_SENSOR_READING, this);
246                     ambientAttribute.setValueInt(ambientLightVal);
247                     this.mAttributes.add(ambientAttribute);
248                     break;
249                 case LIGHT:
250                     // do switch first
251                     boolean lightSwitchVal = ocRepresentation.getValueBool(LIGHT_SWITCH_RESOURCE_KEY);
252                     OcAttributeInfo lightSwitchAttribute = new OcAttributeInfo(
253                             LIGHT_SWITCH, this);
254                     lightSwitchAttribute.setValueBool(lightSwitchVal);
255                     this.mAttributes.add(lightSwitchAttribute);
256                     // then dimmer
257                     int dimmerVal = ocRepresentation.getValueInt(LIGHT_DIMMER_RESOURCE_KEY);
258                     OcAttributeInfo dimmerAttribute = new OcAttributeInfo(
259                             LIGHT_DIMMER, this);
260                     dimmerAttribute.setValueInt(dimmerVal);
261                     this.mAttributes.add(dimmerAttribute);
262                     break;
263                 case PLATFORM_LED:
264                     int ledVal = ocRepresentation.getValueInt(PLATFORM_LED_RESOURCE_KEY);
265                     if (LOCAL_LOGV) Log.v(TAG,
266                             String.format("%s int value of %s attribute = %d",
267                                     mType, PLATFORM_LED_RESOURCE_KEY, ledVal));
268                     OcAttributeInfo ledAttribute = new OcAttributeInfo(
269                             OcAttributeInfo.OC_ATTRIBUTE_TYPE.PLATFORM_LED_SWITCH, this);
270                     ledAttribute.setValueInt(ledVal);
271                     this.mAttributes.add(ledAttribute);
272                     break;
273                 case ROOM_TEMPERATURE_SENSOR:
274                     int temperatureVal = 98;
275                     Log.w(TAG, "getting 'temperature' value is causing crash;" +
276                             " skipping and using 98.");
277                     // TODO This call crashes in the native JNI code.  The example .cpp
278                     //      app receives a double for the Room Temp key, but the Java API
279                     //      doesn't support getValueDouble yet.
280                     //      Debug crash when API fixed?
281 //                    temperatureVal = ocRepresentation.getValueInt(ROOM_TEMPERATURE_RESOURCE_KEY);
282                     if (LOCAL_LOGV) Log.v(TAG,
283                             String.format("%s int value of 'temperature' attribute = %d",
284                                     mType, temperatureVal));
285                     OcAttributeInfo temperatureAttribute = new OcAttributeInfo(
286                             OcAttributeInfo.OC_ATTRIBUTE_TYPE.ROOM_TEMPERATURE_SENSOR_READING,
287                             this);
288                     temperatureAttribute.setValueInt(temperatureVal);
289                     this.mAttributes.add(temperatureAttribute);
290                     break;
291             }
292             this.notifyListeners();
293             if (LOCAL_LOGV) Log.v(TAG, "exit <- onGetCompleted()");
294         }
295     }
296
297     /**
298      * Should be called whenever any Resource or Attribute values change on this object.
299      */
300     private void notifyListeners() {
301         if (LOCAL_LOGV) Log.v(TAG, "notifyListeners()");
302
303         for(OcResourceInfoListener l : this.mListeners) {
304             l.onResourceInfoChanged(this);
305         }
306     }
307
308     private Object onPutCompletedLock = new Object();
309     @Override
310     public void onPutCompleted(List<OcHeaderOption> headerOptionList,
311                                OcRepresentation ocRepresentation) {
312         synchronized (onPutCompletedLock) {
313             if (LOCAL_LOGV) Log.v(TAG, "enter -> onPutCompleted()");
314             if (LOCAL_LOGV) Log.v(TAG, String.format("\tthis = %s", this.toString()));
315             if (LOCAL_LOGV) Log.v(TAG, String.format("\tthis.mType = %s", this.mType));
316
317             switch(this.mType) {
318                 case AMBIENT_LIGHT_SENSOR:
319                     Log.w(TAG, String.format("onPutCompleted(): %s is a readonly attribute type.",
320                             this.mType));
321                     break;
322                 case LIGHT:
323                     // do switch first
324                     boolean lightSwitchVal = ocRepresentation.getValueBool(LIGHT_SWITCH_RESOURCE_KEY);
325                     for(OcAttributeInfo ai : this.mAttributes) {
326                         if (ai.getType() == OcAttributeInfo.OC_ATTRIBUTE_TYPE.LIGHT_SWITCH) {
327                             ai.setValueBool(lightSwitchVal);
328                         }
329                     }
330                     // then dimmer
331                     int dimmerVal = ocRepresentation.getValueInt(LIGHT_DIMMER_RESOURCE_KEY);
332                     for(OcAttributeInfo ai : this.mAttributes) {
333                         if (ai.getType() == OcAttributeInfo.OC_ATTRIBUTE_TYPE.LIGHT_DIMMER) {
334                             ai.setValueInt(dimmerVal);
335                         }
336                     }
337                     break;
338                 case PLATFORM_LED:
339                     int value = ocRepresentation.getValueInt(PLATFORM_LED_RESOURCE_KEY);
340                     for(OcAttributeInfo ai : this.mAttributes) {
341                         if (ai.getType() == OcAttributeInfo.OC_ATTRIBUTE_TYPE.PLATFORM_LED_SWITCH) {
342                             ai.setValueInt(value);
343                         }
344                     }
345                     break;
346                 case ROOM_TEMPERATURE_SENSOR:
347                     Log.w(TAG, String.format("onPutCompleted(): %s is a readonly attribute type.",
348                             this.mType));
349                     break;
350             }
351             this.notifyListeners();
352             if (LOCAL_LOGV) Log.v(TAG, "exit <- onPutCompleted()");
353         }
354     }
355
356     private OC_RESOURCE_TYPE getResourceTypeFromUri(String uri) {
357         if (LOCAL_LOGV) Log.v(TAG, "getResourceTypeFromUri()");
358
359         switch(uri) {
360             case LIGHT_RESOURCE_URI:
361             case LIGHT_RESOURCE_URI2:
362             case LIGHT_RESOURCE_URI3:
363                 return OC_RESOURCE_TYPE.LIGHT;
364             case AMBIENT_LIGHT_RESOURCE_URI:
365                 return OC_RESOURCE_TYPE.AMBIENT_LIGHT_SENSOR;
366             case PLATFORM_LED_RESOURCE_URI:
367                 return OC_RESOURCE_TYPE.PLATFORM_LED;
368             case ROOM_TEMPERATURE_RESOURCE_URI:
369                 return OC_RESOURCE_TYPE.ROOM_TEMPERATURE_SENSOR;
370             default:
371                 Log.w(TAG, "getResourceTypeFromUri(): unsupported resource '" + uri + "'" );
372         }
373         return null;
374     }
375 }