Implement Binary String transit type in C++ stack
authorTodd Malsbary <todd.malsbary@intel.com>
Tue, 26 Apr 2016 20:41:55 +0000 (13:41 -0700)
committerJon A. Cruz <jon@joncruz.org>
Wed, 25 May 2016 06:45:04 +0000 (06:45 +0000)
The C stack got a Binary String component here:
https://gerrit.iotivity.org/gerrit/#/c/2337/

This patch implements it in the C++ stack, and validates it in the unit
test.

Note that this patch does NOT do binary-string-array, but this patch
should be able to demonstrate the effort involved.

Change-Id: I2fd6341f3d84539c3ad5450279f1d755ba211fd6
Signed-off-by: Erich Keane <erich.keane@intel.com>
Signed-off-by: Todd Malsbary <todd.malsbary@intel.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/7937
Tested-by: jenkins-iotivity <jenkins-iotivity@opendaylight.org>
Reviewed-by: Tim Kourt <tim.a.kourt@intel.com>
Reviewed-by: Jon A. Cruz <jon@joncruz.org>
android/android_api/base/jni/JniOcRepresentation.cpp
android/android_api/base/jni/JniOcRepresentation.h
android/android_api/base/src/androidTest/java/org/iotivity/base/OcRepresentationTest.java
android/android_api/base/src/main/java/org/iotivity/base/OcRepresentation.java
resource/include/AttributeValue.h
resource/include/OCRepresentation.h
resource/src/OCRepresentation.cpp
resource/unittests/OCRepresentationEncodingTest.cpp

index c3c37ad..c9cf0d3 100644 (file)
@@ -729,6 +729,38 @@ JNIEXPORT void JNICALL Java_org_iotivity_base_OcRepresentation_setValueRepresent
 
 /*
 * Class:     org_iotivity_base_OcRepresentation
+* Method:    setValueByteArray
+* Signature: (Ljava/lang/String;[B)V
+*/
+JNIEXPORT void JNICALL Java_org_iotivity_base_OcRepresentation_setValueByteArray
+(JNIEnv *env, jobject thiz, jstring jKey, jbyteArray jValue)
+{
+    LOGD("OcRepresentation_setValueByteArray");
+    if (!jKey)
+    {
+        ThrowOcException(OC_STACK_INVALID_PARAM, "key cannot be null");
+        return;
+    }
+
+    const jsize len = env->GetArrayLength(jValue);
+    jbyte* bytes = env->GetByteArrayElements(jValue, nullptr);
+
+    std::vector<uint8_t> value;
+    for (jsize i = 0; i < len; ++i)
+    {
+        value.push_back(static_cast<uint8_t>(bytes[i]));
+    }
+    env->ReleaseByteArrayElements(jValue, bytes, JNI_ABORT);
+
+    OCRepresentation *rep = JniOcRepresentation::getOCRepresentationPtr(env, thiz);
+    if (!rep) return;
+
+    std::string key = env->GetStringUTFChars(jKey, nullptr);
+    rep->setValue(key, value);
+}
+
+/*
+* Class:     org_iotivity_base_OcRepresentation
 * Method:    addChild
 * Signature: (Lorg/iotivity/base/OcRepresentation;)V
 */
index ee8f222..e0a87b6 100644 (file)
@@ -155,6 +155,15 @@ struct JObjectConverter : boost::static_visitor < jobject >
         }
         return repArr;
     }
+    jobject operator()(const std::vector<uint8_t>& val) const
+    {
+        size_t len = val.size();
+        jbyteArray jByteArray = env->NewByteArray(len);
+        if (!jByteArray) return nullptr;
+        const uint8_t* bytes = &val[0];
+        env->SetByteArrayRegion(jByteArray, 0, len, reinterpret_cast<const jbyte*>(bytes));
+        return jByteArray;
+    }
 
     // Nested sequences:
     jobject operator()(const std::vector<std::vector<int>>& val) const
@@ -621,6 +630,14 @@ extern "C" {
 
     /*
     * Class:     org_iotivity_base_OcRepresentation
+    * Method:    setValueByteArray
+    * Signature: (Ljava/lang/String;[B)V
+    */
+    JNIEXPORT void JNICALL Java_org_iotivity_base_OcRepresentation_setValueByteArray
+        (JNIEnv *, jobject, jstring, jbyteArray);
+
+    /*
+    * Class:     org_iotivity_base_OcRepresentation
     * Method:    addChild
     * Signature: (Lorg/iotivity/base/OcRepresentation;)V
     */
index 8a7b93d..043eda0 100644 (file)
@@ -309,6 +309,18 @@ public class OcRepresentationTest extends InstrumentationTestCase {
         rep.setValue(representationK, representationArrVEmpty);
         OcRepresentation[] representationArrVEmptyA = rep.getValue(representationK);
         assertEquals(representationArrVEmpty.length, representationArrVEmptyA.length);
+
+        //byte
+        String byteK = "byteK";
+        byte[] byteArrV = {1, 2, 3, 4, 0, 5, 6, 7};
+        rep.setValue(byteK, byteArrV);
+        byte[] byteArrVa = rep.getValue(byteK);
+        assertTrue(Arrays.equals(byteArrV, byteArrVa));
+
+        byte[] byteArrVEmpty = {};
+        rep.setValue(byteK, byteArrVEmpty);
+        byte[] byteArrVEmptyA = rep.getValue(byteK);
+        assertTrue(Arrays.equals(byteArrVEmpty, byteArrVEmptyA));
     }
 
     public void testAttributeAccessBy2DType() throws OcException {
index a752f09..0be617a 100644 (file)
@@ -141,6 +141,10 @@ public class OcRepresentation {
         this.setValueRepresentation3DArray(key, value);
     }
 
+    public void setValue(String key, byte[] value) throws OcException {
+        this.setValueByteArray(key, value);
+    }
+
     private native void setValueInteger(String key, int value) throws OcException;
 
     private native void setValueDouble(String key, double value) throws OcException;
@@ -181,6 +185,8 @@ public class OcRepresentation {
 
     private native void setValueRepresentation3DArray(String key, OcRepresentation[][][] value) throws OcException;
 
+    private native void setValueByteArray(String key, byte[] value) throws OcException;
+
     /**
      * @deprecated use {@link #getValue(String key)} instead.
      */
index 0506e0f..2bfb10b 100644 (file)
@@ -76,7 +76,10 @@ namespace OC
         std::vector<std::vector<std::vector<std::string>>>,
 
         std::vector<std::vector<OC::OCRepresentation>>,
-        std::vector<std::vector<std::vector<OC::OCRepresentation>>>
+        std::vector<std::vector<std::vector<OC::OCRepresentation>>>,
+
+        // used for binary data type
+        std::vector<uint8_t>
     > AttributeValue;
 
     enum class AttributeType
@@ -87,7 +90,8 @@ namespace OC
         Boolean,
         String,
         OCRepresentation,
-        Vector
+        Vector,
+        Binary
     };
 
     template<typename T>
@@ -129,6 +133,12 @@ namespace OC
         constexpr static AttributeType type = AttributeType::OCRepresentation;
     };
 
+    template<>
+    struct AttributeTypeConvert<std::vector<uint8_t>>
+    {
+        constexpr static AttributeType type = AttributeType::Binary;
+    };
+
     std::ostream& operator << (std::ostream& os, const AttributeType at);
 }
 #endif // OC_ATTRIBUTEVALUE_H_
index 4d1d24a..5f2071a 100644 (file)
@@ -153,6 +153,13 @@ namespace OC
                 m_values[str] = val;
             }
 
+            // using R-value(or universal ref depending) to move string and vector<uint8_t>
+            template <typename T>
+            void setValue(const std::string& str, T&& val)
+            {
+                m_values[str] = std::forward<T>(val);
+            }
+
             /**
              *  Retrieve the attribute value associated with the supplied name
              *
index 47dce71..8b0015b 100644 (file)
@@ -431,6 +431,11 @@ namespace OC
                 case AttributeType::Vector:
                     getPayloadArray(root, val);
                     break;
+                case AttributeType::Binary:
+                    OCRepPayloadSetPropByteString(root, val.attrname().c_str(),
+                            OCByteString{const_cast<uint8_t*>(val.getValue<std::vector<uint8_t>>().data()),
+                            val.getValue<std::vector<uint8_t>>().size()});
+                    break;
                 default:
                     throw std::logic_error(std::string("Getpayload: Not Implemented") +
                             std::to_string((int)val.type()));
@@ -635,6 +640,12 @@ namespace OC
                 case OCREP_PROP_ARRAY:
                     setPayloadArray(val);
                     break;
+                case OCREP_PROP_BYTE_STRING:
+                    setValue(val->name,
+                            std::vector<uint8_t>
+                            (val->ocByteStr.bytes, val->ocByteStr.bytes + val->ocByteStr.len)
+                            );
+                    break;
                 default:
                     throw std::logic_error(std::string("Not Implemented!") +
                             std::to_string((int)val->type));
@@ -841,6 +852,8 @@ namespace OC
             case AttributeType::Vector:
                 os << "Vector";
                 break;
+            case AttributeType::Binary:
+                os<< "Binary";
         }
         return os;
     }
@@ -888,7 +901,13 @@ namespace OC
     };
 
     template<typename T>
-    struct type_info<T, typename std::enable_if<is_vector<T>::value>::type>
+    struct type_info<
+        T,
+        typename std::enable_if<
+            is_vector<T>::value &&
+            !std::is_same<uint8_t, typename T::value_type>::value
+        >::type
+    >
     {
         typedef T type;
         typedef typename type_info<typename T::value_type>::base_type base_type;
@@ -899,6 +918,18 @@ namespace OC
             type_info<typename T::value_type>::depth;
     };
 
+    // special case for binary data, which is a std::vector<uint8_t>
+    template<>
+    struct type_info<std::vector<uint8_t>, void>
+    {
+        typedef std::vector<uint8_t> type;
+        typedef std::vector<uint8_t> base_type;
+        constexpr static AttributeType enum_type = AttributeType::Binary;
+        constexpr static AttributeType enum_base_type = AttributeType::Binary;
+        constexpr static size_t depth = 0;
+    };
+
+
     struct type_introspection_visitor : boost::static_visitor<>
     {
         AttributeType type;
index a1ca196..8c827c1 100644 (file)
@@ -286,6 +286,8 @@ namespace OCRepresentationEncodingTest
         subRep.setValue("DoubleAttr", 3.333);
         subRep.setValue("BoolAttr", true);
         subRep.setValue("StringAttr", std::string("String attr"));
+        std::vector<uint8_t> bin_data {5,3,4,5,6,0,34,2,4,5,6,3};
+        subRep.setValue("BinaryAttr", bin_data);
         startRep.setValue("Sub", subRep);
 
         OC::MessageContainer mc1;
@@ -315,6 +317,8 @@ namespace OCRepresentationEncodingTest
         EXPECT_EQ(3.333, newSubRep.getValue<double>("DoubleAttr"));
         EXPECT_EQ(true, newSubRep.getValue<bool>("BoolAttr"));
         EXPECT_STREQ("String attr", newSubRep.getValue<std::string>("StringAttr").c_str());
+        EXPECT_EQ(bin_data,
+                newSubRep.getValue<std::vector<uint8_t>>("BinaryAttr"));
         OCPayloadDestroy(cparsed);
     }