You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@celix.apache.org by pn...@apache.org on 2015/11/05 16:42:04 UTC

[2/3] celix git commit: CELIX-273: Added dyn_message. To support dynamicly allocation & serializing messages

CELIX-273: Added dyn_message. To support dynamicly allocation & serializing messages


Project: http://git-wip-us.apache.org/repos/asf/celix/repo
Commit: http://git-wip-us.apache.org/repos/asf/celix/commit/e1be5f1a
Tree: http://git-wip-us.apache.org/repos/asf/celix/tree/e1be5f1a
Diff: http://git-wip-us.apache.org/repos/asf/celix/diff/e1be5f1a

Branch: refs/heads/develop
Commit: e1be5f1aee386ece63e783a9a6d263a1a2b07678
Parents: b613302
Author: Pepijn Noltes <pe...@gmail.com>
Authored: Thu Nov 5 16:25:07 2015 +0100
Committer: Pepijn Noltes <pe...@gmail.com>
Committed: Thu Nov 5 16:25:07 2015 +0100

----------------------------------------------------------------------
 .../remote_service_admin_dfi/CMakeLists.txt     |   4 +-
 .../dynamic_function_interface/CMakeLists.txt   |   1 +
 .../dynamic_function_interface/dyn_message.c    | 322 +++++++++++++++++++
 .../dynamic_function_interface/dyn_message.h    |  38 +++
 .../CMakeLists.txt                              |   1 +
 .../descriptors/msg_example1.descriptor         |  10 +
 .../descriptors/msg_example2.descriptor         |  12 +
 .../descriptors/msg_example3.descriptor         |  10 +
 .../dyn_message_tests.cpp                       | 184 +++++++++++
 9 files changed, 580 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/celix/blob/e1be5f1a/remote_services/remote_service_admin_dfi/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/remote_services/remote_service_admin_dfi/CMakeLists.txt b/remote_services/remote_service_admin_dfi/CMakeLists.txt
index ba91105..275a991 100644
--- a/remote_services/remote_service_admin_dfi/CMakeLists.txt
+++ b/remote_services/remote_service_admin_dfi/CMakeLists.txt
@@ -16,7 +16,7 @@
 # under the License.
 
 
-celix_subproject(RSA_REMOTE_SERVICE_ADMIN_DFI "Option to enable building the Remote Service Admin Service DFI" OFF)
+celix_subproject(RSA_REMOTE_SERVICE_ADMIN_DFI "Option to enable building the Remote Service Admin Service DFI" ON)
 
 if (RSA_REMOTE_SERVICE_ADMIN_DFI)
 
@@ -44,4 +44,4 @@ if (RSA_REMOTE_SERVICE_ADMIN_DFI)
         add_subdirectory(rsa_tst)
     endif()
 
-endif()
\ No newline at end of file
+endif()

http://git-wip-us.apache.org/repos/asf/celix/blob/e1be5f1a/remote_services/remote_service_admin_dfi/dynamic_function_interface/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/remote_services/remote_service_admin_dfi/dynamic_function_interface/CMakeLists.txt b/remote_services/remote_service_admin_dfi/dynamic_function_interface/CMakeLists.txt
index d7e1bf0..ea79768 100644
--- a/remote_services/remote_service_admin_dfi/dynamic_function_interface/CMakeLists.txt
+++ b/remote_services/remote_service_admin_dfi/dynamic_function_interface/CMakeLists.txt
@@ -29,6 +29,7 @@ add_library(dfi STATIC
     dyn_type.c
     dyn_function.c
     dyn_interface.c
+    dyn_message.c
     json_serializer.c
     json_rpc.c
     ${MEMSTREAM_SOURCES}

http://git-wip-us.apache.org/repos/asf/celix/blob/e1be5f1a/remote_services/remote_service_admin_dfi/dynamic_function_interface/dyn_message.c
----------------------------------------------------------------------
diff --git a/remote_services/remote_service_admin_dfi/dynamic_function_interface/dyn_message.c b/remote_services/remote_service_admin_dfi/dynamic_function_interface/dyn_message.c
new file mode 100644
index 0000000..bfea35a
--- /dev/null
+++ b/remote_services/remote_service_admin_dfi/dynamic_function_interface/dyn_message.c
@@ -0,0 +1,322 @@
+/**
+ * Licensed under Apache License v2. See LICENSE for more information.
+ */
+#include "dyn_message.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "dyn_common.h"
+#include "dyn_type.h"
+
+DFI_SETUP_LOG(dynMessage);
+
+struct _dyn_message_type {
+    struct namvals_head header;
+    struct namvals_head annotations;
+    struct types_head types;
+    dyn_type *msgType;
+};
+
+static const int OK = 0;
+static const int ERROR = 1;
+
+static int dynMessage_parseSection(dyn_message_type *msg, FILE *stream);
+static int dynMessage_parseAnnotations(dyn_message_type *msg, FILE *stream);
+static int dynMessage_parseTypes(dyn_message_type *msg, FILE *stream);
+static int dynMessage_parseMessage(dyn_message_type *msg, FILE *stream);
+static int dynMessage_parseHeader(dyn_message_type *msg, FILE *stream);
+static int dynMessage_parseNameValueSection(dyn_message_type *msg, FILE *stream, struct namvals_head *head);
+static int dynMessage_checkMessage(dyn_message_type *msg);
+static int dynMessage_getEntryForHead(struct namvals_head *head, const char *name, char **value);
+
+int dynMessage_parse(FILE *descriptor, dyn_message_type **out) {
+    int status = OK;
+
+    dyn_message_type *msg = calloc(1, sizeof(*msg));
+    if (msg != NULL) {
+        TAILQ_INIT(&msg->header);
+        TAILQ_INIT(&msg->annotations);
+        TAILQ_INIT(&msg->types);
+
+        char peek = fgetc(descriptor);
+        while (peek == ':') {
+            ungetc(peek, descriptor);
+            status = dynMessage_parseSection(msg, descriptor);
+            if (status == OK) {
+                peek = fgetc(descriptor);
+            } else {
+                break;
+            }
+        }
+
+        if (status == OK) {
+            status = dynCommon_eatChar(descriptor, EOF);
+        }
+
+        if (status == OK) {
+            status = dynMessage_checkMessage(msg);
+        }
+    } else {
+        status = ERROR;
+        LOG_ERROR("Error allocating memory for dynamic message\n");
+    }
+
+    if (status == OK) {
+        *out = msg;
+    } else if (msg != NULL) {
+        dynMessage_destroy(msg);
+    }
+    return status;
+}
+
+static int dynMessage_checkMessage(dyn_message_type *msg) {
+    int status = OK;
+
+    //check header section
+    if (status == OK) {
+        bool foundType = false;
+        bool foundVersion = false;
+        bool foundName = false;
+        struct namval_entry *entry = NULL;
+        TAILQ_FOREACH(entry, &msg->header, entries) {
+            if (strcmp(entry->name, "type") == 0) {
+                foundType = true;
+            } else if (strcmp(entry->name, "version") == 0) {
+                foundVersion = true;
+            } else if (strcmp(entry->name, "name") == 0) {
+                foundName = true;
+            }
+        }
+
+        if (!foundType || !foundVersion || !foundName) {
+            status = ERROR;
+            LOG_ERROR("Parse Error. There must be a header section with a type, version and name entry");
+        }
+    }
+
+    return status;
+}
+
+static int dynMessage_parseSection(dyn_message_type *msg, FILE *stream) {
+    int status = OK;
+    char *sectionName = NULL;
+
+    status = dynCommon_eatChar(stream, ':');
+
+    if (status == OK) {
+        status = dynCommon_parseName(stream, &sectionName);
+    }
+
+    if (status == OK) {
+        status = dynCommon_eatChar(stream, '\n');
+    }
+
+    if (status == OK) {
+        if (strcmp("header", sectionName) == 0) {
+            status = dynMessage_parseHeader(msg, stream);
+        } else if (strcmp("annotations", sectionName) == 0) {
+            status = dynMessage_parseAnnotations(msg, stream);
+        } else if (strcmp("types", sectionName) == 0) {
+            status = dynMessage_parseTypes(msg, stream);
+        } else if (strcmp("message", sectionName) == 0) {
+            status = dynMessage_parseMessage(msg, stream);
+        } else {
+            status = ERROR;
+            LOG_ERROR("unsupported section '%s'", sectionName);
+        }
+    }
+
+    if (sectionName != NULL) {
+        free(sectionName);
+    }
+
+    return status;
+}
+
+static int dynMessage_parseHeader(dyn_message_type *msg, FILE *stream) {
+    return dynMessage_parseNameValueSection(msg, stream, &msg->header);
+}
+
+static int dynMessage_parseAnnotations(dyn_message_type *msg, FILE *stream) {
+    return dynMessage_parseNameValueSection(msg, stream, &msg->annotations);
+}
+
+static int dynMessage_parseNameValueSection(dyn_message_type *msg, FILE *stream, struct namvals_head *head) {
+    int status = OK;
+
+    int peek = fgetc(stream);
+    while (peek != ':' && peek != EOF) {
+        ungetc(peek, stream);
+
+        char *name;
+        char *value;
+        status = dynCommon_parseNameValue(stream, &name, &value);
+
+        if (status == OK) {
+            status = dynCommon_eatChar(stream, '\n');
+        }
+
+        struct namval_entry *entry = NULL;
+        if (status == OK) {
+            entry = calloc(1, sizeof(*entry));
+            if (entry != NULL) {
+                entry->name = name;
+                entry->value = value;
+                TAILQ_INSERT_TAIL(head, entry, entries);
+            } else {
+                status = ERROR;
+                LOG_ERROR("Error allocating memory for namval entry");
+            }
+        }
+
+        if (status != OK) {
+            if (name != NULL) {
+                free(name);
+            }
+            if (value != NULL) {
+                free(value);
+            }
+            if (entry != NULL) {
+                free(entry);
+            }
+            break;
+        }
+        peek = fgetc(stream);
+    }
+    ungetc(peek, stream);
+
+    return status;
+}
+
+static int dynMessage_parseTypes(dyn_message_type *msg, FILE *stream) {
+    int status = OK;
+
+    //expected input (Name)=<Type>\n
+    int peek = fgetc(stream);
+    while (peek != ':' && peek != EOF) {
+        ungetc(peek, stream);
+
+        char *name;
+        status = dynCommon_parseName(stream, &name);
+
+        if (status == OK) {
+            status = dynCommon_eatChar(stream, '=');
+        }
+
+        dyn_type *type = NULL;
+        if (status == OK) {
+            dynType_parse(stream, name, &msg->types, &type);
+        }
+        if (name != NULL) {
+            free(name);
+        }
+
+        if (status == OK) {
+            status = dynCommon_eatChar(stream, '\n');
+        }
+
+        struct type_entry *entry = NULL;
+        if (status == OK) {
+            entry = calloc(1, sizeof(*entry));
+            if (entry != NULL) {
+                entry->type = type;
+                TAILQ_INSERT_TAIL(&msg->types, entry, entries);
+            } else {
+                status = ERROR;
+                LOG_ERROR("Error allocating memory for type entry");
+            }
+        }
+
+        if (status != OK) {
+            if (type != NULL) {
+                dynType_destroy(type);
+            }
+            if (entry != NULL) {
+                free(entry);
+            }
+            break;
+        }
+        peek = fgetc(stream);
+    }
+    ungetc(peek, stream);
+
+    return status;
+}
+
+static int dynMessage_parseMessage(dyn_message_type *msg, FILE *stream) {
+    int status = OK;
+
+    //expected input <dynType>\n
+    char *name = NULL;
+    status = dynMessage_getName(msg, &name);
+
+    if (status == OK) {
+    	status = dynType_parse(stream, name, &(msg->types), &(msg->msgType));
+    }
+
+    return status;
+}
+
+void dynMessage_destroy(dyn_message_type *msg) {
+    if (msg != NULL) {
+        dynCommon_clearNamValHead(&msg->header);
+        dynCommon_clearNamValHead(&msg->annotations);
+
+        struct type_entry *tmp = NULL;
+        struct type_entry *tInfo = TAILQ_FIRST(&msg->types);
+        while (tInfo != NULL) {
+            tmp = tInfo;
+            tInfo = TAILQ_NEXT(tInfo, entries);
+            dynType_destroy(tmp->type);
+            free(tmp);
+        }
+
+        if (msg->msgType != NULL) {
+        	dynType_destroy(msg->msgType);
+        }
+
+        free(msg);
+    } 
+}
+
+int dynMessage_getName(dyn_message_type *msg, char **out) {
+    return dynMessage_getEntryForHead(&msg->header, "name", out);
+}
+
+int dynMessage_getVersion(dyn_message_type *msg, char **version) {
+    return dynMessage_getEntryForHead(&msg->header, "version", version);
+}
+
+int dynMessage_getHeaderEntry(dyn_message_type *msg, const char *name, char **value) {
+    return dynMessage_getEntryForHead(&msg->header, name, value);
+}
+
+int dynMessage_getAnnotationEntry(dyn_message_type *msg, const char *name, char **value) {
+    return dynMessage_getEntryForHead(&msg->annotations, name, value);
+}
+
+static int dynMessage_getEntryForHead(struct namvals_head *head, const char *name, char **out) {
+    int status = OK;
+    char *value = NULL;
+    struct namval_entry *entry = NULL;
+    TAILQ_FOREACH(entry, head, entries) {
+        if (strcmp(name, entry->name) == 0) {
+            value = entry->value;
+            break;
+        }
+    }
+    if (value != NULL) {
+        *out = value;
+    } else {
+        status = ERROR;
+        LOG_WARNING("Cannot find '%s' in list", name);
+    }
+    return status;
+}
+
+int dynMessage_getMessageType(dyn_message_type *msg, dyn_type **type) {
+	int status = OK;
+	*type = msg->msgType;
+	return status;
+}

http://git-wip-us.apache.org/repos/asf/celix/blob/e1be5f1a/remote_services/remote_service_admin_dfi/dynamic_function_interface/dyn_message.h
----------------------------------------------------------------------
diff --git a/remote_services/remote_service_admin_dfi/dynamic_function_interface/dyn_message.h b/remote_services/remote_service_admin_dfi/dynamic_function_interface/dyn_message.h
new file mode 100644
index 0000000..1116ab3
--- /dev/null
+++ b/remote_services/remote_service_admin_dfi/dynamic_function_interface/dyn_message.h
@@ -0,0 +1,38 @@
+/*
+ * Licensed under Apache License v2. See LICENSE for more information.
+ */
+#ifndef __DYN_MESSAGE_H_
+#define __DYN_MESSAGE_H_
+
+#include "dyn_common.h"
+#include "dyn_type.h"
+#include "dfi_log_util.h"
+
+DFI_SETUP_LOG_HEADER(dynMessage);
+
+/* Description string
+ *
+ * Descriptor (message) = HeaderSection AnnotationSection TypesSection MessageSection
+ *
+ * HeaderSection=
+ * ':header\n' [NameValue]*
+ * ':annotations\n' [NameValue]*
+ * ':types\n' [TypeIdValue]*
+ * ':message\n' [MessageIdValue]
+ *
+ */
+typedef struct _dyn_message_type dyn_message_type;
+
+
+int dynMessage_parse(FILE *descriptor, dyn_message_type **out);
+void dynMessage_destroy(dyn_message_type *msg);
+
+int dynMessage_getName(dyn_message_type *msg, char **name);
+int dynMessage_getVersion(dyn_message_type *msg, char **version);
+int dynMessage_getHeaderEntry(dyn_message_type *msg, const char *name, char **value);
+int dynMessage_getAnnotationEntry(dyn_message_type *msg, const char *name, char **value);
+int dynMessage_getMessageType(dyn_message_type *msg, dyn_type **type);
+
+
+
+#endif

http://git-wip-us.apache.org/repos/asf/celix/blob/e1be5f1a/remote_services/remote_service_admin_dfi/dynamic_function_interface_tst/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/remote_services/remote_service_admin_dfi/dynamic_function_interface_tst/CMakeLists.txt b/remote_services/remote_service_admin_dfi/dynamic_function_interface_tst/CMakeLists.txt
index bfb0f58..3c8a800 100644
--- a/remote_services/remote_service_admin_dfi/dynamic_function_interface_tst/CMakeLists.txt
+++ b/remote_services/remote_service_admin_dfi/dynamic_function_interface_tst/CMakeLists.txt
@@ -24,6 +24,7 @@ add_executable(test_dfi
 	dyn_function_tests.cpp
 	dyn_closure_tests.cpp
 	dyn_interface_tests.cpp
+	dyn_message_tests.cpp
 	json_serializer_tests.cpp
 	json_rpc_tests.cpp
 	run_tests.cpp

http://git-wip-us.apache.org/repos/asf/celix/blob/e1be5f1a/remote_services/remote_service_admin_dfi/dynamic_function_interface_tst/descriptors/msg_example1.descriptor
----------------------------------------------------------------------
diff --git a/remote_services/remote_service_admin_dfi/dynamic_function_interface_tst/descriptors/msg_example1.descriptor b/remote_services/remote_service_admin_dfi/dynamic_function_interface_tst/descriptors/msg_example1.descriptor
new file mode 100644
index 0000000..576523a
--- /dev/null
+++ b/remote_services/remote_service_admin_dfi/dynamic_function_interface_tst/descriptors/msg_example1.descriptor
@@ -0,0 +1,10 @@
+:header
+type=message
+name=poi
+version=1.0.0
+:annotations
+classname=org.example.PointOfInterest
+:types
+location={DD lat long}
+:message
+{llocation;tt location name description}

http://git-wip-us.apache.org/repos/asf/celix/blob/e1be5f1a/remote_services/remote_service_admin_dfi/dynamic_function_interface_tst/descriptors/msg_example2.descriptor
----------------------------------------------------------------------
diff --git a/remote_services/remote_service_admin_dfi/dynamic_function_interface_tst/descriptors/msg_example2.descriptor b/remote_services/remote_service_admin_dfi/dynamic_function_interface_tst/descriptors/msg_example2.descriptor
new file mode 100644
index 0000000..128049d
--- /dev/null
+++ b/remote_services/remote_service_admin_dfi/dynamic_function_interface_tst/descriptors/msg_example2.descriptor
@@ -0,0 +1,12 @@
+:header
+type=message
+name=track
+version=0.0.1
+:annotations
+classname=org.example.Track
+:types
+timestamp={SSSSSSI day month year hour minute second microseconds}
+latlonpos={DD lat lon}
+polarpos={DDD azimuth elevation range}
+:message
+{Iltimestamp;llatlonpos;lpolarpos;SS trackid lastupdate abspos relpos classification identity}

http://git-wip-us.apache.org/repos/asf/celix/blob/e1be5f1a/remote_services/remote_service_admin_dfi/dynamic_function_interface_tst/descriptors/msg_example3.descriptor
----------------------------------------------------------------------
diff --git a/remote_services/remote_service_admin_dfi/dynamic_function_interface_tst/descriptors/msg_example3.descriptor b/remote_services/remote_service_admin_dfi/dynamic_function_interface_tst/descriptors/msg_example3.descriptor
new file mode 100644
index 0000000..7b69380
--- /dev/null
+++ b/remote_services/remote_service_admin_dfi/dynamic_function_interface_tst/descriptors/msg_example3.descriptor
@@ -0,0 +1,10 @@
+:header
+type=message
+name=logEntry
+version=1.0.0
+:annotations
+classname=org.example.LogEntry
+:types
+timestamp={SSSSSSI day month year hour minute second microseconds}
+:message
+{ltimestamp;St timestamp severity eventdescription}

http://git-wip-us.apache.org/repos/asf/celix/blob/e1be5f1a/remote_services/remote_service_admin_dfi/dynamic_function_interface_tst/dyn_message_tests.cpp
----------------------------------------------------------------------
diff --git a/remote_services/remote_service_admin_dfi/dynamic_function_interface_tst/dyn_message_tests.cpp b/remote_services/remote_service_admin_dfi/dynamic_function_interface_tst/dyn_message_tests.cpp
new file mode 100644
index 0000000..e30d16e
--- /dev/null
+++ b/remote_services/remote_service_admin_dfi/dynamic_function_interface_tst/dyn_message_tests.cpp
@@ -0,0 +1,184 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements.  See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership.  The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ */
+#include <CppUTest/TestHarness.h>
+#include "CppUTest/CommandLineTestRunner.h"
+
+extern "C" {
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "dyn_common.h"
+#include "dyn_message.h"
+
+#if defined(BSD) || defined(__APPLE__) 
+#include "open_memstream.h"
+#include "fmemopen.h"
+#endif
+
+static void stdLog(void *handle, int level, const char *file, int line, const char *msg, ...) {
+	va_list ap;
+	const char *levels[5] = {"NIL", "ERROR", "WARNING", "INFO", "DEBUG"};
+	fprintf(stderr, "%s: FILE:%s, LINE:%i, MSG:",levels[level], file, line);
+	va_start(ap, msg);
+	vfprintf(stderr, msg, ap);
+	fprintf(stderr, "\n");
+}
+
+
+static void msg_test1(void) {
+	int status = 0;
+	dyn_message_type *dynMsg = NULL;
+	FILE *desc = fopen("descriptors/msg_example1.descriptor", "r");
+	assert(desc != NULL);
+	status = dynMessage_parse(desc, &dynMsg);
+	CHECK_EQUAL(0, status);
+	fclose(desc);
+
+	char *name = NULL;
+	status = dynMessage_getName(dynMsg, &name);
+	CHECK_EQUAL(0, status);
+	STRCMP_EQUAL("poi", name);
+
+	char *version = NULL;
+	status = dynMessage_getVersion(dynMsg, &version);
+	CHECK_EQUAL(0, status);
+	STRCMP_EQUAL("1.0.0", version);
+
+	char *annVal = NULL;
+	status = dynMessage_getAnnotationEntry(dynMsg, "classname", &annVal);
+	CHECK_EQUAL(0, status);
+	STRCMP_EQUAL("org.example.PointOfInterest", annVal);
+
+	char *nonExist = NULL;
+	status = dynMessage_getHeaderEntry(dynMsg, "nonExisting", &nonExist);
+	CHECK(status != 0);
+	CHECK(nonExist == NULL);
+
+	dyn_type *msgType = NULL;
+	status = dynMessage_getMessageType(dynMsg, &msgType);
+	CHECK_EQUAL(0, status);
+	CHECK(msgType != NULL);
+
+	dynMessage_destroy(dynMsg);
+}
+
+
+static void msg_test2(void) {
+	int status = 0;
+	dyn_message_type *dynMsg = NULL;
+	FILE *desc = fopen("descriptors/msg_example2.descriptor", "r");
+	assert(desc != NULL);
+	status = dynMessage_parse(desc, &dynMsg);
+	CHECK_EQUAL(0, status);
+	fclose(desc);
+
+	char *name = NULL;
+	status = dynMessage_getName(dynMsg, &name);
+	CHECK_EQUAL(0, status);
+	STRCMP_EQUAL("track", name);
+
+	char *version = NULL;
+	status = dynMessage_getVersion(dynMsg, &version);
+	CHECK_EQUAL(0, status);
+	STRCMP_EQUAL("0.0.1", version);
+
+	char *annVal = NULL;
+	status = dynMessage_getAnnotationEntry(dynMsg, "classname", &annVal);
+	CHECK_EQUAL(0, status);
+	STRCMP_EQUAL("org.example.Track", annVal);
+
+	char *nonExist = NULL;
+	status = dynMessage_getHeaderEntry(dynMsg, "nonExisting", &nonExist);
+	CHECK(status != 0);
+	CHECK(nonExist == NULL);
+
+	dyn_type *msgType = NULL;
+	status = dynMessage_getMessageType(dynMsg, &msgType);
+	CHECK_EQUAL(0, status);
+	CHECK(msgType != NULL);
+
+	dynMessage_destroy(dynMsg);
+}
+
+static void msg_test3(void) {
+	int status = 0;
+	dyn_message_type *dynMsg = NULL;
+	FILE *desc = fopen("descriptors/msg_example3.descriptor", "r");
+	assert(desc != NULL);
+	status = dynMessage_parse(desc, &dynMsg);
+	CHECK_EQUAL(0, status);
+	fclose(desc);
+
+	char *name = NULL;
+	status = dynMessage_getName(dynMsg, &name);
+	CHECK_EQUAL(0, status);
+	STRCMP_EQUAL("logEntry", name);
+
+	char *version = NULL;
+	status = dynMessage_getVersion(dynMsg, &version);
+	CHECK_EQUAL(0, status);
+	STRCMP_EQUAL("1.0.0", version);
+
+	char *annVal = NULL;
+	status = dynMessage_getAnnotationEntry(dynMsg, "classname", &annVal);
+	CHECK_EQUAL(0, status);
+	STRCMP_EQUAL("org.example.LogEntry", annVal);
+
+	char *nonExist = NULL;
+	status = dynMessage_getHeaderEntry(dynMsg, "nonExisting", &nonExist);
+	CHECK(status != 0);
+	CHECK(nonExist == NULL);
+
+	dyn_type *msgType = NULL;
+	status = dynMessage_getMessageType(dynMsg, &msgType);
+	CHECK_EQUAL(0, status);
+	CHECK(msgType != NULL);
+
+	dynMessage_destroy(dynMsg);
+}
+
+}
+
+
+TEST_GROUP(DynMessageTests) {
+	void setup() {
+		int level = 1;
+		dynCommon_logSetup(stdLog, NULL, level);
+		dynType_logSetup(stdLog, NULL, level);
+		dynMessage_logSetup(stdLog, NULL, level);
+	}
+};
+
+
+TEST(DynMessageTests, msg_test1) {
+	msg_test1();
+}
+
+TEST(DynMessageTests, msg_test2) {
+	msg_test2();
+}
+
+TEST(DynMessageTests, msg_test3) {
+	msg_test3();
+}