A modelling and serializer library for Microsoft Azure IoTHub client applications

Dependents:   sht15_remote_monitoring f767zi_mqtt remote_monitoring simplesample_amqp ... more

This library implements a serializer library to be used in projects involving Microsoft Azure IoT Hub connectivity. The code is replicated from https://github.com/Azure/azure-iot-sdks

Revision:
17:fa1bba4c6053
Parent:
13:16e88f0cfa5f
Child:
18:58b667752399
diff -r ef107f3f230c -r fa1bba4c6053 schema.c
--- a/schema.c	Thu Oct 20 17:08:06 2016 -0700
+++ b/schema.c	Wed Nov 16 21:38:26 2016 -0800
@@ -15,64 +15,86 @@
 
 DEFINE_ENUM_STRINGS(SCHEMA_RESULT, SCHEMA_RESULT_VALUES);
 
-typedef struct PROPERTY_TAG
+typedef struct SCHEMA_PROPERTY_HANDLE_DATA_TAG
 {
     const char* PropertyName;
     const char* PropertyType;
-} PROPERTY;
+} SCHEMA_PROPERTY_HANDLE_DATA;
+
+typedef struct SCHEMA_REPORTED_PROPERTY_HANDLE_DATA_TAG
+{
+    const char* reportedPropertyName;
+    const char* reportedPropertyType;
+} SCHEMA_REPORTED_PROPERTY_HANDLE_DATA;
 
-typedef struct SCHEMA_ACTION_ARGUMENT_TAG
+typedef struct SCHEMA_DESIRED_PROPERTY_HANDLE_DATA_TAG
+{
+    pfOnDesiredProperty onDesiredProperty;
+    pfDesiredPropertyInitialize desiredPropertInitialize;
+    pfDesiredPropertyDeinitialize desiredPropertDeinitialize;
+    const char* desiredPropertyName;
+    const char* desiredPropertyType;
+    pfDesiredPropertyFromAGENT_DATA_TYPE desiredPropertyFromAGENT_DATA_TYPE;
+    size_t offset;
+} SCHEMA_DESIRED_PROPERTY_HANDLE_DATA;
+
+typedef struct SCHEMA_ACTION_ARGUMENT_HANDLE_DATA_TAG
 {
     const char* Name;
     const char* Type;
-} SCHEMA_ACTION_ARGUMENT;
+} SCHEMA_ACTION_ARGUMENT_HANDLE_DATA;
 
-typedef struct ACTION_TAG
+typedef struct SCHEMA_ACTION_HANDLE_DATA_TAG
 {
     const char* ActionName;
     size_t ArgumentCount;
     SCHEMA_ACTION_ARGUMENT_HANDLE* ArgumentHandles;
-} ACTION;
+} SCHEMA_ACTION_HANDLE_DATA;
 
 typedef struct MODEL_IN_MODEL_TAG
 {
+    pfOnDesiredProperty onDesiredProperty; /*is NULL if not specified or if the model in model is not WITH_DESIRED_PROPERTY*/
+    size_t offset; /*offset of the model in model (offsetof)*/
     const char* propertyName;
     SCHEMA_MODEL_TYPE_HANDLE modelHandle;
 } MODEL_IN_MODEL;
 
-typedef struct MODEL_TYPE_TAG
+typedef struct SCHEMA_MODEL_TYPE_HANDLE_DATA_TAG
 {
+    VECTOR_HANDLE desiredProperties; /*holds SCHEMA_DESIRED_PROPERTY_HANDLE_DATA*/
     const char* Name;
     SCHEMA_HANDLE SchemaHandle;
     SCHEMA_PROPERTY_HANDLE* Properties;
     size_t PropertyCount;
+    VECTOR_HANDLE reportedProperties; /*holds SCHEMA_REPORTED_PROPERTY_HANDLE*/
     SCHEMA_ACTION_HANDLE* Actions;
     size_t ActionCount;
     VECTOR_HANDLE models;
     size_t DeviceCount;
-} MODEL_TYPE;
+} SCHEMA_MODEL_TYPE_HANDLE_DATA;
 
-typedef struct STRUCT_TYPE_TAG
+typedef struct SCHEMA_STRUCT_TYPE_HANDLE_DATA_TAG
 {
     const char* Name;
     SCHEMA_PROPERTY_HANDLE* Properties;
     size_t PropertyCount;
-} STRUCT_TYPE;
+} SCHEMA_STRUCT_TYPE_HANDLE_DATA;
 
-typedef struct SCHEMA_TAG
+typedef struct SCHEMA_HANDLE_DATA_TAG
 {
+    void* metadata;
     const char* Namespace;
     SCHEMA_MODEL_TYPE_HANDLE* ModelTypes;
     size_t ModelTypeCount;
     SCHEMA_STRUCT_TYPE_HANDLE* StructTypes;
     size_t StructTypeCount;
-} SCHEMA;
+} SCHEMA_HANDLE_DATA;
 
 static VECTOR_HANDLE g_schemas = NULL;
 
 static void DestroyProperty(SCHEMA_PROPERTY_HANDLE propertyHandle)
 {
-    PROPERTY* propertyType = (PROPERTY*)propertyHandle;
+    SCHEMA_PROPERTY_HANDLE_DATA* propertyType = (SCHEMA_PROPERTY_HANDLE_DATA*)propertyHandle;
     free((void*)propertyType->PropertyName);
     free((void*)propertyType->PropertyType);
     free(propertyType);
@@ -80,7 +102,7 @@
 
 static void DestroyActionArgument(SCHEMA_ACTION_ARGUMENT_HANDLE actionArgumentHandle)
 {
-    SCHEMA_ACTION_ARGUMENT* actionArgument = (SCHEMA_ACTION_ARGUMENT*)actionArgumentHandle;
+    SCHEMA_ACTION_ARGUMENT_HANDLE_DATA* actionArgument = (SCHEMA_ACTION_ARGUMENT_HANDLE_DATA*)actionArgumentHandle;
     if (actionArgument != NULL)
     {
         free((void*)actionArgument->Name);
@@ -91,7 +113,7 @@
 
 static void DestroyAction(SCHEMA_ACTION_HANDLE actionHandle)
 {
-    ACTION* action = (ACTION*)actionHandle;
+    SCHEMA_ACTION_HANDLE_DATA* action = (SCHEMA_ACTION_HANDLE_DATA*)actionHandle;
     if (action != NULL)
     {
         size_t j;
@@ -110,7 +132,7 @@
 static void DestroyStruct(SCHEMA_STRUCT_TYPE_HANDLE structTypeHandle)
 {
     size_t i;
-    STRUCT_TYPE* structType = (STRUCT_TYPE*)structTypeHandle;
+    SCHEMA_STRUCT_TYPE_HANDLE_DATA* structType = (SCHEMA_STRUCT_TYPE_HANDLE_DATA*)structTypeHandle;
     if (structType != NULL)
     {
         for (i = 0; i < structType->PropertyCount; i++)
@@ -127,8 +149,8 @@
 
 static void DestroyModel(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle)
 {
-    MODEL_TYPE* modelType = (MODEL_TYPE*)modelTypeHandle;
-    size_t i;
+    SCHEMA_MODEL_TYPE_HANDLE_DATA* modelType = (SCHEMA_MODEL_TYPE_HANDLE_DATA*)modelTypeHandle;
+    size_t i, nReportedProperties;
 
     free((void*)modelType->Name);
     modelType->Name = NULL;
@@ -151,6 +173,27 @@
         MODEL_IN_MODEL* temp = (MODEL_IN_MODEL*)VECTOR_element(modelType->models, i);
         free((void*)temp->propertyName);
     }
+
+    nReportedProperties = VECTOR_size(modelType->reportedProperties);
+    for (i = 0;i < nReportedProperties;i++)
+    {
+        SCHEMA_REPORTED_PROPERTY_HANDLE_DATA* reportedProperty = *(SCHEMA_REPORTED_PROPERTY_HANDLE_DATA **)VECTOR_element(modelType->reportedProperties, i);
+        free((void*)reportedProperty->reportedPropertyName);
+        free((void*)reportedProperty->reportedPropertyType);
+        free(reportedProperty);
+    }
+    VECTOR_destroy(modelType->reportedProperties);
+
+    size_t nDesiredProperties = VECTOR_size(modelType->desiredProperties);
+    for (i = 0;i < nDesiredProperties;i++)
+    {
+        SCHEMA_DESIRED_PROPERTY_HANDLE_DATA* desiredProperty = *(SCHEMA_DESIRED_PROPERTY_HANDLE_DATA **)VECTOR_element(modelType->desiredProperties, i);
+        free((void*)desiredProperty->desiredPropertyName);
+        free((void*)desiredProperty->desiredPropertyType);
+        free(desiredProperty);
+    }
+    VECTOR_destroy(modelType->desiredProperties);
+
     VECTOR_clear(modelType->models);
     VECTOR_destroy(modelType->models);
 
@@ -158,7 +201,7 @@
     free(modelType);
 }
 
-static SCHEMA_RESULT AddModelProperty(MODEL_TYPE* modelType, const char* name, const char* type)
+static SCHEMA_RESULT AddModelProperty(SCHEMA_MODEL_TYPE_HANDLE_DATA* modelType, const char* name, const char* type)
 {
     SCHEMA_RESULT result;
 
@@ -177,7 +220,7 @@
         /* Codes_SRS_SCHEMA_99_015:[The property name shall be unique per model, if the same property name is added twice to a model, SCHEMA_DUPLICATE_ELEMENT shall be returned.] */
         for (i = 0; i < modelType->PropertyCount; i++)
         {
-            PROPERTY* property = (PROPERTY*)modelType->Properties[i];
+            SCHEMA_PROPERTY_HANDLE_DATA* property = (SCHEMA_PROPERTY_HANDLE_DATA*)modelType->Properties[i];
             if (strcmp(property->PropertyName, name) == 0)
             {
                 break;
@@ -200,10 +243,10 @@
             }
             else
             {
-                PROPERTY* newProperty;
+                SCHEMA_PROPERTY_HANDLE_DATA* newProperty;
 
                 modelType->Properties = newProperties;
-                if ((newProperty = (PROPERTY*)malloc(sizeof(PROPERTY))) == NULL)
+                if ((newProperty = (SCHEMA_PROPERTY_HANDLE_DATA*)malloc(sizeof(SCHEMA_PROPERTY_HANDLE_DATA))) == NULL)
                 {
                     /* Codes_SRS_SCHEMA_99_014:[On any other error, Schema_AddModelProperty shall return SCHEMA_ERROR.] */
                     result = SCHEMA_ERROR;
@@ -264,31 +307,34 @@
 
 static bool SchemaNamespacesMatch(const SCHEMA_HANDLE* handle, const char* schemaNamespace)
 {
-    const SCHEMA* schema = (SCHEMA*)*handle;
+    const SCHEMA_HANDLE_DATA* schema = (SCHEMA_HANDLE_DATA*)*handle;
     return (strcmp(schema->Namespace, schemaNamespace) == 0);
 }
 
 /* Codes_SRS_SCHEMA_99_001:[Schema_Create shall initialize a schema with a given namespace.] */
-SCHEMA_HANDLE Schema_Create(const char* schemaNamespace)
+SCHEMA_HANDLE Schema_Create(const char* schemaNamespace, void* metadata)
 {
-    SCHEMA* result;
-
+    SCHEMA_HANDLE_DATA* result;
+    /*Codes_SRS_SCHEMA_02_090: [ If metadata is NULL then Schema_Create shall fail and return NULL. ]*/
     /* Codes_SRS_SCHEMA_99_004:[If schemaNamespace is NULL, Schema_Create shall fail.] */
-    if (schemaNamespace == NULL)
+    if (
+        (schemaNamespace == NULL)||
+        (metadata == NULL)
+        )
     {
         /* Codes_SRS_SCHEMA_99_003:[On failure, NULL shall be returned.] */
+        LogError("invalid arg const char* schemaNamespace=%p, void* metadata=%p",schemaNamespace, metadata);
         result = NULL;
-        LogError("(Error code:%s)", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_INVALID_ARG));
     }
     else
     {
-        if (g_schemas == NULL && (g_schemas = VECTOR_create(sizeof(SCHEMA*) ) ) == NULL)
+        if (g_schemas == NULL && (g_schemas = VECTOR_create(sizeof(SCHEMA_HANDLE_DATA*) ) ) == NULL)
         {
             /* Codes_SRS_SCHEMA_99_003:[On failure, NULL shall be returned.] */
             result = NULL;
             LogError("(Error code:%s)", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_ERROR));
         }
-        else if ((result = (SCHEMA*)malloc(sizeof(SCHEMA))) == NULL)
+        else if ((result = (SCHEMA_HANDLE_DATA*)malloc(sizeof(SCHEMA_HANDLE_DATA))) == NULL)
         {
             /* Codes_SRS_SCHEMA_99_003:[On failure, NULL shall be returned.] */
             LogError("(Error code:%s)", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_ERROR));
@@ -314,6 +360,7 @@
             result->ModelTypeCount = 0;
             result->StructTypes = NULL;
             result->StructTypeCount = 0;
+            result->metadata = metadata;
         }
     }
 
@@ -359,7 +406,7 @@
     else
     {
         /* Codes_SRS_SCHEMA_99_129: [Schema_GetSchemaNamespace shall return the namespace for the schema identified by schemaHandle.] */
-        result = ((SCHEMA*)schemaHandle)->Namespace;
+        result = ((SCHEMA_HANDLE_DATA*)schemaHandle)->Namespace;
     }
 
     return result;
@@ -370,7 +417,7 @@
     /* Codes_SRS_SCHEMA_99_006:[If the schemaHandle is NULL, Schema_Destroy shall do nothing.] */
     if (schemaHandle != NULL)
     {
-        SCHEMA* schema = (SCHEMA*)schemaHandle;
+        SCHEMA_HANDLE_DATA* schema = (SCHEMA_HANDLE_DATA*)schemaHandle;
         size_t i;
 
         /* Codes_SRS_SCHEMA_99_005:[Schema_Destroy shall free all resources associated with a schema.] */
@@ -391,7 +438,7 @@
         free((void*)schema->Namespace);
         free(schema);
 
-        schema = (SCHEMA*)VECTOR_find_if(g_schemas, (PREDICATE_FUNCTION)SchemaHandlesMatch, &schemaHandle);
+        schema = (SCHEMA_HANDLE_DATA*)VECTOR_find_if(g_schemas, (PREDICATE_FUNCTION)SchemaHandlesMatch, &schemaHandle);
         if (schema != NULL)
         {
             VECTOR_erase(g_schemas, schema, 1);
@@ -419,13 +466,13 @@
         }
         else
         {
-            SCHEMA* schema = (SCHEMA*)schemaHandle;
+            SCHEMA_HANDLE_DATA* schema = (SCHEMA_HANDLE_DATA*)schemaHandle;
             size_t nIndex;
 
             /* Codes_SRS_SCHEMA_07_190: [Schema_DestroyIfUnused shall iterate through the ModuleTypes objects and if all the DeviceCount variables 0 then it will delete the schemaHandle.] */
             for (nIndex = 0; nIndex < schema->ModelTypeCount; nIndex++)
             {
-                MODEL_TYPE* modelType = (MODEL_TYPE*)schema->ModelTypes[nIndex];
+                SCHEMA_MODEL_TYPE_HANDLE_DATA* modelType = (SCHEMA_MODEL_TYPE_HANDLE_DATA*)schema->ModelTypes[nIndex];
                 if (modelType->DeviceCount > 0)
                     break;
             }
@@ -459,8 +506,8 @@
     }
     else
     {
-        MODEL_TYPE* model = (MODEL_TYPE*)modelTypeHandle;
-        /* Codes_SRS_SCHEMA_07_188: [If the modelTypeHandle is nonNULL, Schema_AddDeviceRef shall increment the MODEL_TYPE DeviceCount variable.] */
+        SCHEMA_MODEL_TYPE_HANDLE_DATA* model = (SCHEMA_MODEL_TYPE_HANDLE_DATA*)modelTypeHandle;
+        /* Codes_SRS_SCHEMA_07_188: [If the modelTypeHandle is nonNULL, Schema_AddDeviceRef shall increment the SCHEMA_MODEL_TYPE_HANDLE_DATA DeviceCount variable.] */
         model->DeviceCount++;
         result = SCHEMA_OK;
     }
@@ -478,7 +525,7 @@
     }
     else
     {
-        MODEL_TYPE* model = (MODEL_TYPE*)modelTypeHandle;
+        SCHEMA_MODEL_TYPE_HANDLE_DATA* model = (SCHEMA_MODEL_TYPE_HANDLE_DATA*)modelTypeHandle;
         if (model->DeviceCount > 0)
         {
             /* Codes_SRS_SCHEMA_07_186: [On a nonNULL SCHEMA_MODEL_TYPE_HANDLE if the DeviceCount variable is > 0 then the variable will be decremented.] */
@@ -487,8 +534,8 @@
         }
         else
         {
-            result = SCHEMA_DEVICE_COUNT_ZERO;
-            LogError("(Error code:%s)", ENUM_TO_STRING(SCHEMA_RESULT, result));
+result = SCHEMA_DEVICE_COUNT_ZERO;
+LogError("(Error code:%s)", ENUM_TO_STRING(SCHEMA_RESULT, result));
         }
     }
     return result;
@@ -509,13 +556,13 @@
     }
     else
     {
-        SCHEMA* schema = (SCHEMA*)schemaHandle;
+        SCHEMA_HANDLE_DATA* schema = (SCHEMA_HANDLE_DATA*)schemaHandle;
 
         /* Codes_SRS_SCHEMA_99_100: [Schema_CreateModelType shall return SCHEMA_DUPLICATE_ELEMENT if modelName already exists.] */
         size_t i;
         for (i = 0; i < schema->ModelTypeCount; i++)
         {
-            MODEL_TYPE* model = (MODEL_TYPE*)(schema->ModelTypes[i]);
+            SCHEMA_MODEL_TYPE_HANDLE_DATA* model = (SCHEMA_MODEL_TYPE_HANDLE_DATA*)(schema->ModelTypes[i]);
             if (strcmp(model->Name, modelName) == 0)
             {
                 break;
@@ -540,10 +587,10 @@
             }
             else
             {
-                MODEL_TYPE* modelType;
+                SCHEMA_MODEL_TYPE_HANDLE_DATA* modelType;
                 schema->ModelTypes = newModelTypes;
 
-                if ((modelType = (MODEL_TYPE*)malloc(sizeof(MODEL_TYPE))) == NULL)
+                if ((modelType = (SCHEMA_MODEL_TYPE_HANDLE_DATA*)malloc(sizeof(SCHEMA_MODEL_TYPE_HANDLE_DATA))) == NULL)
                 {
 
                     /* Codes_SRS_SCHEMA_99_009:[On failure, Schema_CreateModelType shall return NULL.] */
@@ -559,27 +606,60 @@
                 }
                 else
                 {
-                    modelType->PropertyCount = 0;
-                    modelType->Properties = NULL;
-                    modelType->ActionCount = 0;
-                    modelType->Actions = NULL;
-                    modelType->SchemaHandle = schemaHandle;
-                    modelType->DeviceCount = 0;
-                    modelType->models = VECTOR_create(sizeof(MODEL_IN_MODEL) );
-                    schema->ModelTypes[schema->ModelTypeCount] = modelType;
-                    schema->ModelTypeCount++;
+                    modelType->models = VECTOR_create(sizeof(MODEL_IN_MODEL));
+                    if (modelType->models == NULL)
+                    {
+                        LogError("unable to VECTOR_create");
+                        free((void*)modelType->Name);
+                        free((void*)modelType);
+                        result = NULL;
+                    }
+                    else
+                    {
+                        if ((modelType->reportedProperties = VECTOR_create(sizeof(SCHEMA_REPORTED_PROPERTY_HANDLE))) == NULL)
+                        {
+                            LogError("failed to VECTOR_create (reported properties)");
+                            VECTOR_destroy(modelType->models);
+                            free((void*)modelType->Name);
+                            free((void*)modelType);
+                            result = NULL;
 
-                    /* Codes_SRS_SCHEMA_99_008:[On success, a non-NULL handle shall be returned.] */
-                    result = (SCHEMA_MODEL_TYPE_HANDLE)modelType;
+                        }
+                        else
+                        {
+                            if ((modelType->desiredProperties = VECTOR_create(sizeof(SCHEMA_DESIRED_PROPERTY_HANDLE))) == NULL)
+                            {
+                                LogError("failure in VECTOR_create (desired properties)");
+                                VECTOR_destroy(modelType->reportedProperties);
+                                VECTOR_destroy(modelType->models);
+                                free((void*)modelType->Name);
+                                free((void*)modelType);
+                                result = NULL;
+                            }
+                            else
+                            {
+                                modelType->PropertyCount = 0;
+                                modelType->Properties = NULL;
+                                modelType->ActionCount = 0;
+                                modelType->Actions = NULL;
+                                modelType->SchemaHandle = schemaHandle;
+                                modelType->DeviceCount = 0;
+
+                                schema->ModelTypes[schema->ModelTypeCount] = modelType;
+                                schema->ModelTypeCount++;
+                                /* Codes_SRS_SCHEMA_99_008:[On success, a non-NULL handle shall be returned.] */
+                                result = (SCHEMA_MODEL_TYPE_HANDLE)modelType;
+                            }
+                        }
+                    }
                 }
 
                 /* If possible, reduce the memory of over allocation */
-                if (result == NULL)
+                if ((result == NULL) &&(schema->ModelTypeCount>0))
                 {
                     SCHEMA_MODEL_TYPE_HANDLE* oldModelTypes = (SCHEMA_MODEL_TYPE_HANDLE*)realloc(schema->ModelTypes, sizeof(SCHEMA_MODEL_TYPE_HANDLE) * schema->ModelTypeCount);
                     if (oldModelTypes == NULL)
                     {
-                        result = NULL;
                         LogError("(Error code:%s)", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_ERROR));
                     }
                     else
@@ -606,7 +686,7 @@
     else
     {
         /* Codes_SRS_SCHEMA_99_131: [Schema_GetSchemaForModelType returns the schema handle for a given model type.] */
-        result = ((MODEL_TYPE*)modelTypeHandle)->SchemaHandle;
+        result = ((SCHEMA_MODEL_TYPE_HANDLE_DATA*)modelTypeHandle)->SchemaHandle;
     }
 
     return result;
@@ -615,7 +695,90 @@
 /* Codes_SRS_SCHEMA_99_011:[Schema_AddModelProperty shall add one property to the model type identified by modelTypeHandle.] */
 SCHEMA_RESULT Schema_AddModelProperty(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, const char* propertyName, const char* propertyType)
 {
-    return AddModelProperty((MODEL_TYPE*)modelTypeHandle, propertyName, propertyType);
+    return AddModelProperty((SCHEMA_MODEL_TYPE_HANDLE_DATA*)modelTypeHandle, propertyName, propertyType);
+}
+
+static bool reportedPropertyExists(const void* element, const void* value)
+{
+    SCHEMA_REPORTED_PROPERTY_HANDLE_DATA* reportedProperty = *(SCHEMA_REPORTED_PROPERTY_HANDLE_DATA**)element;
+    return (strcmp(reportedProperty->reportedPropertyName, value) == 0);
+}
+
+SCHEMA_RESULT Schema_AddModelReportedProperty(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, const char* reportedPropertyName, const char* reportedPropertyType)
+{
+    SCHEMA_RESULT result;
+    /*Codes_SRS_SCHEMA_02_001: [ If modelTypeHandle is NULL then Schema_AddModelReportedProperty shall fail and return SCHEMA_INVALID_ARG. ]*/
+    /*Codes_SRS_SCHEMA_02_002: [ If reportedPropertyName is NULL then Schema_AddModelReportedProperty shall fail and return SCHEMA_INVALID_ARG. ]*/
+    /*Codes_SRS_SCHEMA_02_003: [ If reportedPropertyType is NULL then Schema_AddModelReportedProperty shall fail and return SCHEMA_INVALID_ARG. ]*/
+    if (
+        (modelTypeHandle == NULL) ||
+        (reportedPropertyName == NULL) ||
+        (reportedPropertyType == NULL)
+        )
+    {
+        LogError("invalid argument SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle=%p, const char* reportedPropertyName=%p, const char* reportedPropertyType=%p", modelTypeHandle, reportedPropertyName, reportedPropertyType);
+        result = SCHEMA_INVALID_ARG;
+    }
+    else
+    {
+        SCHEMA_MODEL_TYPE_HANDLE_DATA* modelType = (SCHEMA_MODEL_TYPE_HANDLE_DATA*)modelTypeHandle;
+        /*Codes_SRS_SCHEMA_02_004: [ If reportedPropertyName has already been added then Schema_AddModelReportedProperty shall fail and return SCHEMA_PROPERTY_ELEMENT_EXISTS. ]*/
+        if (VECTOR_find_if(modelType->reportedProperties, reportedPropertyExists, reportedPropertyName) != NULL)
+        {
+            LogError("unable to add reportedProperty %s because it already exists", reportedPropertyName);
+            result = SCHEMA_DUPLICATE_ELEMENT;
+        }
+        else
+        {
+            /*Codes_SRS_SCHEMA_02_005: [ Schema_AddModelReportedProperty shall record reportedPropertyName and reportedPropertyType. ]*/
+            SCHEMA_REPORTED_PROPERTY_HANDLE_DATA* reportedProperty = (SCHEMA_REPORTED_PROPERTY_HANDLE_DATA*)malloc(sizeof(SCHEMA_REPORTED_PROPERTY_HANDLE_DATA));
+            if (reportedProperty == NULL)
+            {
+                /*Codes_SRS_SCHEMA_02_006: [ If any error occurs then Schema_AddModelReportedProperty shall fail and return SCHEMA_ERROR. ]*/
+                LogError("unable to malloc");
+                result = SCHEMA_ERROR;
+            }
+            else
+            {
+                if (mallocAndStrcpy_s((char**)&reportedProperty->reportedPropertyName, reportedPropertyName) != 0)
+                {
+                    /*Codes_SRS_SCHEMA_02_006: [ If any error occurs then Schema_AddModelReportedProperty shall fail and return SCHEMA_ERROR. ]*/
+                    LogError("unable to mallocAndStrcpy_s");
+                    free(reportedProperty);
+                    result = SCHEMA_ERROR;
+                }
+                else
+                {
+                    if (mallocAndStrcpy_s((char**)&reportedProperty->reportedPropertyType, reportedPropertyType) != 0)
+                    {
+                        /*Codes_SRS_SCHEMA_02_006: [ If any error occurs then Schema_AddModelReportedProperty shall fail and return SCHEMA_ERROR. ]*/
+                        LogError("unable to mallocAndStrcpy_s");
+                        free((void*)reportedProperty->reportedPropertyName);
+                        free(reportedProperty);
+                        result = SCHEMA_ERROR;
+                    }
+                    else
+                    {
+                        if (VECTOR_push_back(modelType->reportedProperties, &reportedProperty, 1) != 0)
+                        {
+                            /*Codes_SRS_SCHEMA_02_006: [ If any error occurs then Schema_AddModelReportedProperty shall fail and return SCHEMA_ERROR. ]*/
+                            LogError("unable to VECTOR_push_back");
+                            free((void*)reportedProperty->reportedPropertyType);
+                            free((void*)reportedProperty->reportedPropertyName);
+                            free(reportedProperty);
+                            result = SCHEMA_ERROR;
+                        }
+                        else
+                        {
+                            /*Codes_SRS_SCHEMA_02_007: [ Otherwise Schema_AddModelReportedProperty shall succeed and return SCHEMA_OK. ]*/
+                            result = SCHEMA_OK;
+                        }
+                    }
+                }
+            }
+        }
+    }
+    return result;
 }
 
 SCHEMA_ACTION_HANDLE Schema_CreateModelAction(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, const char* actionName)
@@ -631,13 +794,13 @@
     }
     else
     {
-        MODEL_TYPE* modelType = (MODEL_TYPE*)modelTypeHandle;
+        SCHEMA_MODEL_TYPE_HANDLE_DATA* modelType = (SCHEMA_MODEL_TYPE_HANDLE_DATA*)modelTypeHandle;
         size_t i;
 
         /* Codes_SRS_SCHEMA_99_105: [The action name shall be unique per model, if the same action name is added twice to a model, Schema_CreateModelAction shall return NULL.] */
         for (i = 0; i < modelType->ActionCount; i++)
         {
-            ACTION* action = (ACTION*)modelType->Actions[i];
+            SCHEMA_ACTION_HANDLE_DATA* action = (SCHEMA_ACTION_HANDLE_DATA*)modelType->Actions[i];
             if (strcmp(action->ActionName, actionName) == 0)
             {
                 break;
@@ -661,11 +824,11 @@
             }
             else
             {
-                ACTION* newAction;
+                SCHEMA_ACTION_HANDLE_DATA* newAction;
                 modelType->Actions = newActions;
 
                 /* Codes_SRS_SCHEMA_99_103: [On success, Schema_CreateModelAction shall return a none-NULL SCHEMA_ACTION_HANDLE to the newly created action.] */
-                if ((newAction = (ACTION*)malloc(sizeof(ACTION))) == NULL)
+                if ((newAction = (SCHEMA_ACTION_HANDLE_DATA*)malloc(sizeof(SCHEMA_ACTION_HANDLE_DATA))) == NULL)
                 {
                     /* Codes_SRS_SCHEMA_99_106: [On any other error, Schema_CreateModelAction shall return NULL.]*/
                     result = NULL;
@@ -724,14 +887,14 @@
     }
     else
     {
-        ACTION* action = (ACTION*)actionHandle;
+        SCHEMA_ACTION_HANDLE_DATA* action = (SCHEMA_ACTION_HANDLE_DATA*)actionHandle;
 
         /* Codes_SRS_SCHEMA_99_110: [The argument name shall be unique per action, if the same name is added twice to an action, SCHEMA_DUPLICATE_ELEMENT shall be returned.] */
         /* Codes_SRS_SCHEMA_99_111: [Schema_AddModelActionArgument shall accept arguments with different names of the same type.]  */
         size_t i;
         for (i = 0; i < action->ArgumentCount; i++)
         {
-            SCHEMA_ACTION_ARGUMENT* actionArgument = (SCHEMA_ACTION_ARGUMENT*)action->ArgumentHandles[i];
+            SCHEMA_ACTION_ARGUMENT_HANDLE_DATA* actionArgument = (SCHEMA_ACTION_ARGUMENT_HANDLE_DATA*)action->ArgumentHandles[i];
             if (strcmp((actionArgument->Name), argumentName) == 0)
             {
                 break;
@@ -755,8 +918,8 @@
             }
             else
             {
-                SCHEMA_ACTION_ARGUMENT* newActionArgument;
-                if ((newActionArgument = (SCHEMA_ACTION_ARGUMENT*)malloc(sizeof(SCHEMA_ACTION_ARGUMENT))) == NULL)
+                SCHEMA_ACTION_ARGUMENT_HANDLE_DATA* newActionArgument;
+                if ((newActionArgument = (SCHEMA_ACTION_ARGUMENT_HANDLE_DATA*)malloc(sizeof(SCHEMA_ACTION_ARGUMENT_HANDLE_DATA))) == NULL)
                 {
                     /* Codes_SRS_SCHEMA_99_112: [On any other error, Schema_ AddModelActionArgumet shall return SCHEMA_ERROR.] */
                     result = SCHEMA_ERROR;
@@ -824,12 +987,12 @@
     else
     {
         size_t i;
-        MODEL_TYPE* modelType = (MODEL_TYPE*)modelTypeHandle;
+        SCHEMA_MODEL_TYPE_HANDLE_DATA* modelType = (SCHEMA_MODEL_TYPE_HANDLE_DATA*)modelTypeHandle;
 
         /* Codes_SRS_SCHEMA_99_036:[Schema_GetModelPropertyByName shall return a non-NULL SCHEMA_PROPERTY_HANDLE corresponding to the model type identified by modelTypeHandle and matching the propertyName argument value.] */
         for (i = 0; i < modelType->PropertyCount; i++)
         {
-            PROPERTY* modelProperty = (PROPERTY*)modelType->Properties[i];
+            SCHEMA_PROPERTY_HANDLE_DATA* modelProperty = (SCHEMA_PROPERTY_HANDLE_DATA*)modelType->Properties[i];
             if (strcmp(modelProperty->PropertyName, propertyName) == 0)
             {
                 break;
@@ -864,7 +1027,7 @@
     else
     {
         /* Codes_SRS_SCHEMA_99_089: [Schema_GetModelPropertyCount shall provide the number of properties defined in the model type identified by modelTypeHandle.] */
-        MODEL_TYPE* modelType = (MODEL_TYPE*)modelTypeHandle;
+        SCHEMA_MODEL_TYPE_HANDLE_DATA* modelType = (SCHEMA_MODEL_TYPE_HANDLE_DATA*)modelTypeHandle;
 
         /* Codes_SRS_SCHEMA_99_090: [The count shall be provided via the out argument propertyCount.]*/
         *propertyCount = modelType->PropertyCount;
@@ -876,10 +1039,90 @@
     return result;
 }
 
+SCHEMA_RESULT Schema_GetModelReportedPropertyCount(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, size_t* reportedPropertyCount)
+{
+    SCHEMA_RESULT result;
+    /*Codes_SRS_SCHEMA_02_008: [ If parameter modelTypeHandle is NULL then Schema_GetModelReportedPropertyCount shall fail and return SCHEMA_INVALID_ARG. ]*/
+    /*Codes_SRS_SCHEMA_02_009: [ If parameter reportedPropertyCount is NULL then Schema_GetModelReportedPropertyCount shall fail and return SCHEMA_INVALID_ARG. ]*/
+    if (
+        (modelTypeHandle == NULL)||
+        (reportedPropertyCount==NULL)
+        )
+    {
+        LogError("SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle=%p, size_t* reportedPropertyCount=%p", modelTypeHandle, reportedPropertyCount);
+        result = SCHEMA_INVALID_ARG;
+    }
+    else
+    {
+        /*Codes_SRS_SCHEMA_02_010: [ Schema_GetModelReportedPropertyCount shall provide in reportedPropertyCount the number of reported properties and return SCHEMA_OK. ]*/
+        SCHEMA_MODEL_TYPE_HANDLE_DATA* modelType = (SCHEMA_MODEL_TYPE_HANDLE_DATA*)modelTypeHandle;
+        *reportedPropertyCount = VECTOR_size(modelType->reportedProperties);
+        result = SCHEMA_OK;
+    }
+    return result;
+}
+
+SCHEMA_REPORTED_PROPERTY_HANDLE Schema_GetModelReportedPropertyByName(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, const char* reportedPropertyName)
+{
+    SCHEMA_REPORTED_PROPERTY_HANDLE result;
+    /*Codes_SRS_SCHEMA_02_011: [ If argument modelTypeHandle is NULL then Schema_GetModelReportedPropertyByName shall fail and return NULL. ]*/
+    /*Codes_SRS_SCHEMA_02_012: [ If argument reportedPropertyName is NULL then Schema_GetModelReportedPropertyByName shall fail and return NULL. ]*/
+    if(
+        (modelTypeHandle == NULL) ||
+        (reportedPropertyName == NULL)
+        )
+    {
+        LogError("invalid argument SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle=%p, const char* reportedPropertyName=%p", modelTypeHandle, reportedPropertyName);
+        result = NULL;
+    }
+    else
+    {
+        SCHEMA_MODEL_TYPE_HANDLE_DATA* modelType = (SCHEMA_MODEL_TYPE_HANDLE_DATA*)modelTypeHandle;
+        /*Codes_SRS_SCHEMA_02_013: [ If reported property by the name reportedPropertyName exists then Schema_GetModelReportedPropertyByName shall succeed and return a non-NULL value. ]*/
+        /*Codes_SRS_SCHEMA_02_014: [ Otherwise Schema_GetModelReportedPropertyByName shall fail and return NULL. ]*/
+        if((result = VECTOR_find_if(modelType->reportedProperties, reportedPropertyExists, reportedPropertyName))==NULL)
+        {
+            LogError("a reported property with name \"%s\" does not exist", reportedPropertyName);
+        }
+        else
+        {
+            /*return as is*/
+        }
+    }
+    return result;
+}
+
+SCHEMA_REPORTED_PROPERTY_HANDLE Schema_GetModelReportedPropertyByIndex(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, size_t index)
+{
+    SCHEMA_REPORTED_PROPERTY_HANDLE result;
+    /*Codes_SRS_SCHEMA_02_015: [ If argument modelTypeHandle is NULL then Schema_GetModelReportedPropertyByIndex shall fail and return NULL. ]*/
+    if (modelTypeHandle == NULL)
+    {
+        LogError("invalid argument SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle=%p, size_t index=%zu", modelTypeHandle, index);
+        result = NULL;
+    }
+    else
+    {
+        SCHEMA_MODEL_TYPE_HANDLE_DATA* modelType = (SCHEMA_MODEL_TYPE_HANDLE_DATA*)modelTypeHandle;
+
+        /*Codes_SRS_SCHEMA_02_016: [ If a reported property with index equal to index exists then Schema_GetModelReportedPropertyByIndex shall succeed and return the non-NULL handle of that REPORTED_PROPERTY. ]*/
+        /*Codes_SRS_SCHEMA_02_017: [ Otherwise Schema_GetModelReportedPropertyByIndex shall fail and return NULL. ]*/
+        if ((result = VECTOR_element(modelType->reportedProperties, index)) == NULL)
+        {
+            LogError("index %zu is invalid", index);
+        }
+        else
+        {
+            /*return as is*/
+        }
+    }
+    return result;
+}
+
 SCHEMA_PROPERTY_HANDLE Schema_GetModelPropertyByIndex(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, size_t index)
 {
     SCHEMA_PROPERTY_HANDLE result;
-    MODEL_TYPE* modelType = (MODEL_TYPE*)modelTypeHandle;
+    SCHEMA_MODEL_TYPE_HANDLE_DATA* modelType = (SCHEMA_MODEL_TYPE_HANDLE_DATA*)modelTypeHandle;
 
     /* Codes_SRS_SCHEMA_99_094: [Schema_GetModelProperty shall return NULL if the index specified is outside the valid range or if modelTypeHandle argument is NULL.] */
     if ((modelTypeHandle == NULL) ||
@@ -912,12 +1155,12 @@
     else
     {
         size_t i;
-        MODEL_TYPE* modelType = (MODEL_TYPE*)modelTypeHandle;
+        SCHEMA_MODEL_TYPE_HANDLE_DATA* modelType = (SCHEMA_MODEL_TYPE_HANDLE_DATA*)modelTypeHandle;
 
         /* Codes_SRS_SCHEMA_99_040:[Schema_GetModelActionByName shall return a non-NULL SCHEMA_ACTION_HANDLE corresponding to the model type identified by modelTypeHandle and matching the actionName argument value.] */
         for (i = 0; i < modelType->ActionCount; i++)
         {
-            ACTION* modelAction = (ACTION*)modelType->Actions[i];
+            SCHEMA_ACTION_HANDLE_DATA* modelAction = (SCHEMA_ACTION_HANDLE_DATA*)modelType->Actions[i];
             if (strcmp(modelAction->ActionName, actionName) == 0)
             {
                 break;
@@ -953,7 +1196,7 @@
     else
     {
         /* Codes_SRS_SCHEMA_99_042:[Schema_GetModelActionCount shall provide the total number of actions defined in a model type identified by the modelTypeHandle.] */
-        MODEL_TYPE* modelType = (MODEL_TYPE*)modelTypeHandle;
+        SCHEMA_MODEL_TYPE_HANDLE_DATA* modelType = (SCHEMA_MODEL_TYPE_HANDLE_DATA*)modelTypeHandle;
 
         /* Codes_SRS_SCHEMA_99_043:[The count shall be provided via the out argument actionCount.] */
         *actionCount = modelType->ActionCount;
@@ -968,7 +1211,7 @@
 SCHEMA_ACTION_HANDLE Schema_GetModelActionByIndex(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, size_t index)
 {
     SCHEMA_ACTION_HANDLE result;
-    MODEL_TYPE* modelType = (MODEL_TYPE*)modelTypeHandle;
+    SCHEMA_MODEL_TYPE_HANDLE_DATA* modelType = (SCHEMA_MODEL_TYPE_HANDLE_DATA*)modelTypeHandle;
 
     /* Codes_SRS_SCHEMA_99_048:[Schema_GetModelAction shall return NULL if the index specified is outside the valid range or if modelTypeHandle argument is NULL.] */
     if ((modelType == NULL) ||
@@ -999,7 +1242,7 @@
     }
     else
     {
-        ACTION* action = (ACTION*)actionHandle;
+        SCHEMA_ACTION_HANDLE_DATA* action = (SCHEMA_ACTION_HANDLE_DATA*)actionHandle;
         /* Codes_SRS_SCHEMA_99_049:[Schema_GetModelActionName shall return the action name for a given action handle.] */
         result = action->ActionName;
     }
@@ -1020,7 +1263,7 @@
     }
     else
     {
-        ACTION* modelAction = (ACTION*)actionHandle;
+        SCHEMA_ACTION_HANDLE_DATA* modelAction = (SCHEMA_ACTION_HANDLE_DATA*)actionHandle;
 
         /* Codes_SRS_SCHEMA_99_051:[Schema_GetModelActionArgumentCount shall provide the number of arguments for a specific schema action identified by actionHandle.] */
         /* Codes_SRS_SCHEMA_99_052:[The argument count shall be provided via the out argument argumentCount.] */
@@ -1047,12 +1290,12 @@
     else
     {
         /* Codes_SRS_SCHEMA_99_118: [Schema_GetModelActionArgumentByName shall return NULL if unable to find a matching argument or if any of the arguments are NULL.] */
-        ACTION* modelAction = (ACTION*)actionHandle;
+        SCHEMA_ACTION_HANDLE_DATA* modelAction = (SCHEMA_ACTION_HANDLE_DATA*)actionHandle;
         size_t i;
 
         for (i = 0; i < modelAction->ArgumentCount; i++)
         {
-            SCHEMA_ACTION_ARGUMENT* actionArgument = (SCHEMA_ACTION_ARGUMENT*)modelAction->ArgumentHandles[i];
+            SCHEMA_ACTION_ARGUMENT_HANDLE_DATA* actionArgument = (SCHEMA_ACTION_ARGUMENT_HANDLE_DATA*)modelAction->ArgumentHandles[i];
             if (strcmp(actionArgument->Name, actionArgumentName) == 0)
             {
                 break;
@@ -1078,7 +1321,7 @@
 SCHEMA_ACTION_ARGUMENT_HANDLE Schema_GetModelActionArgumentByIndex(SCHEMA_ACTION_HANDLE actionHandle, size_t argumentIndex)
 {
     SCHEMA_ACTION_ARGUMENT_HANDLE result;
-    ACTION* modelAction = (ACTION*)actionHandle;
+    SCHEMA_ACTION_HANDLE_DATA* modelAction = (SCHEMA_ACTION_HANDLE_DATA*)actionHandle;
 
     /* Codes_SRS_SCHEMA_99_056:[Schema_GetModelActionArgument shall return NULL if the index specified is outside the valid range or if the actionHandle argument is NULL.] */
     if ((actionHandle == NULL) ||
@@ -1108,7 +1351,7 @@
     else
     {
         /* Codes_SRS_SCHEMA_99_113: [Schema_GetActionArgumentName shall return the argument name identified by the actionArgumentHandle.] */
-        SCHEMA_ACTION_ARGUMENT* actionArgument = (SCHEMA_ACTION_ARGUMENT*)actionArgumentHandle;
+        SCHEMA_ACTION_ARGUMENT_HANDLE_DATA* actionArgument = (SCHEMA_ACTION_ARGUMENT_HANDLE_DATA*)actionArgumentHandle;
         result = actionArgument->Name;
     }
     return result;
@@ -1126,7 +1369,7 @@
     else
     {
         /* Codes_SRS_SCHEMA_99_115: [Schema_GetActionArgumentType shall return the argument type identified by the actionArgumentHandle.] */
-        SCHEMA_ACTION_ARGUMENT* actionArgument = (SCHEMA_ACTION_ARGUMENT*)actionArgumentHandle;
+        SCHEMA_ACTION_ARGUMENT_HANDLE_DATA* actionArgument = (SCHEMA_ACTION_ARGUMENT_HANDLE_DATA*)actionArgumentHandle;
         result = actionArgument->Type;
     }
     return result;
@@ -1135,7 +1378,7 @@
 SCHEMA_STRUCT_TYPE_HANDLE Schema_CreateStructType(SCHEMA_HANDLE schemaHandle, const char* typeName)
 {
     SCHEMA_STRUCT_TYPE_HANDLE result;
-    SCHEMA* schema = (SCHEMA*)schemaHandle;
+    SCHEMA_HANDLE_DATA* schema = (SCHEMA_HANDLE_DATA*)schemaHandle;
 
     /* Codes_SRS_SCHEMA_99_060:[If any of the arguments is NULL, Schema_CreateStructType shall return NULL.] */
     if ((schema == NULL) ||
@@ -1146,13 +1389,13 @@
     }
     else
     {
-        STRUCT_TYPE* structType;
+        SCHEMA_STRUCT_TYPE_HANDLE_DATA* structType;
         size_t i;
 
         /* Codes_SRS_SCHEMA_99_061:[If a struct type with the same name already exists, Schema_CreateStructType shall return NULL.] */
         for (i = 0; i < schema->StructTypeCount; i++)
         {
-            structType = (STRUCT_TYPE*)schema->StructTypes[i];
+            structType = (SCHEMA_STRUCT_TYPE_HANDLE_DATA*)schema->StructTypes[i];
             if (strcmp(structType->Name, typeName) == 0)
             {
                 break;
@@ -1176,7 +1419,7 @@
             else
             {
                 schema->StructTypes = newStructTypes;
-                if ((structType = (STRUCT_TYPE*)malloc(sizeof(STRUCT_TYPE))) == NULL)
+                if ((structType = (SCHEMA_STRUCT_TYPE_HANDLE_DATA*)malloc(sizeof(SCHEMA_STRUCT_TYPE_HANDLE_DATA))) == NULL)
                 {
                     /* Codes_SRS_SCHEMA_99_066:[On any other error, Schema_CreateStructType shall return NULL.] */
                     result = NULL;
@@ -1235,7 +1478,7 @@
     else
     {
         /* Codes_SRS_SCHEMA_99_135: [Schema_GetStructTypeName shall return the name of a struct type identified by the structTypeHandle argument.] */
-        result = ((STRUCT_TYPE*)structTypeHandle)->Name;
+        result = ((SCHEMA_STRUCT_TYPE_HANDLE_DATA*)structTypeHandle)->Name;
     }
     
     return result;
@@ -1255,7 +1498,7 @@
     else
     {
         /* Codes_SRS_SCHEMA_99_137: [Schema_GetStructTypeCount shall provide the number of structs defined in the schema identified by schemaHandle.] */
-        SCHEMA* schema = (SCHEMA*)schemaHandle;
+        SCHEMA_HANDLE_DATA* schema = (SCHEMA_HANDLE_DATA*)schemaHandle;
         /* Codes_SRS_SCHEMA_99_138: [The count shall be provided via the out argument structTypeCount.] */
         *structTypeCount = schema->StructTypeCount;
         /* Codes_SRS_SCHEMA_99_139: [On success, Schema_GetStructTypeCount shall return SCHEMA_OK.] */
@@ -1267,8 +1510,8 @@
 
 SCHEMA_STRUCT_TYPE_HANDLE Schema_GetStructTypeByName(SCHEMA_HANDLE schemaHandle, const char* name)
 {
-    SCHEMA_ACTION_HANDLE result;
-    SCHEMA* schema = (SCHEMA*)schemaHandle;
+    SCHEMA_STRUCT_TYPE_HANDLE result;
+    SCHEMA_HANDLE_DATA* schema = (SCHEMA_HANDLE_DATA*)schemaHandle;
 
     /* Codes_SRS_SCHEMA_99_069:[Schema_GetStructTypeByName shall return NULL if unable to find a matching struct or if any of the arguments are NULL.] */
     if ((schemaHandle == NULL) ||
@@ -1284,7 +1527,7 @@
         /* Codes_SRS_SCHEMA_99_068:[Schema_GetStructTypeByName shall return a non-NULL handle corresponding to the struct type identified by the structTypeName in the schemaHandle schema.] */
         for (i = 0; i < schema->StructTypeCount; i++)
         {
-            STRUCT_TYPE* structType = (STRUCT_TYPE*)schema->StructTypes[i];
+            SCHEMA_STRUCT_TYPE_HANDLE_DATA* structType = (SCHEMA_STRUCT_TYPE_HANDLE_DATA*)schema->StructTypes[i];
             if (strcmp(structType->Name, name) == 0)
             {
                 break;
@@ -1309,7 +1552,7 @@
 SCHEMA_STRUCT_TYPE_HANDLE Schema_GetStructTypeByIndex(SCHEMA_HANDLE schemaHandle, size_t index)
 {
     SCHEMA_STRUCT_TYPE_HANDLE result;
-    SCHEMA* schema = (SCHEMA*)schemaHandle;
+    SCHEMA_HANDLE_DATA* schema = (SCHEMA_HANDLE_DATA*)schemaHandle;
 
     /* Codes_SRS_SCHEMA_99_143: [Schema_GetStructTypeByIndex shall return NULL if the index specified is outside the valid range or if schemaHandle argument is NULL.] */
     /* Codes_SRS_SCHEMA_99_142: [The index argument is zero based, and the order in which models were added shall be the index in which they will be retrieved.] */
@@ -1344,12 +1587,12 @@
     else
     {
         size_t i;
-        STRUCT_TYPE* structType = (STRUCT_TYPE*)structTypeHandle;
+        SCHEMA_STRUCT_TYPE_HANDLE_DATA* structType = (SCHEMA_STRUCT_TYPE_HANDLE_DATA*)structTypeHandle;
 
         /* Codes_SRS_SCHEMA_99_074:[The property name shall be unique per struct type, if the same property name is added twice to a struct type, SCHEMA_DUPLICATE_ELEMENT shall be returned.] */
         for (i = 0; i < structType->PropertyCount; i++)
         {
-            PROPERTY* property = (PROPERTY*)structType->Properties[i];
+            SCHEMA_PROPERTY_HANDLE_DATA* property = (SCHEMA_PROPERTY_HANDLE_DATA*)structType->Properties[i];
             if (strcmp(property->PropertyName, propertyName) == 0)
             {
                 break;
@@ -1371,10 +1614,10 @@
             }
             else
             {
-                PROPERTY* newProperty;
+                SCHEMA_PROPERTY_HANDLE_DATA* newProperty;
 
                 structType->Properties = newProperties;
-                if ((newProperty = (PROPERTY*)malloc(sizeof(PROPERTY))) == NULL)
+                if ((newProperty = (SCHEMA_PROPERTY_HANDLE_DATA*)malloc(sizeof(SCHEMA_PROPERTY_HANDLE_DATA))) == NULL)
                 {
                     result = SCHEMA_ERROR;
                     LogError("(result = %s)", ENUM_TO_STRING(SCHEMA_RESULT, result));
@@ -1440,11 +1683,11 @@
     else
     {
         size_t i;
-        STRUCT_TYPE* structType = (STRUCT_TYPE*)structTypeHandle;
+        SCHEMA_STRUCT_TYPE_HANDLE_DATA* structType = (SCHEMA_STRUCT_TYPE_HANDLE_DATA*)structTypeHandle;
 
         for (i = 0; i < structType->PropertyCount; i++)
         {
-            PROPERTY* modelProperty = (PROPERTY*)structType->Properties[i];
+            SCHEMA_PROPERTY_HANDLE_DATA* modelProperty = (SCHEMA_PROPERTY_HANDLE_DATA*)structType->Properties[i];
             if (strcmp(modelProperty->PropertyName, propertyName) == 0)
             {
                 break;
@@ -1480,7 +1723,7 @@
     }
     else
     {
-        STRUCT_TYPE* structType = (STRUCT_TYPE*)structTypeHandle;
+        SCHEMA_STRUCT_TYPE_HANDLE_DATA* structType = (SCHEMA_STRUCT_TYPE_HANDLE_DATA*)structTypeHandle;
 
         /* Codes_SRS_SCHEMA_99_077: [Schema_GetStructTypePropertyCount shall provide the total number of properties defined in a struct type identified by structTypeHandle. The value is provided via the out argument propertyCount.] */
         /* Codes_SRS_SCHEMA_99_081: [The count shall be provided via the out argument propertyCount.] */
@@ -1496,7 +1739,7 @@
 SCHEMA_PROPERTY_HANDLE Schema_GetStructTypePropertyByIndex(SCHEMA_STRUCT_TYPE_HANDLE structTypeHandle, size_t index)
 {
     SCHEMA_PROPERTY_HANDLE result;
-    STRUCT_TYPE* structType = (STRUCT_TYPE*)structTypeHandle;
+    SCHEMA_STRUCT_TYPE_HANDLE_DATA* structType = (SCHEMA_STRUCT_TYPE_HANDLE_DATA*)structTypeHandle;
 
     /* Codes_SRS_SCHEMA_99_083: [Schema_ GetStructTypeProperty shall return NULL if the index specified is outside the valid range, if structTypeHandle argument is NULL] */
     if ((structTypeHandle == NULL) ||
@@ -1527,7 +1770,7 @@
     }
     else
     {
-        PROPERTY* propertyType = (PROPERTY*)propertyHandle;
+        SCHEMA_PROPERTY_HANDLE_DATA* propertyType = (SCHEMA_PROPERTY_HANDLE_DATA*)propertyHandle;
 
         /* Codes_SRS_SCHEMA_99_085: [Schema_GetPropertyName shall return the property name identified by the propertyHandle.] */
         result = propertyType->PropertyName;
@@ -1548,7 +1791,7 @@
     }
     else
     {
-        PROPERTY* modelProperty = (PROPERTY*)propertyHandle;
+        SCHEMA_PROPERTY_HANDLE_DATA* modelProperty = (SCHEMA_PROPERTY_HANDLE_DATA*)propertyHandle;
 
         /* Codes_SRS_SCHEMA_99_087: [Schema_GetPropertyType shall return the property type identified by the propertyHandle.] */
         result = modelProperty->PropertyType;
@@ -1570,7 +1813,7 @@
     else
     {
         /* Codes_SRS_SCHEMA_99_120: [Schema_GetModelCount shall provide the number of models defined in the schema identified by schemaHandle.] */
-        SCHEMA* schema = (SCHEMA*)schemaHandle;
+        SCHEMA_HANDLE_DATA* schema = (SCHEMA_HANDLE_DATA*)schemaHandle;
         /* Codes_SRS_SCHEMA_99_121: [The count shall be provided via the out argument modelCount.] */
         *modelCount = schema->ModelTypeCount;
         /* Codes_SRS_SCHEMA_99_122: [On success, Schema_GetModelCount shall return SCHEMA_OK.] */
@@ -1593,11 +1836,11 @@
     else
     {
         /* Codes_SRS_SCHEMA_99_124: [Schema_GetModelByName shall return a non-NULL SCHEMA_MODEL_TYPE_HANDLE corresponding to the model identified by schemaHandle and matching the modelName argument value.] */
-        SCHEMA* schema = (SCHEMA*)schemaHandle;
+        SCHEMA_HANDLE_DATA* schema = (SCHEMA_HANDLE_DATA*)schemaHandle;
         size_t i;
         for (i = 0; i < schema->ModelTypeCount; i++)
         {
-            MODEL_TYPE* modelType = (MODEL_TYPE*)schema->ModelTypes[i];
+            SCHEMA_MODEL_TYPE_HANDLE_DATA* modelType = (SCHEMA_MODEL_TYPE_HANDLE_DATA*)schema->ModelTypes[i];
             if (strcmp(modelName, modelType->Name)==0)
             {
                 break;
@@ -1619,7 +1862,7 @@
 SCHEMA_MODEL_TYPE_HANDLE Schema_GetModelByIndex(SCHEMA_HANDLE schemaHandle, size_t index)
 {
     SCHEMA_MODEL_TYPE_HANDLE result;
-    SCHEMA* schema = (SCHEMA*)schemaHandle;
+    SCHEMA_HANDLE_DATA* schema = (SCHEMA_HANDLE_DATA*)schemaHandle;
 
     /* Codes_SRS_SCHEMA_99_128: [Schema_GetModelByIndex shall return NULL if the index specified is outside the valid range or if schemaHandle argument is NULL.] */
     /* Codes_SRS_SCHEMA_99_127: [The index argument is zero based, and the order in which models were added shall be the index in which they will be retrieved.] */
@@ -1649,14 +1892,14 @@
     }
     else
     {
-        MODEL_TYPE* modelType = (MODEL_TYPE*)modelTypeHandle;
+        SCHEMA_MODEL_TYPE_HANDLE_DATA* modelType = (SCHEMA_MODEL_TYPE_HANDLE_DATA*)modelTypeHandle;
         result = modelType->Name;
     }
     return result;
 }
 
 /*Codes_SRS_SCHEMA_99_163: [Schema_AddModelModel shall insert an existing model, identified by the handle modelType, into the existing model identified by modelTypeHandle under a property having the name propertyName.]*/
-SCHEMA_RESULT Schema_AddModelModel(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, const char* propertyName, SCHEMA_MODEL_TYPE_HANDLE modelType)
+SCHEMA_RESULT Schema_AddModelModel(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, const char* propertyName, SCHEMA_MODEL_TYPE_HANDLE modelType, size_t offset, pfOnDesiredProperty onDesiredProperty)
 {
     SCHEMA_RESULT result;
     /*Codes_SRS_SCHEMA_99_165: [If any of the parameters is NULL then Schema_AddModelModel shall return SCHEMA_INVALID_ARG.]*/
@@ -1671,9 +1914,11 @@
     }
     else
     {
-        MODEL_TYPE* parentModel = (MODEL_TYPE*)modelTypeHandle;
+        SCHEMA_MODEL_TYPE_HANDLE_DATA* parentModel = (SCHEMA_MODEL_TYPE_HANDLE_DATA*)modelTypeHandle;
         MODEL_IN_MODEL temp;
         temp.modelHandle = modelType;
+        temp.offset = offset;
+        temp.onDesiredProperty = onDesiredProperty;
         if (mallocAndStrcpy_s((char**)&(temp.propertyName), propertyName) != 0)
         {
             result = SCHEMA_ERROR;
@@ -1689,6 +1934,7 @@
         else
         {
             /*Codes_SRS_SCHEMA_99_164: [If the function succeeds, then the return value shall be SCHEMA_OK.]*/
+            
             result = SCHEMA_OK;
         }
     }
@@ -1710,7 +1956,7 @@
     }
     else
     {
-        MODEL_TYPE* model = (MODEL_TYPE*)modelTypeHandle;
+        SCHEMA_MODEL_TYPE_HANDLE_DATA* model = (SCHEMA_MODEL_TYPE_HANDLE_DATA*)modelTypeHandle;
         /*Codes_SRS_SCHEMA_99_167: [Schema_GetModelModelCount shall return in parameter modelCount the number of models inserted in the model identified by parameter modelTypeHandle.]*/
         *modelCount = VECTOR_size(model->models);
         /*SRS_SCHEMA_99_168: [If the function succeeds, it shall return SCHEMA_OK.]*/
@@ -1740,7 +1986,7 @@
     }
     else
     {
-        MODEL_TYPE* model = (MODEL_TYPE*)modelTypeHandle;
+        SCHEMA_MODEL_TYPE_HANDLE_DATA* model = (SCHEMA_MODEL_TYPE_HANDLE_DATA*)modelTypeHandle;
         /*Codes_SRS_SCHEMA_99_170: [Schema_GetModelModelByName shall return a handle to the model identified by the property with the name propertyName in the model identified by the handle modelTypeHandle.]*/
         /*Codes_SRS_SCHEMA_99_171: [If Schema_GetModelModelByName is unable to provide the handle it shall return NULL.]*/
         void* temp = VECTOR_find_if(model->models, matchModelName, propertyName);
@@ -1757,6 +2003,101 @@
     return result;
 }
 
+size_t Schema_GetModelModelByName_Offset(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, const char* propertyName)
+{
+    size_t result;
+    /*Codes_SRS_SCHEMA_02_053: [ If modelTypeHandle is NULL then Schema_GetModelModelByName_Offset shall fail and return 0. ]*/
+    /*Codes_SRS_SCHEMA_02_054: [ If propertyName is NULL then Schema_GetModelModelByName_Offset shall fail and return 0. ]*/
+    if (
+        (modelTypeHandle == NULL) ||
+        (propertyName == NULL)
+        )
+    {
+        /*Codes_SRS_SCHEMA_99_171: [If Schema_GetModelModelByName is unable to provide the handle it shall return NULL.]*/
+        result = 0;
+        LogError("error SCHEMA_INVALID_ARG");
+    }
+    else
+    {
+        SCHEMA_MODEL_TYPE_HANDLE_DATA* model = (SCHEMA_MODEL_TYPE_HANDLE_DATA*)modelTypeHandle;
+        /*Codes_SRS_SCHEMA_02_056: [ If propertyName is not a model then Schema_GetModelModelByName_Offset shall fail and return 0. ]*/
+        void* temp = VECTOR_find_if(model->models, matchModelName, propertyName);
+        if (temp == NULL)
+        {
+            LogError("specified propertyName not found (%s)", propertyName);
+            result = 0;
+        }
+        else
+        {
+            /*Codes_SRS_SCHEMA_02_055: [ Otherwise Schema_GetModelModelByName_Offset shall succeed and return the offset. ]*/
+            result = ((MODEL_IN_MODEL*)temp)->offset;
+        }
+    }
+    return result;
+}
+
+pfOnDesiredProperty Schema_GetModelModelByName_OnDesiredProperty(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, const char* propertyName)
+{
+    pfOnDesiredProperty result;
+    /*Codes_SRS_SCHEMA_02_086: [ If modelTypeHandle is NULL then Schema_GetModelModelByName_OnDesiredProperty shall return NULL. ]*/
+    /*Codes_SRS_SCHEMA_02_087: [ If propertyName is NULL then Schema_GetModelModelByName_OnDesiredProperty shall return NULL. ]*/
+    if (
+        (modelTypeHandle == NULL) ||
+        (propertyName == NULL)
+        )
+    {
+        result = NULL;
+        LogError("invalid argument SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle=%p, const char* propertyName=%p",modelTypeHandle, propertyName);
+    }
+    else
+    {
+        SCHEMA_MODEL_TYPE_HANDLE_DATA* model = (SCHEMA_MODEL_TYPE_HANDLE_DATA*)modelTypeHandle;
+        void* temp = VECTOR_find_if(model->models, matchModelName, propertyName);
+        if (temp == NULL)
+        {
+            LogError("specified propertyName not found (%s)", propertyName);
+            result = NULL;
+        }
+        else
+        {
+            /*Codes_SRS_SCHEMA_02_089: [ Otherwise Schema_GetModelModelByName_OnDesiredProperty shall return the desired property callback. ]*/
+            result = ((MODEL_IN_MODEL*)temp)->onDesiredProperty;
+        }
+    }
+    return result;
+
+}
+
+size_t Schema_GetModelModelByIndex_Offset(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, size_t index)
+{
+    size_t result;
+    /*Codes_SRS_SCHEMA_02_057: [ If modelTypeHandle is NULL then Schema_GetModelModelByIndex_Offset shall fail and return 0. ]*/
+    if (
+        (modelTypeHandle == NULL)
+        )
+    {
+        result = 0;
+        LogError("error SCHEMA_INVALID_ARG");
+    }
+    else
+    {
+        SCHEMA_MODEL_TYPE_HANDLE_DATA* model = (SCHEMA_MODEL_TYPE_HANDLE_DATA*)modelTypeHandle;
+        /*Codes_SRS_SCHEMA_02_058: [ If index is not valid then Schema_GetModelModelByIndex_Offset shall fail and return 0. ]*/
+        void* temp = VECTOR_element(model->models, index);
+        if (temp == 0)
+        {
+            LogError("specified index [out of bounds] (%zu)", index);
+            result = 0;
+        }
+        else
+        {
+            /*Codes_SRS_SCHEMA_02_059: [ Otherwise Schema_GetModelModelByIndex_Offset shall succeed and return the offset. ]*/
+            result = ((MODEL_IN_MODEL*)temp)->offset;
+        }
+    }
+    return result;
+}
+
 SCHEMA_MODEL_TYPE_HANDLE Schema_GetModelModelyByIndex(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, size_t index)
 {
     SCHEMA_MODEL_TYPE_HANDLE result;
@@ -1770,7 +2111,7 @@
     }
     else
     {
-        MODEL_TYPE* model = (MODEL_TYPE*)modelTypeHandle;
+        SCHEMA_MODEL_TYPE_HANDLE_DATA* model = (SCHEMA_MODEL_TYPE_HANDLE_DATA*)modelTypeHandle;
         size_t nModelsInModel;
         /*Codes_SRS_SCHEMA_99_172: [ Schema_GetModelModelyByIndex shall return a handle to the "index"th model inserted in the model identified by the parameter modelTypeHandle.]*/
         /*Codes_SRS_SCHEMA_99_173: [Schema_GetModelModelyByIndex shall return NULL in the cases when it cannot provide the handle.]*/
@@ -1798,7 +2139,7 @@
     }
     else
     {
-        MODEL_TYPE* model = (MODEL_TYPE*)modelTypeHandle;
+        SCHEMA_MODEL_TYPE_HANDLE_DATA* model = (SCHEMA_MODEL_TYPE_HANDLE_DATA*)modelTypeHandle;
         size_t nModelsInModel;
         /*Codes_SRS_SCHEMA_99_175: [Schema_GetModelModelPropertyNameByIndex shall return the name of the property for the "index"th model in the model identified by modelTypeHandle parameter.]*/
         /*Codes_SRS_SCHEMA_99_176: [If Schema_GetModelModelPropertyNameByIndex cannot produce the property name, it shall return NULL.]*/
@@ -1843,7 +2184,7 @@
             const char* endPos;
             size_t i;
             size_t modelCount;
-            MODEL_TYPE* modelType = (MODEL_TYPE*)modelTypeHandle;
+            SCHEMA_MODEL_TYPE_HANDLE_DATA* modelType = (SCHEMA_MODEL_TYPE_HANDLE_DATA*)modelTypeHandle;
 
             /* Codes_SRS_SCHEMA_99_179: [The propertyPath shall be assumed to be in the format model1/model2/.../propertyName.] */
             slashPos = strchr(propertyPath, '/');
@@ -1888,7 +2229,7 @@
                 /* Codes_SRS_SCHEMA_99_178: [The argument propertyPath shall be used to find the leaf property.] */
                 for (i = 0; i < modelType->PropertyCount; i++)
                 {
-                    PROPERTY* property = (PROPERTY*)modelType->Properties[i];
+                    SCHEMA_PROPERTY_HANDLE_DATA* property = (SCHEMA_PROPERTY_HANDLE_DATA*)modelType->Properties[i];
                     if ((strncmp(property->PropertyName, propertyPath, endPos - propertyPath) == 0) &&
                         (strlen(property->PropertyName) == (size_t)(endPos - propertyPath)))
                     {
@@ -1906,3 +2247,618 @@
 
     return result;
 }
+
+bool Schema_ModelReportedPropertyByPathExists(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, const char* reportedPropertyPath)
+{
+    bool result;
+
+    /*Codes_SRS_SCHEMA_02_018: [ If argument modelTypeHandle is NULL then Schema_ModelReportedPropertyByPathExists shall fail and return false. ]*/
+    /*Codes_SRS_SCHEMA_02_019: [ If argument reportedPropertyPath is NULL then Schema_ModelReportedPropertyByPathExists shall fail and return false. ]*/
+    if ((modelTypeHandle == NULL) ||
+        (reportedPropertyPath == NULL))
+    {
+        LogError("invalid argument SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle=%p, const char* reportedPropertyPath=%s", modelTypeHandle, reportedPropertyPath);
+        result = false;
+    }
+    else
+    {
+        const char* slashPos;
+
+        /*Codes_SRS_SCHEMA_02_021: [ If the reported property cannot be found Schema_ModelReportedPropertyByPathExists shall fail and return false. ]*/
+        result = false;
+
+        /*Codes_SRS_SCHEMA_02_020: [ reportedPropertyPath shall be assumed to be in the format model1/model2/.../reportedPropertyName. ]*/
+        if (*reportedPropertyPath == '/')
+        {
+            reportedPropertyPath++;
+        }
+
+        do
+        {
+            const char* endPos;
+            size_t i;
+            size_t modelCount;
+            SCHEMA_MODEL_TYPE_HANDLE_DATA* modelType = (SCHEMA_MODEL_TYPE_HANDLE_DATA*)modelTypeHandle;
+
+            slashPos = strchr(reportedPropertyPath, '/');
+            endPos = slashPos;
+            if (endPos == NULL)
+            {
+                endPos = &reportedPropertyPath[strlen(reportedPropertyPath)];
+            }
+
+            modelCount = VECTOR_size(modelType->models);
+            for (i = 0; i < modelCount; i++)
+            {
+                MODEL_IN_MODEL* childModel = (MODEL_IN_MODEL*)VECTOR_element(modelType->models, i);
+                if ((strncmp(childModel->propertyName, reportedPropertyPath, endPos - reportedPropertyPath) == 0) &&
+                    (strlen(childModel->propertyName) == (size_t)(endPos - reportedPropertyPath)))
+                {
+                    /* found */
+                    modelTypeHandle = childModel->modelHandle;
+                    break;
+                }
+            }
+
+            if (i < modelCount)
+            {
+                /* model found, check if there is more in the path */
+                if (slashPos == NULL)
+                {
+                    /*Codes_SRS_SCHEMA_02_022: [ If the path reportedPropertyPath points to a sub-model, Schema_ModelReportedPropertyByPathExists shall succeed and true. ]*/
+                    /* this is the last one, so this is the thing we were looking for */
+                    result = true;
+                    break;
+                }
+                else
+                {
+                    /* continue looking, there's more  */
+                    reportedPropertyPath = slashPos + 1;
+                }
+            }
+            else
+            {
+                /* no model found, let's see if this is a property */
+                result = (VECTOR_find_if(modelType->reportedProperties, reportedPropertyExists, reportedPropertyPath) != NULL);
+                if (!result)
+                {
+                    LogError("no such reported property \"%s\"", reportedPropertyPath);
+                }
+                break;
+            }
+        } while (slashPos != NULL);
+    }
+
+    return result;
+}
+
+static bool desiredPropertyExists(const void* element, const void* value)
+{
+    SCHEMA_DESIRED_PROPERTY_HANDLE_DATA* desiredProperty = *(SCHEMA_DESIRED_PROPERTY_HANDLE_DATA**)element;
+    return (strcmp(desiredProperty->desiredPropertyName, value) == 0);
+}
+
+SCHEMA_RESULT Schema_AddModelDesiredProperty(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, const char* desiredPropertyName, const char* desiredPropertyType, pfDesiredPropertyFromAGENT_DATA_TYPE desiredPropertyFromAGENT_DATA_TYPE, pfDesiredPropertyInitialize desiredPropertyInitialize, pfDesiredPropertyDeinitialize desiredPropertyDeinitialize, size_t offset, pfOnDesiredProperty onDesiredProperty)
+{
+    SCHEMA_RESULT result;
+    /*Codes_SRS_SCHEMA_02_024: [ If modelTypeHandle is NULL then Schema_AddModelDesiredProperty shall fail and return SCHEMA_INVALID_ARG. ]*/
+    /*Codes_SRS_SCHEMA_02_025: [ If desiredPropertyName is NULL then Schema_AddModelDesiredProperty shall fail and return SCHEMA_INVALID_ARG. ]*/
+    /*Codes_SRS_SCHEMA_02_026: [ If desiredPropertyType is NULL then Schema_AddModelDesiredProperty shall fail and return SCHEMA_INVALID_ARG. ]*/
+    /*Codes_SRS_SCHEMA_02_048: [ If desiredPropertyFromAGENT_DATA_TYPE is NULL then Schema_AddModelDesiredProperty shall fail and return SCHEMA_INVALID_ARG. ]*/
+    /*Codes_SRS_SCHEMA_02_049: [ If desiredPropertyInitialize is NULL then Schema_AddModelDesiredProperty shall fail and return SCHEMA_INVALID_ARG. ]*/
+    /*Codes_SRS_SCHEMA_02_050: [ If desiredPropertyDeinitialize is NULL then Schema_AddModelDesiredProperty shall fail and return SCHEMA_INVALID_ARG. ]*/
+    if (
+        (modelTypeHandle == NULL) ||
+        (desiredPropertyName == NULL) ||
+        (desiredPropertyType == NULL) ||
+        (desiredPropertyFromAGENT_DATA_TYPE == NULL) ||
+        (desiredPropertyInitialize == NULL) ||
+        (desiredPropertyDeinitialize== NULL)
+        )
+    {
+        LogError("invalid arg SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle=%p, const char* desiredPropertyName=%p, const char* desiredPropertyType=%p, pfDesiredPropertyFromAGENT_DATA_TYPE desiredPropertyFromAGENT_DATA_TYPE=%p, pfDesiredPropertyInitialize desiredPropertyInitialize=%p, pfDesiredPropertyDeinitialize desiredPropertyDeinitialize=%p, size_t offset=%zu",
+            modelTypeHandle, desiredPropertyName, desiredPropertyType, desiredPropertyFromAGENT_DATA_TYPE, desiredPropertyInitialize, desiredPropertyDeinitialize, offset);
+        result = SCHEMA_INVALID_ARG;
+    }
+    else
+    {
+        SCHEMA_MODEL_TYPE_HANDLE_DATA* handleData = (SCHEMA_MODEL_TYPE_HANDLE_DATA*)modelTypeHandle;
+        /*Codes_SRS_SCHEMA_02_027: [ Schema_AddModelDesiredProperty shall add the desired property given by the name desiredPropertyName and the type desiredPropertyType to the collection of existing desired properties. ]*/
+        if (VECTOR_find_if(handleData->desiredProperties, desiredPropertyExists, desiredPropertyName) != NULL)
+        {
+            /*Codes_SRS_SCHEMA_02_047: [ If the desired property already exists, then Schema_AddModelDesiredProperty shall fail and return SCHEMA_DUPLICATE_ELEMENT. ]*/
+            LogError("unable to Schema_AddModelDesiredProperty because a desired property with the same name (%s) already exists", desiredPropertyName);
+            result = SCHEMA_DUPLICATE_ELEMENT;
+        }
+        else
+        {
+            SCHEMA_DESIRED_PROPERTY_HANDLE_DATA* desiredProperty = (SCHEMA_DESIRED_PROPERTY_HANDLE_DATA*)malloc(sizeof(SCHEMA_DESIRED_PROPERTY_HANDLE_DATA));
+            if (desiredProperty == NULL)
+            {
+                /*Codes_SRS_SCHEMA_02_028: [ If any failure occurs then Schema_AddModelDesiredProperty shall fail and return SCHEMA_ERROR. ]*/
+                LogError("failure in malloc");
+                result = SCHEMA_ERROR;
+            }
+            else
+            {
+                if (mallocAndStrcpy_s((char**)&desiredProperty->desiredPropertyName, desiredPropertyName) != 0)
+                {
+                    /*Codes_SRS_SCHEMA_02_028: [ If any failure occurs then Schema_AddModelDesiredProperty shall fail and return SCHEMA_ERROR. ]*/
+                    LogError("failure in mallocAndStrcpy_s");
+                    free(desiredProperty);
+                    result = SCHEMA_ERROR;
+                }
+                else
+                {
+                    if (mallocAndStrcpy_s((char**)&desiredProperty->desiredPropertyType, desiredPropertyType) != 0)
+                    {
+                        /*Codes_SRS_SCHEMA_02_028: [ If any failure occurs then Schema_AddModelDesiredProperty shall fail and return SCHEMA_ERROR. ]*/
+                        LogError("failure in mallocAndStrcpy_s");
+                        free((void*)desiredProperty->desiredPropertyName);
+                        free(desiredProperty);
+                        result = SCHEMA_ERROR;
+                    }
+                    else
+                    {
+                        if (VECTOR_push_back(handleData->desiredProperties, &desiredProperty, 1) != 0)
+                        {
+                            /*Codes_SRS_SCHEMA_02_028: [ If any failure occurs then Schema_AddModelDesiredProperty shall fail and return SCHEMA_ERROR. ]*/
+                            LogError("failure in VECTOR_push_back");
+                            free((void*)desiredProperty->desiredPropertyType);
+                            free((void*)desiredProperty->desiredPropertyName);
+                            free(desiredProperty);
+                            result = SCHEMA_ERROR;
+                        }
+                        else
+                        {
+                            /*Codes_SRS_SCHEMA_02_029: [ Otherwise, Schema_AddModelDesiredProperty shall succeed and return SCHEMA_OK. ]*/
+                            desiredProperty->desiredPropertyFromAGENT_DATA_TYPE = desiredPropertyFromAGENT_DATA_TYPE;
+                            desiredProperty->desiredPropertInitialize = desiredPropertyInitialize;
+                            desiredProperty->desiredPropertDeinitialize = desiredPropertyDeinitialize;
+                            desiredProperty->onDesiredProperty = onDesiredProperty; /*NULL is a perfectly fine value*/
+                            desiredProperty->offset = offset;
+                            result = SCHEMA_OK;
+                        }
+                    }
+                }
+            }
+        }
+    }
+    return result;
+}
+
+
+SCHEMA_RESULT Schema_GetModelDesiredPropertyCount(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, size_t* desiredPropertyCount)
+{
+    SCHEMA_RESULT result;
+    /*Codes_SRS_SCHEMA_02_030: [ If modelTypeHandle is NULL then Schema_GetModelDesiredPropertyCount shall fail and return SCHEMA_INVALID_ARG. ]*/
+    /*Codes_SRS_SCHEMA_02_031: [ If desiredPropertyCount is NULL then Schema_GetModelDesiredPropertyCount shall fail and return SCHEMA_INVALID_ARG. ]*/
+    if (
+        (modelTypeHandle == NULL) ||
+        (desiredPropertyCount == NULL)
+        )
+    {
+        LogError("invalid arg: SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle=%p, size_t* desiredPropertyCount=%p", modelTypeHandle, desiredPropertyCount);
+        result = SCHEMA_INVALID_ARG;
+    }
+    else
+    {
+        /*Codes_SRS_SCHEMA_02_032: [ Otherwise, Schema_GetModelDesiredPropertyCount shall succeed and write in desiredPropertyCount the existing number of desired properties. ]*/
+        SCHEMA_MODEL_TYPE_HANDLE_DATA* handleData = (SCHEMA_MODEL_TYPE_HANDLE_DATA*)modelTypeHandle;
+        *desiredPropertyCount = VECTOR_size(handleData->desiredProperties);
+        result = SCHEMA_OK;
+    }
+    return result;
+}
+
+SCHEMA_DESIRED_PROPERTY_HANDLE Schema_GetModelDesiredPropertyByName(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, const char* desiredPropertyName)
+{
+    SCHEMA_DESIRED_PROPERTY_HANDLE result;
+    /*Codes_SRS_SCHEMA_02_034: [ If modelTypeHandle is NULL then Schema_GetModelDesiredPropertyByName shall fail and return NULL. ]*/
+    /*Codes_SRS_SCHEMA_02_035: [ If desiredPropertyName is NULL then Schema_GetModelDesiredPropertyByName shall fail and return NULL. ]*/
+    if (
+        (modelTypeHandle == NULL) ||
+        (desiredPropertyName == NULL)
+        )
+    {
+        LogError("invalid arg SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle=%p, const char* desiredPropertyName=%p", modelTypeHandle, desiredPropertyName);
+        result = NULL;
+    }
+    else
+    {
+        /*Codes_SRS_SCHEMA_02_036: [ If a desired property having the name desiredPropertyName exists then Schema_GetModelDesiredPropertyByName shall succeed and return a non-NULL value. ]*/
+        /*Codes_SRS_SCHEMA_02_037: [ Otherwise, Schema_GetModelDesiredPropertyByName shall fail and return NULL. ]*/
+        SCHEMA_MODEL_TYPE_HANDLE_DATA* handleData = (SCHEMA_MODEL_TYPE_HANDLE_DATA*)modelTypeHandle;
+        SCHEMA_DESIRED_PROPERTY_HANDLE* temp = VECTOR_find_if(handleData->desiredProperties, desiredPropertyExists, desiredPropertyName);
+        if (temp == NULL)
+        {
+            LogError("no such desired property by name %s", desiredPropertyName);
+            result = NULL;
+        }
+        else
+        {
+            result = *temp;
+        }
+    }
+    return result;
+}
+
+SCHEMA_DESIRED_PROPERTY_HANDLE Schema_GetModelDesiredPropertyByIndex(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, size_t index)
+{
+    SCHEMA_DESIRED_PROPERTY_HANDLE result;
+    /*Codes_SRS_SCHEMA_02_038: [ If modelTypeHandle is NULL then Schema_GetModelDesiredPropertyByIndex shall fail and return NULL. ]*/
+    if (modelTypeHandle == NULL)
+    {
+        LogError("invalid argument SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle=%p, size_t index=%p", modelTypeHandle, index);
+        result = NULL;
+    }
+    else
+    {
+        SCHEMA_MODEL_TYPE_HANDLE_DATA* handleData = (SCHEMA_MODEL_TYPE_HANDLE_DATA*)modelTypeHandle;
+        /*Codes_SRS_SCHEMA_02_039: [ If index is outside the range for existing indexes of desire properties, then Schema_GetModelDesiredPropertyByIndex shall fail and return NULL. ]*/
+        /*Codes_SRS_SCHEMA_02_040: [ Otherwise, Schema_GetModelDesiredPropertyByIndex shall succeed and return a non-NULL value. ]*/
+        SCHEMA_DESIRED_PROPERTY_HANDLE* temp = VECTOR_element(handleData->desiredProperties, index);
+        if (temp == NULL)
+        {
+            LogError("VECTOR_element produced NULL (likely out of bounds index)");
+            result = NULL;
+        }
+        else
+        {
+            result = *temp;
+        }
+    }
+    return result;
+}
+
+bool Schema_ModelDesiredPropertyByPathExists(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, const char* desiredPropertyPath)
+{
+    bool result;
+    /*Codes_SRS_SCHEMA_02_041: [ If modelTypeHandle is NULL then Schema_ModelDesiredPropertyByPathExists shall fail and return false. ]*/
+    /*Codes_SRS_SCHEMA_02_042: [ If desiredPropertyPath is NULL then Schema_ModelDesiredPropertyByPathExists shall fail and return false. ]*/
+    if (
+        (modelTypeHandle == NULL) ||
+        (desiredPropertyPath == NULL)
+        )
+    {
+        LogError("invalid arg SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle=%p, const char* desiredPropertyPath=%p", modelTypeHandle, desiredPropertyPath);
+        result = false;
+    }
+    else
+    {
+        const char* slashPos;
+
+        /*Codes_SRS_SCHEMA_02_044: [ If the desired property cannot be found Schema_ModelDesiredPropertyByPathExists shall fail and return false. ]*/
+        result = false;
+
+        /*Codes_SRS_SCHEMA_02_043: [ desiredPropertyPath shall be assumed to be in the format model1/model2/.../desiredPropertyName. ]*/
+        if (*desiredPropertyPath == '/')
+        {
+            desiredPropertyPath++;
+        }
+
+        do
+        {
+            const char* endPos;
+            size_t i;
+            size_t modelCount;
+            SCHEMA_MODEL_TYPE_HANDLE_DATA* modelType = (SCHEMA_MODEL_TYPE_HANDLE_DATA*)modelTypeHandle;
+
+            slashPos = strchr(desiredPropertyPath, '/');
+            endPos = slashPos;
+            if (endPos == NULL)
+            {
+                endPos = &desiredPropertyPath[strlen(desiredPropertyPath)];
+            }
+
+            modelCount = VECTOR_size(modelType->models);
+            for (i = 0; i < modelCount; i++)
+            {
+                MODEL_IN_MODEL* childModel = (MODEL_IN_MODEL*)VECTOR_element(modelType->models, i);
+                if ((strncmp(childModel->propertyName, desiredPropertyPath, endPos - desiredPropertyPath) == 0) &&
+                    (strlen(childModel->propertyName) == (size_t)(endPos - desiredPropertyPath)))
+                {
+                    /* found */
+                    modelTypeHandle = childModel->modelHandle;
+                    break;
+                }
+            }
+
+            if (i < modelCount)
+            {
+                /* model found, check if there is more in the path */
+                if (slashPos == NULL)
+                {
+                    /*Codes_SRS_SCHEMA_02_045: [ If the path desiredPropertyPath points to a sub-model, Schema_ModelDesiredPropertyByPathExists shall succeed and true. ]*/
+                    /* this is the last one, so this is the thing we were looking for */
+                    result = true;
+                    break;
+                }
+                else
+                {
+                    /* continue looking, there's more  */
+                    desiredPropertyPath = slashPos + 1;
+                }
+            }
+            else
+            {
+                /* no model found, let's see if this is a property */
+                result = (VECTOR_find_if(modelType->desiredProperties, desiredPropertyExists, desiredPropertyPath) != NULL);
+                if (!result)
+                {
+                    LogError("no such desired property \"%s\"", desiredPropertyPath);
+                }
+                break;
+            }
+        } while (slashPos != NULL);
+    }
+    return result;
+}
+
+const char* Schema_GetModelDesiredPropertyType(SCHEMA_DESIRED_PROPERTY_HANDLE desiredPropertyHandle)
+{
+    const char* result;
+    /*Codes_SRS_SCHEMA_02_062: [ If desiredPropertyHandle is NULL then Schema_GetModelDesiredPropertyType shall fail and return NULL. ]*/
+    if (desiredPropertyHandle == NULL)
+    {
+        LogError("invalid argument SCHEMA_DESIRED_PROPERTY_HANDLE desiredPropertyHandle=%p", desiredPropertyHandle);
+        result = NULL;
+    }
+    else
+    {
+        /*Codes_SRS_SCHEMA_02_063: [ Otherwise, Schema_GetModelDesiredPropertyType shall return the type of the desired property. ]*/
+        SCHEMA_DESIRED_PROPERTY_HANDLE_DATA* desirePropertyHandleData = (SCHEMA_DESIRED_PROPERTY_HANDLE_DATA*)desiredPropertyHandle;
+        result = desirePropertyHandleData->desiredPropertyType;
+    }
+    return result;
+}
+
+pfDesiredPropertyFromAGENT_DATA_TYPE Schema_GetModelDesiredProperty_pfDesiredPropertyFromAGENT_DATA_TYPE(SCHEMA_DESIRED_PROPERTY_HANDLE desiredPropertyHandle)
+{
+    pfDesiredPropertyFromAGENT_DATA_TYPE result;
+    if (desiredPropertyHandle == NULL)
+    {
+        LogError("invalid argument SCHEMA_DESIRED_PROPERTY_HANDLE desiredPropertyHandle=%p", desiredPropertyHandle);
+        result = NULL;
+    }
+    else
+    {
+        SCHEMA_DESIRED_PROPERTY_HANDLE_DATA* desirePropertyHandleData = (SCHEMA_DESIRED_PROPERTY_HANDLE_DATA*)desiredPropertyHandle;
+        result = desirePropertyHandleData->desiredPropertyFromAGENT_DATA_TYPE;
+    }
+    return result;
+}
+
+pfOnDesiredProperty Schema_GetModelDesiredProperty_pfOnDesiredProperty(SCHEMA_DESIRED_PROPERTY_HANDLE desiredPropertyHandle)
+{
+    pfOnDesiredProperty result;
+    /*Codes_SRS_SCHEMA_02_084: [ If desiredPropertyHandle is NULL then Schema_GetModelDesiredProperty_pfOnDesiredProperty shall return NULL. ]*/
+    if (desiredPropertyHandle == NULL)
+    {
+        LogError("invalid argument SCHEMA_DESIRED_PROPERTY_HANDLE desiredPropertyHandle=%p", desiredPropertyHandle);
+        result = NULL;
+    }
+    else
+    {
+        /*Codes_SRS_SCHEMA_02_085: [ Otherwise Schema_GetModelDesiredProperty_pfOnDesiredProperty shall return the saved desired property callback. ]*/
+        SCHEMA_DESIRED_PROPERTY_HANDLE_DATA* desirePropertyHandleData = (SCHEMA_DESIRED_PROPERTY_HANDLE_DATA*)desiredPropertyHandle;
+        result = desirePropertyHandleData->onDesiredProperty;
+    }
+    return result;
+}
+
+size_t Schema_GetModelDesiredProperty_offset(SCHEMA_DESIRED_PROPERTY_HANDLE desiredPropertyHandle)
+{
+    size_t result;
+    /*Codes_SRS_SCHEMA_02_060: [ If desiredPropertyHandle is NULL then Schema_GetModelDesiredProperty_offset shall fail and return 0. ]*/
+    if (desiredPropertyHandle == NULL)
+    {
+        LogError("invalid argument SCHEMA_DESIRED_PROPERTY_HANDLE desiredPropertyHandle=%p", desiredPropertyHandle);
+        result = 0;
+    }
+    else
+    {
+        /*Codes_SRS_SCHEMA_02_061: [ Otherwise Schema_GetModelDesiredProperty_offset shall succeed and return the offset. ]*/
+        SCHEMA_DESIRED_PROPERTY_HANDLE_DATA* desirePropertyHandleData = (SCHEMA_DESIRED_PROPERTY_HANDLE_DATA*)desiredPropertyHandle;
+        result = desirePropertyHandleData->offset;
+    }
+    return result;
+}
+
+static bool modelInModelExists(const void* element, const void* value)
+{
+    MODEL_IN_MODEL* modelInModel = (MODEL_IN_MODEL*)element;
+    return (strcmp(modelInModel->propertyName, value) == 0);
+}
+
+SCHEMA_MODEL_ELEMENT Schema_GetModelElementByName(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, const char* elementName)
+{
+    SCHEMA_MODEL_ELEMENT result;
+    /*Codes_SRS_SCHEMA_02_076: [ If modelTypeHandle is NULL then Schema_GetModelElementByName shall fail and set SCHEMA_MODEL_ELEMENT.elementType to SCHEMA_SEARCH_INVALID_ARG. ]*/
+    /*Codes_SRS_SCHEMA_02_077: [ If elementName is NULL then Schema_GetModelElementByName shall fail and set SCHEMA_MODEL_ELEMENT.elementType to SCHEMA_SEARCH_INVALID_ARG. ]*/
+    if (
+        (modelTypeHandle == NULL) ||
+        (elementName == NULL)
+        )
+    {
+        LogError("invalid argument SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle=%p, const char* elementName=%p", modelTypeHandle, elementName);
+        result.elementType = SCHEMA_SEARCH_INVALID_ARG;
+    }
+    else
+    {
+        SCHEMA_MODEL_TYPE_HANDLE_DATA* handleData = (SCHEMA_MODEL_TYPE_HANDLE_DATA*)modelTypeHandle;
+
+        SCHEMA_DESIRED_PROPERTY_HANDLE* desiredPropertyHandle = VECTOR_find_if(handleData->desiredProperties, desiredPropertyExists, elementName);
+        if (desiredPropertyHandle != NULL)
+        {
+            /*Codes_SRS_SCHEMA_02_080: [ If elementName is a desired property then Schema_GetModelElementByName shall succeed and set SCHEMA_MODEL_ELEMENT.elementType to SCHEMA_DESIRED_PROPERTY and SCHEMA_MODEL_ELEMENT.elementHandle.desiredPropertyHandle to the handle of the desired property. ]*/
+            result.elementType = SCHEMA_DESIRED_PROPERTY;
+            result.elementHandle.desiredPropertyHandle = *desiredPropertyHandle;
+        }
+        else
+        {
+            size_t nProcessedProperties = 0;
+            SCHEMA_PROPERTY_HANDLE_DATA* property = NULL;
+            for (size_t i = 0; i < handleData->PropertyCount;i++)
+            {
+                property = (SCHEMA_PROPERTY_HANDLE_DATA*)(handleData->Properties[i]);
+                if (strcmp(property->PropertyName, elementName) == 0)
+                {
+                    i = handleData->PropertyCount; /*found it*/
+                }
+                else
+                {
+                    nProcessedProperties++;
+                }
+            }
+
+            if (nProcessedProperties < handleData->PropertyCount)
+            {
+                /*Codes_SRS_SCHEMA_02_078: [ If elementName is a property then Schema_GetModelElementByName shall succeed and set SCHEMA_MODEL_ELEMENT.elementType to SCHEMA_PROPERTY and SCHEMA_MODEL_ELEMENT.elementHandle.propertyHandle to the handle of the property. ]*/
+                result.elementType = SCHEMA_PROPERTY;
+                result.elementHandle.propertyHandle = property;
+            }
+            else
+            {
+
+                SCHEMA_REPORTED_PROPERTY_HANDLE* reportedPropertyHandle = VECTOR_find_if(handleData->reportedProperties, reportedPropertyExists, elementName);
+                if (reportedPropertyHandle != NULL)
+                {
+                    /*Codes_SRS_SCHEMA_02_079: [ If elementName is a reported property then Schema_GetModelElementByName shall succeed and set SCHEMA_MODEL_ELEMENT.elementType to SCHEMA_REPORTED_PROPERTY and SCHEMA_MODEL_ELEMENT.elementHandle.reportedPropertyHandle to the handle of the reported property. ]*/
+                    result.elementType = SCHEMA_REPORTED_PROPERTY;
+                    result.elementHandle.reportedPropertyHandle = *reportedPropertyHandle;
+                }
+                else
+                {
+
+                    size_t nProcessedActions = 0;
+                    SCHEMA_ACTION_HANDLE_DATA* actionHandleData = NULL;
+                    for (size_t i = 0;i < handleData->ActionCount; i++)
+                    {
+                        actionHandleData = (SCHEMA_ACTION_HANDLE_DATA*)(handleData->Actions[i]);
+                        if (strcmp(actionHandleData->ActionName, elementName) == 0)
+                        {
+                            i = handleData->ActionCount; /*get out quickly*/
+                        }
+                        else
+                        {
+                            nProcessedActions++;
+                        }
+                    }
+
+                    if (nProcessedActions < handleData->ActionCount)
+                    {
+                        /*Codes_SRS_SCHEMA_02_081: [ If elementName is a model action then Schema_GetModelElementByName shall succeed and set SCHEMA_MODEL_ELEMENT.elementType to SCHEMA_MODEL_ACTION and SCHEMA_MODEL_ELEMENT.elementHandle.actionHandle to the handle of the action. ]*/
+                        result.elementType = SCHEMA_MODEL_ACTION;
+                        result.elementHandle.actionHandle = actionHandleData;
+                    }
+                    else
+                    {
+                        MODEL_IN_MODEL* modelInModel = VECTOR_find_if(handleData->models, modelInModelExists, elementName);
+                        if (modelInModel != NULL)
+                        {
+                            /*Codes_SRS_SCHEMA_02_082: [ If elementName is a model in model then Schema_GetModelElementByName shall succeed and set SCHEMA_MODEL_ELEMENT.elementType to SCHEMA_MODEL_IN_MODEL and SCHEMA_MODEL_ELEMENT.elementHandle.modelHandle to the handle of the model. ]*/
+                            result.elementType = SCHEMA_MODEL_IN_MODEL;
+                            result.elementHandle.modelHandle = modelInModel->modelHandle;
+                        }
+                        else
+                        {
+                            /*Codes_SRS_SCHEMA_02_083: [ Otherwise Schema_GetModelElementByName shall fail and set SCHEMA_MODEL_ELEMENT.elementType to SCHEMA_NOT_FOUND. ]*/
+                            result.elementType = SCHEMA_NOT_FOUND;
+                        }
+                    }
+                }
+            }
+        }
+    }
+    return result;
+}
+
+pfDesiredPropertyDeinitialize Schema_GetModelDesiredProperty_pfDesiredPropertyDeinitialize(SCHEMA_DESIRED_PROPERTY_HANDLE desiredPropertyHandle)
+{
+    pfDesiredPropertyDeinitialize result;
+    /*Ccodes_SRS_SCHEMA_02_064: [ If desiredPropertyHandle is NULL then Schema_GetModelDesiredProperty_pfDesiredPropertyDeinitialize shall fail and return NULL. ]*/
+    if (desiredPropertyHandle == NULL)
+    {
+        LogError("invalid argument SCHEMA_DESIRED_PROPERTY_HANDLE desiredPropertyHandle=%p", desiredPropertyHandle);
+        result = NULL;
+    }
+    else
+    {
+        /*Codes_SRS_SCHEMA_02_065: [ Otherwise Schema_GetModelDesiredProperty_pfDesiredPropertyDeinitialize shall return a non-NULL function pointer. ]*/
+        SCHEMA_DESIRED_PROPERTY_HANDLE_DATA* handleData = (SCHEMA_DESIRED_PROPERTY_HANDLE_DATA*)desiredPropertyHandle;
+        result = handleData->desiredPropertDeinitialize;
+    }
+    return result;
+}
+
+pfDesiredPropertyInitialize Schema_GetModelDesiredProperty_pfDesiredPropertyInitialize(SCHEMA_DESIRED_PROPERTY_HANDLE desiredPropertyHandle)
+{
+    pfDesiredPropertyInitialize result;
+    /*Codes_SRS_SCHEMA_02_066: [ If desiredPropertyHandle is NULL then Schema_GetModelDesiredProperty_pfDesiredPropertyInitialize shall fail and return NULL. ]*/
+    if (desiredPropertyHandle == NULL)
+    {
+        LogError("invalid argument SCHEMA_DESIRED_PROPERTY_HANDLE desiredPropertyHandle=%p", desiredPropertyHandle);
+        result = NULL;
+    }
+    else
+    {
+        /*Codes_SRS_SCHEMA_02_067: [ Otherwise Schema_GetModelDesiredProperty_pfDesiredPropertyInitialize shall return a non-NULL function pointer. ]*/
+        SCHEMA_DESIRED_PROPERTY_HANDLE_DATA* handleData = (SCHEMA_DESIRED_PROPERTY_HANDLE_DATA*)desiredPropertyHandle;
+        result = handleData->desiredPropertInitialize;
+    }
+    return result;
+}
+
+static bool SchemaHasModel(const SCHEMA_HANDLE* schemaHandle, const char* modelName)
+{
+    return (Schema_GetModelByName(*schemaHandle, modelName) != NULL);
+}
+
+
+SCHEMA_HANDLE Schema_GetSchemaForModel(const char* modelName)
+{
+    SCHEMA_HANDLE result;
+    /*Codes_SRS_SCHEMA_02_093: [ If modelName is NULL then Schema_GetSchemaForModel shall fail and return NULL. ]*/
+    if (modelName == NULL)
+    {
+        LogError("invalid arg const char* modelName=%p", modelName);
+        result = NULL;
+    }
+    else
+    {
+        /*Codes_SRS_SCHEMA_02_094: [ Schema_GetSchemaForModel shall find the SCHEMA_HANDLE that contains a model by name modelName and if found, succeed and return that. ]*/
+        SCHEMA_HANDLE* temp = VECTOR_find_if(g_schemas, (PREDICATE_FUNCTION)SchemaHasModel, modelName);
+
+        if (temp == NULL)
+        {
+            /*Codes_SRS_SCHEMA_02_095: [ If the model is not found in any schema, then Schema_GetSchemaForModel shall fail and return NULL. ]*/
+            LogError("unable to find a schema that has a model named %s", modelName);
+            result = NULL;
+        }
+        else
+        {
+            /*Codes_SRS_SCHEMA_02_094: [ Schema_GetSchemaForModel shall find the SCHEMA_HANDLE that contains a model by name modelName and if found, succeed and return that. ]*/
+            result = *temp;
+        }
+    }
+
+    return result;
+}
+
+void* Schema_GetMetadata(SCHEMA_HANDLE schemaHandle)
+{
+    void* result;
+    /*Codes_SRS_SCHEMA_02_091: [ If schemaHandle is NULL then Schema_GetMetadata shall fail and return NULL. ]*/
+    if (schemaHandle == NULL)
+    {
+        LogError("invalid arg SCHEMA_HANDLE schemaHandle=%p", schemaHandle);
+        result = NULL;
+    }
+    else
+    {
+        /*Codes_SRS_SCHEMA_02_092: [ Otherwise, Schema_GetMetadata shall succeed and return the saved metadata pointer. ]*/
+        result = ((SCHEMA_HANDLE_DATA*)schemaHandle)->metadata;
+    }
+    return result;
+}