1 //******************************************************************
3 // Copyright 2014 Intel Corporation.
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
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
11 // http://www.apache.org/licenses/LICENSE-2.0
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.
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
21 package org.iotivity.guiclient;
23 import android.util.Log;
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;
31 import java.io.Serializable;
32 import java.util.ArrayList;
33 import java.util.HashMap;
34 import java.util.List;
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;
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.
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.
57 public class OcResourceInfo
58 implements OcResource.OnGetListener, OcResource.OnPutListener, Serializable {
60 * Hardcoded TAG... if project never uses proguard then
61 * MyOcClient.class.getName() is the better way.
63 private static final String TAG = "OcResourceInfo";
65 private static final boolean LOCAL_LOGV = true; // set to false to compile out verbose logging
68 * These are the resource types supported by OcResourceInfo. They should have corresponding
69 * URI strings in the OcProtocolStrings interface.
71 public enum OC_RESOURCE_TYPE {
75 ROOM_TEMPERATURE_SENSOR;
77 private static final OC_RESOURCE_TYPE[] values = OC_RESOURCE_TYPE.values();
79 public static OC_RESOURCE_TYPE fromInt(int i) {
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;
93 public interface OcResourceInfoListener {
94 public void onResourceInfoChanged(OcResourceInfo resourceInfo);
98 public OcResourceInfo(OcResource resource, OcResourceInfoListener changeListener) {
99 if (LOCAL_LOGV) Log.v(TAG, "OcResourceInfo() constructor");
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();
112 public void registerListener(OcResourceInfoListener changeListener) {
113 if(null == this.mListeners) {
114 Log.e(TAG, "registerListener(): null mListeners List");
116 boolean alreadyRegistered = false;
117 for(OcResourceInfoListener rl : this.mListeners) {
118 if(changeListener == rl) {
119 alreadyRegistered = true;
122 if(!alreadyRegistered) {
123 this.mListeners.add(changeListener);
128 public OC_RESOURCE_TYPE getType() {
132 public String getHost() {
136 public String getUri() {
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
147 Log.e(TAG, throwable.toString());
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
157 Log.e(TAG, throwable.toString());
160 public List<OcAttributeInfo> getAttributes() {
161 return this.mAttributes;
164 public void doOcGet() {
165 if(null != this.mResource) {
167 this.mResource.get(new HashMap<String, String>(), this);
168 } catch (OcException e) {
170 Log.e(TAG, e.getMessage());
173 Log.e(TAG, "doOcGet(): null mResource");
177 public void doOcPut(OcAttributeInfo attribute) {
178 if (LOCAL_LOGV) Log.v(TAG, "doOcPut()");
180 if(attribute.isReadOnly()) {
181 Log.w(TAG, String.format("doOcPut(): %s attribute is read only; skipping put!",
182 attribute.getType()));
184 if (null != this.mResource) {
186 OcRepresentation representation = new OcRepresentation();
187 switch (attribute.getType()) {
188 case AMBIENT_LIGHT_SENSOR_READING:
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.
196 for(OcAttributeInfo ai : this.mAttributes) {
197 if(ai.getType() == LIGHT_SWITCH) {
198 sw = ai.getValueBool();
201 representation.setValueBool(LIGHT_SWITCH_RESOURCE_KEY, sw);
204 representation.setValueBool(LIGHT_SWITCH_RESOURCE_KEY,
205 attribute.getValueBool());
207 case PLATFORM_LED_SWITCH:
208 representation.setValueInt(PLATFORM_LED_RESOURCE_KEY,
209 attribute.getValueInt());
211 case ROOM_TEMPERATURE_SENSOR_READING:
216 this.mResource.put(representation, new HashMap<String, String>(), this);
217 } catch (OcException e) {
219 Log.e(TAG, e.getMessage());
222 Log.e(TAG, "doOcGet(): null mResource");
227 private static Object onGetCompletedLock = new Object();
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));
237 this.mAttributes.clear();
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);
251 boolean lightSwitchVal = ocRepresentation.getValueBool(LIGHT_SWITCH_RESOURCE_KEY);
252 OcAttributeInfo lightSwitchAttribute = new OcAttributeInfo(
254 lightSwitchAttribute.setValueBool(lightSwitchVal);
255 this.mAttributes.add(lightSwitchAttribute);
257 int dimmerVal = ocRepresentation.getValueInt(LIGHT_DIMMER_RESOURCE_KEY);
258 OcAttributeInfo dimmerAttribute = new OcAttributeInfo(
260 dimmerAttribute.setValueInt(dimmerVal);
261 this.mAttributes.add(dimmerAttribute);
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);
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,
288 temperatureAttribute.setValueInt(temperatureVal);
289 this.mAttributes.add(temperatureAttribute);
292 this.notifyListeners();
293 if (LOCAL_LOGV) Log.v(TAG, "exit <- onGetCompleted()");
298 * Should be called whenever any Resource or Attribute values change on this object.
300 private void notifyListeners() {
301 if (LOCAL_LOGV) Log.v(TAG, "notifyListeners()");
303 for(OcResourceInfoListener l : this.mListeners) {
304 l.onResourceInfoChanged(this);
308 private Object onPutCompletedLock = new Object();
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));
318 case AMBIENT_LIGHT_SENSOR:
319 Log.w(TAG, String.format("onPutCompleted(): %s is a readonly attribute type.",
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);
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);
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);
346 case ROOM_TEMPERATURE_SENSOR:
347 Log.w(TAG, String.format("onPutCompleted(): %s is a readonly attribute type.",
351 this.notifyListeners();
352 if (LOCAL_LOGV) Log.v(TAG, "exit <- onPutCompleted()");
356 private OC_RESOURCE_TYPE getResourceTypeFromUri(String uri) {
357 if (LOCAL_LOGV) Log.v(TAG, "getResourceTypeFromUri()");
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;
371 Log.w(TAG, "getResourceTypeFromUri(): unsupported resource '" + uri + "'" );