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 2017/02/06 14:23:00 UTC

[1/6] celix git commit: CELIX-389: Adds Celix Publish Subscribe donation.

Repository: celix
Updated Branches:
  refs/heads/develop 3e678523e -> f9a5fb11e


http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_discovery/private/src/pubsub_discovery_impl.c
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_discovery/private/src/pubsub_discovery_impl.c b/celix-pubsub/pubsub/pubsub_discovery/private/src/pubsub_discovery_impl.c
new file mode 100644
index 0000000..1b6aca9
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_discovery/private/src/pubsub_discovery_impl.c
@@ -0,0 +1,468 @@
+/**
+ *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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <netdb.h>
+#include <netinet/in.h>
+
+#include "constants.h"
+#include "celix_threads.h"
+#include "bundle_context.h"
+#include "array_list.h"
+#include "utils.h"
+#include "celix_errno.h"
+#include "filter.h"
+#include "service_reference.h"
+#include "service_registration.h"
+
+#include "publisher_endpoint_announce.h"
+#include "etcd_common.h"
+#include "etcd_watcher.h"
+#include "etcd_writer.h"
+#include "pubsub_endpoint.h"
+#include "pubsub_discovery_impl.h"
+
+/* Discovery activator functions */
+celix_status_t pubsub_discovery_create(bundle_context_pt context, pubsub_discovery_pt *ps_discovery) {
+	celix_status_t status = CELIX_SUCCESS;
+
+	*ps_discovery = calloc(1, sizeof(**ps_discovery));
+
+	if (*ps_discovery == NULL) {
+		status = CELIX_ENOMEM;
+	}
+	else{
+		(*ps_discovery)->context = context;
+		(*ps_discovery)->discoveredPubs = hashMap_create(utils_stringHash, NULL, utils_stringEquals, NULL);
+		(*ps_discovery)->listenerReferences = hashMap_create(serviceReference_hashCode, NULL, serviceReference_equals2, NULL);
+		(*ps_discovery)->watchers = hashMap_create(utils_stringHash,NULL,utils_stringEquals, NULL);
+		celixThreadMutex_create(&(*ps_discovery)->listenerReferencesMutex, NULL);
+		celixThreadMutex_create(&(*ps_discovery)->discoveredPubsMutex, NULL);
+		celixThreadMutex_create(&(*ps_discovery)->watchersMutex, NULL);
+	}
+
+	return status;
+}
+
+celix_status_t pubsub_discovery_destroy(pubsub_discovery_pt ps_discovery) {
+	celix_status_t status = CELIX_SUCCESS;
+
+	celixThreadMutex_lock(&ps_discovery->discoveredPubsMutex);
+
+	hash_map_iterator_pt iter = hashMapIterator_create(ps_discovery->discoveredPubs);
+
+	while (hashMapIterator_hasNext(iter)) {
+		array_list_pt pubEP_list = (array_list_pt) hashMapIterator_nextValue(iter);
+
+		for(int i=0; i < arrayList_size(pubEP_list); i++) {
+			pubsubEndpoint_destroy(((pubsub_endpoint_pt)arrayList_get(pubEP_list,i)));
+		}
+		arrayList_destroy(pubEP_list);
+	}
+
+	hashMapIterator_destroy(iter);
+
+	hashMap_destroy(ps_discovery->discoveredPubs, true, false);
+	ps_discovery->discoveredPubs = NULL;
+
+	celixThreadMutex_unlock(&ps_discovery->discoveredPubsMutex);
+
+	celixThreadMutex_destroy(&ps_discovery->discoveredPubsMutex);
+
+
+	celixThreadMutex_lock(&ps_discovery->listenerReferencesMutex);
+
+	hashMap_destroy(ps_discovery->listenerReferences, false, false);
+	ps_discovery->listenerReferences = NULL;
+
+	celixThreadMutex_unlock(&ps_discovery->listenerReferencesMutex);
+
+	celixThreadMutex_destroy(&ps_discovery->listenerReferencesMutex);
+
+	free(ps_discovery);
+
+	return status;
+}
+
+celix_status_t pubsub_discovery_start(pubsub_discovery_pt ps_discovery) {
+    celix_status_t status = CELIX_SUCCESS;
+    status = etcdCommon_init(ps_discovery->context);
+    ps_discovery->writer = etcdWriter_create(ps_discovery);
+
+    return status;
+}
+
+celix_status_t pubsub_discovery_stop(pubsub_discovery_pt ps_discovery) {
+    celix_status_t status = CELIX_SUCCESS;
+
+    const char* fwUUID = NULL;
+
+    bundleContext_getProperty(ps_discovery->context, OSGI_FRAMEWORK_FRAMEWORK_UUID, &fwUUID);
+    if (fwUUID == NULL) {
+        printf("PSD: Cannot retrieve fwUUID.\n");
+        return CELIX_INVALID_BUNDLE_CONTEXT;
+    }
+
+    celixThreadMutex_lock(&ps_discovery->watchersMutex);
+
+    hash_map_iterator_pt iter = hashMapIterator_create(ps_discovery->watchers);
+    while (hashMapIterator_hasNext(iter)) {
+        struct watcher_info * wi = hashMapIterator_nextValue(iter);
+        etcdWatcher_stop(wi->watcher);
+    }
+    hashMapIterator_destroy(iter);
+    celixThreadMutex_unlock(&ps_discovery->watchersMutex);
+
+    celixThreadMutex_lock(&ps_discovery->discoveredPubsMutex);
+
+    /* Unexport all publishers for the local framework, and also delete from ETCD publisher belonging to the local framework */
+
+    iter = hashMapIterator_create(ps_discovery->discoveredPubs);
+    while (hashMapIterator_hasNext(iter)) {
+        array_list_pt pubEP_list = (array_list_pt) hashMapIterator_nextValue(iter);
+
+        int i;
+        for (i = 0; i < arrayList_size(pubEP_list); i++) {
+            pubsub_endpoint_pt pubEP = (pubsub_endpoint_pt) arrayList_get(pubEP_list, i);
+            if (strcmp(pubEP->frameworkUUID, fwUUID) == 0) {
+                etcdWriter_deletePublisherEndpoint(ps_discovery->writer, pubEP);
+            } else {
+                pubsub_discovery_informPublishersListeners(ps_discovery, pubEP, false);
+                arrayList_remove(pubEP_list, i);
+                pubsubEndpoint_destroy(pubEP);
+                i--;
+            }
+        }
+    }
+
+    hashMapIterator_destroy(iter);
+
+    celixThreadMutex_unlock(&ps_discovery->discoveredPubsMutex);
+    etcdWriter_destroy(ps_discovery->writer);
+
+    iter = hashMapIterator_create(ps_discovery->watchers);
+    while (hashMapIterator_hasNext(iter)) {
+        struct watcher_info * wi = hashMapIterator_nextValue(iter);
+        etcdWatcher_destroy(wi->watcher);
+    }
+    hashMapIterator_destroy(iter);
+    hashMap_destroy(ps_discovery->watchers, true, true);
+    celixThreadMutex_unlock(&ps_discovery->watchersMutex);
+    return status;
+}
+
+/* Functions called by the etcd_watcher */
+
+celix_status_t pubsub_discovery_addNode(pubsub_discovery_pt pubsub_discovery, pubsub_endpoint_pt pubEP) {
+	celix_status_t status = CELIX_SUCCESS;
+	bool inform=false;
+	celixThreadMutex_lock(&pubsub_discovery->discoveredPubsMutex);
+
+	char *pubs_key = createScopeTopicKey(pubEP->scope, pubEP->topic);
+	array_list_pt pubEP_list = (array_list_pt)hashMap_get(pubsub_discovery->discoveredPubs,pubs_key);
+	if(pubEP_list==NULL){
+		arrayList_create(&pubEP_list);
+		arrayList_add(pubEP_list,pubEP);
+		hashMap_put(pubsub_discovery->discoveredPubs,strdup(pubs_key),pubEP_list);
+		inform=true;
+	}
+	else{
+		int i;
+		bool found = false;
+		for(i=0;i<arrayList_size(pubEP_list) && !found;i++){
+			found = pubsubEndpoint_equals(pubEP,(pubsub_endpoint_pt)arrayList_get(pubEP_list,i));
+		}
+		if(found){
+			pubsubEndpoint_destroy(pubEP);
+		}
+		else{
+			arrayList_add(pubEP_list,pubEP);
+			inform=true;
+    	}
+	}
+	free(pubs_key);
+
+	celixThreadMutex_unlock(&pubsub_discovery->discoveredPubsMutex);
+
+	if(inform){
+	    status = pubsub_discovery_informPublishersListeners(pubsub_discovery,pubEP,true);
+	}
+
+	return status;
+}
+
+celix_status_t pubsub_discovery_removeNode(pubsub_discovery_pt pubsub_discovery, pubsub_endpoint_pt pubEP) {
+    celix_status_t status = CELIX_SUCCESS;
+    pubsub_endpoint_pt p = NULL;
+    bool found = false;
+
+    celixThreadMutex_lock(&pubsub_discovery->discoveredPubsMutex);
+    char *pubs_key = createScopeTopicKey(pubEP->scope, pubEP->topic);
+    array_list_pt pubEP_list = (array_list_pt) hashMap_get(pubsub_discovery->discoveredPubs, pubs_key);
+    free(pubs_key);
+    if (pubEP_list == NULL) {
+        printf("PSD: Cannot find any registered publisher for topic %s. Something is not consistent.\n", pubEP->topic);
+        status = CELIX_ILLEGAL_STATE;
+    } else {
+        int i;
+
+        for (i = 0; !found && i < arrayList_size(pubEP_list); i++) {
+            p = arrayList_get(pubEP_list, i);
+            found = pubsubEndpoint_equals(pubEP, p);
+            if (found) {
+                arrayList_remove(pubEP_list, i);
+                pubsubEndpoint_destroy(p);
+            }
+        }
+    }
+
+    celixThreadMutex_unlock(&pubsub_discovery->discoveredPubsMutex);
+    if (found) {
+        status = pubsub_discovery_informPublishersListeners(pubsub_discovery, pubEP, false);
+    }
+    pubsubEndpoint_destroy(pubEP);
+
+    return status;
+}
+
+/* Callback to the pubsub_topology_manager */
+celix_status_t pubsub_discovery_informPublishersListeners(pubsub_discovery_pt pubsub_discovery, pubsub_endpoint_pt pubEP, bool epAdded) {
+	celix_status_t status = CELIX_SUCCESS;
+
+	// Inform listeners of new publisher endpoint
+	celixThreadMutex_lock(&pubsub_discovery->listenerReferencesMutex);
+
+	if (pubsub_discovery->listenerReferences != NULL) {
+		hash_map_iterator_pt iter = hashMapIterator_create(pubsub_discovery->listenerReferences);
+		while (hashMapIterator_hasNext(iter)) {
+			service_reference_pt reference = hashMapIterator_nextKey(iter);
+
+			publisher_endpoint_announce_pt listener = NULL;
+
+			bundleContext_getService(pubsub_discovery->context, reference, (void**) &listener);
+            if (epAdded) {
+                listener->announcePublisher(listener->handle, pubEP);
+            } else {
+                listener->removePublisher(listener->handle, pubEP);
+            }
+            bundleContext_ungetService(pubsub_discovery->context, reference, NULL);
+		}
+		hashMapIterator_destroy(iter);
+	}
+
+	celixThreadMutex_unlock(&pubsub_discovery->listenerReferencesMutex);
+
+	return status;
+}
+
+
+/* Service's functions implementation */
+celix_status_t pubsub_discovery_announcePublisher(void *handle, pubsub_endpoint_pt pubEP) {
+	celix_status_t status = CELIX_SUCCESS;
+	printf("pubsub_discovery_announcePublisher : %s / %s\n", pubEP->topic, pubEP->endpoint);
+	pubsub_discovery_pt pubsub_discovery = (pubsub_discovery_pt) handle;
+
+	celixThreadMutex_lock(&pubsub_discovery->discoveredPubsMutex);
+
+	char *pub_key = createScopeTopicKey(pubEP->scope,pubEP->topic);
+	array_list_pt pubEP_list = (array_list_pt)hashMap_get(pubsub_discovery->discoveredPubs,pub_key);
+
+	if(pubEP_list==NULL){
+		arrayList_create(&pubEP_list);
+		hashMap_put(pubsub_discovery->discoveredPubs,strdup(pub_key),pubEP_list);
+	}
+	free(pub_key);
+	pubsub_endpoint_pt p = NULL;
+	pubsubEndpoint_create(pubEP->frameworkUUID,pubEP->scope,pubEP->topic,pubEP->serviceID,pubEP->endpoint,&p);
+
+	arrayList_add(pubEP_list,p);
+
+	status = etcdWriter_addPublisherEndpoint(pubsub_discovery->writer,p,true);
+
+	celixThreadMutex_unlock(&pubsub_discovery->discoveredPubsMutex);
+
+	return status;
+}
+
+celix_status_t pubsub_discovery_removePublisher(void *handle, pubsub_endpoint_pt pubEP) {
+	celix_status_t status = CELIX_SUCCESS;
+
+	pubsub_discovery_pt pubsub_discovery = (pubsub_discovery_pt) handle;
+
+	celixThreadMutex_lock(&pubsub_discovery->discoveredPubsMutex);
+
+	char *pub_key = createScopeTopicKey(pubEP->scope,pubEP->topic);
+	array_list_pt pubEP_list = (array_list_pt)hashMap_get(pubsub_discovery->discoveredPubs,pub_key);
+	free(pub_key);
+	if(pubEP_list==NULL){
+		printf("PSD: Cannot find any registered publisher for topic %s. Something is not consistent.\n",pubEP->topic);
+		return CELIX_ILLEGAL_STATE;
+	}
+	else{
+
+		int i;
+		bool found = false;
+		pubsub_endpoint_pt p = NULL;
+
+		for(i=0;!found && i<arrayList_size(pubEP_list);i++){
+			p = (pubsub_endpoint_pt)arrayList_get(pubEP_list,i);
+			found = pubsubEndpoint_equals(pubEP,p);
+		}
+
+		if(!found){
+			printf("PSD: Trying to remove a not existing endpoint. Something is not consistent.\n");
+			status = CELIX_ILLEGAL_STATE;
+		}
+		else{
+
+			arrayList_removeElement(pubEP_list,p);
+
+			status = etcdWriter_deletePublisherEndpoint(pubsub_discovery->writer,p);
+
+			pubsubEndpoint_destroy(p);
+		}
+	}
+
+	celixThreadMutex_unlock(&pubsub_discovery->discoveredPubsMutex);
+
+	return status;
+}
+
+celix_status_t pubsub_discovery_interestedInTopic(void *handle, const char* scope, const char* topic) {
+    pubsub_discovery_pt pubsub_discovery = (pubsub_discovery_pt) handle;
+
+    char *scope_topic_key = createScopeTopicKey(scope, topic);
+    celixThreadMutex_lock(&pubsub_discovery->watchersMutex);
+    struct watcher_info * wi = hashMap_get(pubsub_discovery->watchers, scope_topic_key);
+    if(wi) {
+        wi->nr_references++;
+        free(scope_topic_key);
+    } else {
+        wi = calloc(1, sizeof(*wi));
+        etcdWatcher_create(pubsub_discovery, pubsub_discovery->context, scope, topic, &wi->watcher);
+        wi->nr_references = 1;
+        hashMap_put(pubsub_discovery->watchers, scope_topic_key, wi);
+    }
+
+    celixThreadMutex_unlock(&pubsub_discovery->watchersMutex);
+
+    return CELIX_SUCCESS;
+}
+
+celix_status_t pubsub_discovery_uninterestedInTopic(void *handle, const char* scope, const char* topic) {
+    pubsub_discovery_pt pubsub_discovery = (pubsub_discovery_pt) handle;
+
+    char *scope_topic_key = createScopeTopicKey(scope, topic);
+    celixThreadMutex_lock(&pubsub_discovery->watchersMutex);
+
+    hash_map_entry_pt entry =  hashMap_getEntry(pubsub_discovery->watchers, scope_topic_key);
+    if(entry) {
+        struct watcher_info * wi = hashMapEntry_getValue(entry);
+        wi->nr_references--;
+        if(wi->nr_references == 0) {
+            char *key = hashMapEntry_getKey(entry);
+            hashMap_remove(pubsub_discovery->watchers, scope_topic_key);
+            free(key);
+            free(scope_topic_key);
+            etcdWatcher_stop(wi->watcher);
+            etcdWatcher_destroy(wi->watcher);
+            free(wi);
+        }
+    } else {
+        fprintf(stderr, "[DISC] Inconsistency error: Removing unknown topic %s\n", topic);
+    }
+    celixThreadMutex_unlock(&pubsub_discovery->watchersMutex);
+    return CELIX_SUCCESS;
+}
+
+/* pubsub_topology_manager tracker callbacks */
+
+celix_status_t pubsub_discovery_tmPublisherAnnounceAdding(void * handle, service_reference_pt reference, void **service) {
+	celix_status_t status = CELIX_SUCCESS;
+
+	pubsub_discovery_pt pubsub_discovery = (pubsub_discovery_pt)handle;
+
+	status = bundleContext_getService(pubsub_discovery->context, reference, service);
+
+	return status;
+}
+
+celix_status_t pubsub_discovery_tmPublisherAnnounceAdded(void * handle, service_reference_pt reference, void * service) {
+	celix_status_t status = CELIX_SUCCESS;
+
+	pubsub_discovery_pt pubsub_discovery = (pubsub_discovery_pt)handle;
+	publisher_endpoint_announce_pt listener = (publisher_endpoint_announce_pt)service;
+
+	celixThreadMutex_lock(&pubsub_discovery->discoveredPubsMutex);
+	celixThreadMutex_lock(&pubsub_discovery->listenerReferencesMutex);
+
+	/* Notify the PSTM about discovered publisher endpoints */
+	hash_map_iterator_pt iter = hashMapIterator_create(pubsub_discovery->discoveredPubs);
+	while(hashMapIterator_hasNext(iter)){
+		array_list_pt pubEP_list = (array_list_pt)hashMapIterator_nextValue(iter);
+		int i;
+		for(i=0;i<arrayList_size(pubEP_list);i++){
+			pubsub_endpoint_pt pubEP = (pubsub_endpoint_pt)arrayList_get(pubEP_list,i);
+			status += listener->announcePublisher(listener->handle, pubEP);
+		}
+	}
+
+	hashMapIterator_destroy(iter);
+
+	hashMap_put(pubsub_discovery->listenerReferences, reference, NULL);
+
+	celixThreadMutex_unlock(&pubsub_discovery->listenerReferencesMutex);
+	celixThreadMutex_unlock(&pubsub_discovery->discoveredPubsMutex);
+
+	printf("PSD: pubsub_tm_announce_publisher added.\n");
+
+	return status;
+}
+
+celix_status_t pubsub_discovery_tmPublisherAnnounceModified(void * handle, service_reference_pt reference, void * service) {
+	celix_status_t status = CELIX_SUCCESS;
+
+	status = pubsub_discovery_tmPublisherAnnounceRemoved(handle, reference, service);
+	if (status == CELIX_SUCCESS) {
+		status = pubsub_discovery_tmPublisherAnnounceAdded(handle, reference, service);
+	}
+
+	return status;
+}
+
+celix_status_t pubsub_discovery_tmPublisherAnnounceRemoved(void * handle, service_reference_pt reference, void * service) {
+	celix_status_t status = CELIX_SUCCESS;
+	pubsub_discovery_pt pubsub_discovery = handle;
+
+	celixThreadMutex_lock(&pubsub_discovery->listenerReferencesMutex);
+
+	if (pubsub_discovery->listenerReferences != NULL) {
+		if (hashMap_remove(pubsub_discovery->listenerReferences, reference)) {
+			printf("PSD: pubsub_tm_announce_publisher removed.\n");
+		}
+	}
+	celixThreadMutex_unlock(&pubsub_discovery->listenerReferencesMutex);
+
+	return status;
+}
+

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_discovery/public/include/pubsub_discovery.h
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_discovery/public/include/pubsub_discovery.h b/celix-pubsub/pubsub/pubsub_discovery/public/include/pubsub_discovery.h
new file mode 100644
index 0000000..f77905a
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_discovery/public/include/pubsub_discovery.h
@@ -0,0 +1,26 @@
+/**
+ *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.
+ */
+
+#ifndef PUBSUB_DISCOVERY_H_
+#define PUBSUB_DISCOVERY_H_
+
+typedef struct pubsub_discovery *pubsub_discovery_pt;
+
+
+#endif /* PUBSUB_DISCOVERY_H_ */

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_topology_manager/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_topology_manager/CMakeLists.txt b/celix-pubsub/pubsub/pubsub_topology_manager/CMakeLists.txt
new file mode 100644
index 0000000..02540f3
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_topology_manager/CMakeLists.txt
@@ -0,0 +1,43 @@
+# 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_directories("${PROJECT_SOURCE_DIR}/log_service/public/include")
+include_directories("${PROJECT_SOURCE_DIR}/remote_services/remote_service_admin/public/include")
+include_directories("${PROJECT_SOURCE_DIR}/pubsub/pubsub_common/public/include")
+include_directories("${PROJECT_SOURCE_DIR}/pubsub/pubsub_admin/public/include")
+include_directories("${PROJECT_SOURCE_DIR}/pubsub/api/pubsub")
+include_directories("private/include")
+include_directories("public/include")
+
+add_bundle(org.apache.celix.pubsub_topology_manager.PubSubTopologyManager
+    BUNDLE_SYMBOLICNAME "apache_celix_pubsub_topology_manager"
+    VERSION "1.0.0"
+    SOURCES
+    	private/src/pstm_activator.c
+    	private/src/pubsub_topology_manager.c
+    	${PROJECT_SOURCE_DIR}/pubsub/pubsub_common/public/src/pubsub_endpoint.c
+    	${PROJECT_SOURCE_DIR}/pubsub/pubsub_common/public/src/log_helper.c
+    	${PROJECT_SOURCE_DIR}/pubsub/pubsub_common/public/src/pubsub_utils.c	
+)
+
+bundle_files(org.apache.celix.pubsub_topology_manager.PubSubTopologyManager
+   ${PROJECT_SOURCE_DIR}/pubsub/pubsub_common/public/include/pubsub_topic_info.descriptor
+    DESTINATION "META-INF/"
+)
+
+install_bundle(org.apache.celix.pubsub_topology_manager.PubSubTopologyManager)
+

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_topology_manager/private/include/pubsub_topology_manager.h
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_topology_manager/private/include/pubsub_topology_manager.h b/celix-pubsub/pubsub/pubsub_topology_manager/private/include/pubsub_topology_manager.h
new file mode 100644
index 0000000..2e940aa
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_topology_manager/private/include/pubsub_topology_manager.h
@@ -0,0 +1,86 @@
+/**
+ *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.
+ */
+/*
+ * pubsub_topology_manager.h
+ *
+ *  \date       Sep 29, 2011
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#ifndef PUBSUB_TOPOLOGY_MANAGER_H_
+#define PUBSUB_TOPOLOGY_MANAGER_H_
+
+#include "endpoint_listener.h"
+#include "service_reference.h"
+#include "bundle_context.h"
+#include "log_helper.h"
+
+#include "pubsub_common.h"
+#include "pubsub_endpoint.h"
+#include "publisher.h"
+#include "subscriber.h"
+
+
+struct pubsub_topology_manager {
+	bundle_context_pt context;
+
+	celix_thread_mutex_t psaListLock;
+	array_list_pt psaList;
+
+	celix_thread_mutex_t discoveryListLock;
+	hash_map_pt discoveryList; //<serviceReference,NULL>
+
+	celix_thread_mutex_t publicationsLock;
+	hash_map_pt publications; //<topic(string),list<pubsub_ep>>
+
+	celix_thread_mutex_t subscriptionsLock;
+	hash_map_pt subscriptions; //<topic(string),list<pubsub_ep>>
+
+	log_helper_pt loghelper;
+};
+
+typedef struct pubsub_topology_manager *pubsub_topology_manager_pt;
+
+celix_status_t pubsub_topologyManager_create(bundle_context_pt context, log_helper_pt logHelper, pubsub_topology_manager_pt *manager);
+celix_status_t pubsub_topologyManager_destroy(pubsub_topology_manager_pt manager);
+celix_status_t pubsub_topologyManager_closeImports(pubsub_topology_manager_pt manager);
+
+celix_status_t pubsub_topologyManager_psaAdding(void *handle, service_reference_pt reference, void **service);
+celix_status_t pubsub_topologyManager_psaAdded(void *handle, service_reference_pt reference, void *service);
+celix_status_t pubsub_topologyManager_psaModified(void *handle, service_reference_pt reference, void *service);
+celix_status_t pubsub_topologyManager_psaRemoved(void *handle, service_reference_pt reference, void *service);
+
+celix_status_t pubsub_topologyManager_pubsubDiscoveryAdding(void* handle, service_reference_pt reference, void** service);
+celix_status_t pubsub_topologyManager_pubsubDiscoveryAdded(void* handle, service_reference_pt reference, void* service);
+celix_status_t pubsub_topologyManager_pubsubDiscoveryModified(void * handle, service_reference_pt reference, void* service);
+celix_status_t pubsub_topologyManager_pubsubDiscoveryRemoved(void * handle, service_reference_pt reference, void* service);
+
+celix_status_t pubsub_topologyManager_subscriberAdding(void * handle, service_reference_pt reference, void **service);
+celix_status_t pubsub_topologyManager_subscriberAdded(void * handle, service_reference_pt reference, void * service);
+celix_status_t pubsub_topologyManager_subscriberModified(void * handle, service_reference_pt reference, void * service);
+celix_status_t pubsub_topologyManager_subscriberRemoved(void * handle, service_reference_pt reference, void * service);
+
+celix_status_t pubsub_topologyManager_publisherTrackerAdded(void *handle, array_list_pt listeners);
+celix_status_t pubsub_topologyManager_publisherTrackerRemoved(void *handle, array_list_pt listeners);
+
+celix_status_t pubsub_topologyManager_announcePublisher(void *handle, pubsub_endpoint_pt pubEP);
+celix_status_t pubsub_topologyManager_removePublisher(void *handle, pubsub_endpoint_pt pubEP);
+
+#endif /* PUBSUB_TOPOLOGY_MANAGER_H_ */

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_topology_manager/private/src/pstm_activator.c
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_topology_manager/private/src/pstm_activator.c b/celix-pubsub/pubsub/pubsub_topology_manager/private/src/pstm_activator.c
new file mode 100644
index 0000000..ae7b4a9
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_topology_manager/private/src/pstm_activator.c
@@ -0,0 +1,233 @@
+/**
+ *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.
+ */
+/*
+ * pstm_activator.c
+ *
+ *  \date       Sep 29, 2011
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "constants.h"
+#include "bundle_activator.h"
+#include "service_tracker.h"
+#include "service_registration.h"
+
+#include "endpoint_listener.h"
+#include "remote_constants.h"
+#include "listener_hook_service.h"
+#include "log_service.h"
+#include "log_helper.h"
+
+
+#include "pubsub_topology_manager.h"
+#include "publisher_endpoint_announce.h"
+
+struct activator {
+	bundle_context_pt context;
+
+	pubsub_topology_manager_pt manager;
+
+	service_tracker_pt pubsubDiscoveryTracker;
+	service_tracker_pt pubsubAdminTracker;
+	service_tracker_pt pubsubSubscribersTracker;
+
+	listener_hook_service_pt hookService;
+	service_registration_pt hook;
+
+	publisher_endpoint_announce_pt publisherEPDiscover;
+	service_registration_pt publisherEPDiscoverService;
+
+	log_helper_pt loghelper;
+};
+
+
+static celix_status_t bundleActivator_createPSDTracker(struct activator *activator, service_tracker_pt *tracker);
+static celix_status_t bundleActivator_createPSATracker(struct activator *activator, service_tracker_pt *tracker);
+static celix_status_t bundleActivator_createPSSubTracker(struct activator *activator, service_tracker_pt *tracker);
+
+
+static celix_status_t bundleActivator_createPSDTracker(struct activator *activator, service_tracker_pt *tracker) {
+	celix_status_t status;
+
+	service_tracker_customizer_pt customizer = NULL;
+
+	status = serviceTrackerCustomizer_create(activator->manager,
+			pubsub_topologyManager_pubsubDiscoveryAdding,
+			pubsub_topologyManager_pubsubDiscoveryAdded,
+			pubsub_topologyManager_pubsubDiscoveryModified,
+			pubsub_topologyManager_pubsubDiscoveryRemoved,
+			&customizer);
+
+	if (status == CELIX_SUCCESS) {
+		status = serviceTracker_create(activator->context, (char *) PUBSUB_DISCOVERY_SERVICE, customizer, tracker);
+	}
+
+	return status;
+}
+
+static celix_status_t bundleActivator_createPSATracker(struct activator *activator, service_tracker_pt *tracker) {
+	celix_status_t status = CELIX_SUCCESS;
+
+	service_tracker_customizer_pt customizer = NULL;
+
+	status = serviceTrackerCustomizer_create(activator->manager,
+			pubsub_topologyManager_psaAdding,
+			pubsub_topologyManager_psaAdded,
+			pubsub_topologyManager_psaModified,
+			pubsub_topologyManager_psaRemoved,
+			&customizer);
+
+	if (status == CELIX_SUCCESS) {
+		status = serviceTracker_create(activator->context, PUBSUB_ADMIN_SERVICE, customizer, tracker);
+	}
+
+	return status;
+}
+
+static celix_status_t bundleActivator_createPSSubTracker(struct activator *activator, service_tracker_pt *tracker) {
+	celix_status_t status = CELIX_SUCCESS;
+
+	service_tracker_customizer_pt customizer = NULL;
+
+	status = serviceTrackerCustomizer_create(activator->manager,
+			pubsub_topologyManager_subscriberAdding,
+			pubsub_topologyManager_subscriberAdded,
+			pubsub_topologyManager_subscriberModified,
+			pubsub_topologyManager_subscriberRemoved,
+			&customizer);
+
+	if (status == CELIX_SUCCESS) {
+		status = serviceTracker_create(activator->context, PUBSUB_SUBSCRIBER_SERVICE_NAME, customizer, tracker);
+	}
+
+	return status;
+}
+
+celix_status_t bundleActivator_create(bundle_context_pt context, void **userData) {
+	celix_status_t status = CELIX_SUCCESS;
+	struct activator *activator = NULL;
+
+	activator = calloc(1,sizeof(struct activator));
+
+	if (!activator) {
+		return CELIX_ENOMEM;
+	}
+
+	activator->context = context;
+
+	logHelper_create(context, &activator->loghelper);
+	logHelper_start(activator->loghelper);
+
+	status = pubsub_topologyManager_create(context, activator->loghelper, &activator->manager);
+	if (status == CELIX_SUCCESS) {
+		status = bundleActivator_createPSDTracker(activator, &activator->pubsubDiscoveryTracker);
+		if (status == CELIX_SUCCESS) {
+			status = bundleActivator_createPSATracker(activator, &activator->pubsubAdminTracker);
+			if (status == CELIX_SUCCESS) {
+				status = bundleActivator_createPSSubTracker(activator, &activator->pubsubSubscribersTracker);
+				if (status == CELIX_SUCCESS) {
+					*userData = activator;
+				}
+			}
+		}
+	}
+
+	return status;
+}
+
+
+celix_status_t bundleActivator_start(void * userData, bundle_context_pt context) {
+	celix_status_t status = CELIX_SUCCESS;
+	struct activator *activator = userData;
+
+	publisher_endpoint_announce_pt pubEPDiscover = calloc(1, sizeof(*pubEPDiscover));
+	pubEPDiscover->handle = activator->manager;
+	pubEPDiscover->announcePublisher = pubsub_topologyManager_announcePublisher;
+	pubEPDiscover->removePublisher = pubsub_topologyManager_removePublisher;
+	activator->publisherEPDiscover = pubEPDiscover;
+
+	status += bundleContext_registerService(context, (char *) PUBSUB_TM_ANNOUNCE_PUBLISHER_SERVICE, pubEPDiscover, NULL, &activator->publisherEPDiscoverService);
+
+
+	listener_hook_service_pt hookService = calloc(1,sizeof(*hookService));
+	hookService->handle = activator->manager;
+	hookService->added = pubsub_topologyManager_publisherTrackerAdded;
+	hookService->removed = pubsub_topologyManager_publisherTrackerRemoved;
+	activator->hookService = hookService;
+
+	status += bundleContext_registerService(context, (char *) OSGI_FRAMEWORK_LISTENER_HOOK_SERVICE_NAME, hookService, NULL, &activator->hook);
+
+	/* NOTE: Enable those line in order to remotely expose the topic_info service
+	properties_pt props = properties_create();
+	properties_set(props, (char *) OSGI_RSA_SERVICE_EXPORTED_INTERFACES, (char *) PUBSUB_TOPIC_INFO_SERVICE);
+	status += bundleContext_registerService(context, (char *) PUBSUB_TOPIC_INFO_SERVICE, activator->topicInfo, props, &activator->topicInfoService);
+	*/
+	status += serviceTracker_open(activator->pubsubAdminTracker);
+
+	status += serviceTracker_open(activator->pubsubDiscoveryTracker);
+
+	status += serviceTracker_open(activator->pubsubSubscribersTracker);
+
+
+	return status;
+}
+
+celix_status_t bundleActivator_stop(void * userData, bundle_context_pt context) {
+	celix_status_t status = CELIX_SUCCESS;
+	struct activator *activator = userData;
+
+	serviceTracker_close(activator->pubsubSubscribersTracker);
+	serviceTracker_close(activator->pubsubDiscoveryTracker);
+	serviceTracker_close(activator->pubsubAdminTracker);
+
+	serviceRegistration_unregister(activator->publisherEPDiscoverService);
+	free(activator->publisherEPDiscover);
+
+	serviceRegistration_unregister(activator->hook);
+	free(activator->hookService);
+
+	return status;
+}
+
+celix_status_t bundleActivator_destroy(void * userData, bundle_context_pt context) {
+	celix_status_t status = CELIX_SUCCESS;
+
+	struct activator *activator = userData;
+	if (!activator || !activator->manager) {
+		status = CELIX_BUNDLE_EXCEPTION;
+	} else {
+
+		serviceTracker_destroy(activator->pubsubSubscribersTracker);
+		serviceTracker_destroy(activator->pubsubDiscoveryTracker);
+		serviceTracker_destroy(activator->pubsubAdminTracker);
+
+		logHelper_stop(activator->loghelper);
+		logHelper_destroy(&activator->loghelper);
+
+		status = pubsub_topologyManager_destroy(activator->manager);
+		free(activator);
+	}
+
+	return status;
+}

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_topology_manager/private/src/pubsub_topology_manager.c
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_topology_manager/private/src/pubsub_topology_manager.c b/celix-pubsub/pubsub/pubsub_topology_manager/private/src/pubsub_topology_manager.c
new file mode 100644
index 0000000..a485f37
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_topology_manager/private/src/pubsub_topology_manager.c
@@ -0,0 +1,758 @@
+/**
+ *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.
+ */
+/*
+ * pubsub_topology_manager.c
+ *
+ *  \date       Sep 29, 2011
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include "hash_map.h"
+#include "array_list.h"
+#include "bundle_context.h"
+#include "constants.h"
+#include "module.h"
+#include "bundle.h"
+#include "remote_service_admin.h"
+#include "remote_constants.h"
+#include "filter.h"
+#include "listener_hook_service.h"
+#include "utils.h"
+#include "service_reference.h"
+#include "service_registration.h"
+#include "log_service.h"
+#include "log_helper.h"
+
+#include "publisher_endpoint_announce.h"
+#include "pubsub_topology_manager.h"
+#include "pubsub_endpoint.h"
+#include "pubsub_admin.h"
+#include "pubsub_utils.h"
+
+
+celix_status_t pubsub_topologyManager_create(bundle_context_pt context, log_helper_pt logHelper, pubsub_topology_manager_pt *manager) {
+	celix_status_t status = CELIX_SUCCESS;
+
+	*manager = calloc(1, sizeof(**manager));
+	if (!*manager) {
+		return CELIX_ENOMEM;
+	}
+
+	(*manager)->context = context;
+
+	celix_thread_mutexattr_t psaAttr;
+	celixThreadMutexAttr_create(&psaAttr);
+	celixThreadMutexAttr_settype(&psaAttr, CELIX_THREAD_MUTEX_RECURSIVE);
+	status = celixThreadMutex_create(&(*manager)->psaListLock, &psaAttr);
+    celixThreadMutexAttr_destroy(&psaAttr);
+
+    status = celixThreadMutex_create(&(*manager)->publicationsLock, NULL);
+	status = celixThreadMutex_create(&(*manager)->subscriptionsLock, NULL);
+	status = celixThreadMutex_create(&(*manager)->discoveryListLock, NULL);
+
+	arrayList_create(&(*manager)->psaList);
+
+	(*manager)->discoveryList = hashMap_create(serviceReference_hashCode, NULL, serviceReference_equals2, NULL);
+	(*manager)->publications = hashMap_create(utils_stringHash, NULL, utils_stringEquals, NULL);
+	(*manager)->subscriptions = hashMap_create(utils_stringHash, NULL, utils_stringEquals, NULL);
+
+	(*manager)->loghelper = logHelper;
+
+	return status;
+}
+
+celix_status_t pubsub_topologyManager_destroy(pubsub_topology_manager_pt manager) {
+	celix_status_t status = CELIX_SUCCESS;
+
+	celixThreadMutex_lock(&manager->discoveryListLock);
+	hashMap_destroy(manager->discoveryList, false, false);
+	celixThreadMutex_unlock(&manager->discoveryListLock);
+	celixThreadMutex_destroy(&manager->discoveryListLock);
+
+	celixThreadMutex_lock(&manager->psaListLock);
+	arrayList_destroy(manager->psaList);
+	celixThreadMutex_unlock(&manager->psaListLock);
+	celixThreadMutex_destroy(&manager->psaListLock);
+
+	celixThreadMutex_lock(&manager->publicationsLock);
+	hash_map_iterator_pt pubit = hashMapIterator_create(manager->publications);
+	while(hashMapIterator_hasNext(pubit)){
+		array_list_pt l = (array_list_pt)hashMapIterator_nextValue(pubit);
+		int i;
+		for(i=0;i<arrayList_size(l);i++){
+			pubsubEndpoint_destroy((pubsub_endpoint_pt)arrayList_get(l,i));
+		}
+		arrayList_destroy(l);
+	}
+	hashMapIterator_destroy(pubit);
+	hashMap_destroy(manager->publications, true, false);
+	celixThreadMutex_unlock(&manager->publicationsLock);
+	celixThreadMutex_destroy(&manager->publicationsLock);
+
+	celixThreadMutex_lock(&manager->subscriptionsLock);
+	hash_map_iterator_pt subit = hashMapIterator_create(manager->subscriptions);
+	while(hashMapIterator_hasNext(subit)){
+		array_list_pt l = (array_list_pt)hashMapIterator_nextValue(subit);
+		int i;
+		for(i=0;i<arrayList_size(l);i++){
+			pubsubEndpoint_destroy((pubsub_endpoint_pt)arrayList_get(l,i));
+		}
+		arrayList_destroy(l);
+	}
+	hashMapIterator_destroy(subit);
+	hashMap_destroy(manager->subscriptions, true, false);
+	celixThreadMutex_unlock(&manager->subscriptionsLock);
+	celixThreadMutex_destroy(&manager->subscriptionsLock);
+
+	free(manager);
+
+	return status;
+}
+
+
+celix_status_t pubsub_topologyManager_psaAdding(void * handle, service_reference_pt reference, void **service) {
+	celix_status_t status = CELIX_SUCCESS;
+	pubsub_topology_manager_pt manager = handle;
+
+	status = bundleContext_getService(manager->context, reference, service);
+
+	return status;
+}
+
+celix_status_t pubsub_topologyManager_psaAdded(void * handle, service_reference_pt reference, void * service) {
+	celix_status_t status = CELIX_SUCCESS;
+	pubsub_topology_manager_pt manager = handle;
+	int i;
+
+	pubsub_admin_service_pt psa = (pubsub_admin_service_pt) service;
+	logHelper_log(manager->loghelper, OSGI_LOGSERVICE_INFO, "PSTM: Added PSA");
+
+	celixThreadMutex_lock(&manager->psaListLock);
+	arrayList_add(manager->psaList, psa);
+	celixThreadMutex_unlock(&manager->psaListLock);
+
+	// Add already detected subscriptions to new PSA
+	celixThreadMutex_lock(&manager->subscriptionsLock);
+	hash_map_iterator_pt subscriptionsIterator = hashMapIterator_create(manager->subscriptions);
+
+	while (hashMapIterator_hasNext(subscriptionsIterator)) {
+		array_list_pt sub_ep_list = hashMapIterator_nextValue(subscriptionsIterator);
+		for(i=0;i<arrayList_size(sub_ep_list);i++){
+			status += psa->addSubscription(psa->admin, (pubsub_endpoint_pt)arrayList_get(sub_ep_list,i));
+		}
+	}
+
+	hashMapIterator_destroy(subscriptionsIterator);
+
+	celixThreadMutex_unlock(&manager->subscriptionsLock);
+
+	// Add already detected publications to new PSA
+	status = celixThreadMutex_lock(&manager->publicationsLock);
+	hash_map_iterator_pt publicationsIterator = hashMapIterator_create(manager->publications);
+
+	while (hashMapIterator_hasNext(publicationsIterator)) {
+		array_list_pt pub_ep_list = hashMapIterator_nextValue(publicationsIterator);
+		for(i=0;i<arrayList_size(pub_ep_list);i++){
+			status += psa->addPublication(psa->admin, (pubsub_endpoint_pt)arrayList_get(pub_ep_list,i));
+		}
+	}
+
+	hashMapIterator_destroy(publicationsIterator);
+
+	celixThreadMutex_unlock(&manager->publicationsLock);
+
+	return status;
+}
+
+celix_status_t pubsub_topologyManager_psaModified(void * handle, service_reference_pt reference, void * service) {
+	celix_status_t status = CELIX_SUCCESS;
+
+	// Nop...
+
+	return status;
+}
+
+celix_status_t pubsub_topologyManager_psaRemoved(void * handle, service_reference_pt reference, void * service) {
+	celix_status_t status = CELIX_SUCCESS;
+	pubsub_topology_manager_pt manager = handle;
+
+	pubsub_admin_service_pt psa = (pubsub_admin_service_pt) service;
+
+	celixThreadMutex_lock(&manager->psaListLock);
+
+	/* Deactivate all publications */
+	celixThreadMutex_lock(&manager->publicationsLock);
+
+	hash_map_iterator_pt pubit = hashMapIterator_create(manager->publications);
+	while(hashMapIterator_hasNext(pubit)){
+		hash_map_entry_pt pub_entry = hashMapIterator_nextEntry(pubit);
+		char* scope_topic_key = (char*)hashMapEntry_getKey(pub_entry);
+		// Extract scope/topic name from key
+		char scope[MAX_SCOPE_LEN];
+		char topic[MAX_TOPIC_LEN];
+		sscanf(scope_topic_key, "%[^:]:%s", scope, topic );
+		array_list_pt pubEP_list = (array_list_pt)hashMapEntry_getValue(pub_entry);
+
+		status = psa->closeAllPublications(psa->admin,scope,topic);
+
+		if(status==CELIX_SUCCESS){
+			celixThreadMutex_lock(&manager->discoveryListLock);
+			hash_map_iterator_pt iter = hashMapIterator_create(manager->discoveryList);
+			while(hashMapIterator_hasNext(iter)){
+				service_reference_pt disc_sr = (service_reference_pt)hashMapIterator_nextKey(iter);
+				publisher_endpoint_announce_pt disc = NULL;
+				bundleContext_getService(manager->context, disc_sr, (void**) &disc);
+				const char* fwUUID = NULL;
+				bundleContext_getProperty(manager->context,OSGI_FRAMEWORK_FRAMEWORK_UUID,&fwUUID);
+				int i;
+				for(i=0;i<arrayList_size(pubEP_list);i++){
+					pubsub_endpoint_pt pubEP = (pubsub_endpoint_pt)arrayList_get(pubEP_list,i);
+					if(strcmp(pubEP->frameworkUUID,fwUUID)==0){
+						disc->removePublisher(disc->handle,pubEP);
+					}
+				}
+				bundleContext_ungetService(manager->context, disc_sr, NULL);
+			}
+			hashMapIterator_destroy(iter);
+			celixThreadMutex_unlock(&manager->discoveryListLock);
+		}
+	}
+	hashMapIterator_destroy(pubit);
+
+	celixThreadMutex_unlock(&manager->publicationsLock);
+
+	/* Deactivate all subscriptions */
+	celixThreadMutex_lock(&manager->subscriptionsLock);
+	hash_map_iterator_pt subit = hashMapIterator_create(manager->subscriptions);
+	while(hashMapIterator_hasNext(subit)){
+		// TODO do some error checking
+		char* scope_topic = (char*)hashMapIterator_nextKey(subit);
+		char scope[MAX_TOPIC_LEN];
+		char topic[MAX_TOPIC_LEN];
+		memset(scope, 0 , MAX_TOPIC_LEN*sizeof(char));
+		memset(topic, 0 , MAX_TOPIC_LEN*sizeof(char));
+		sscanf(scope_topic, "%[^:]:%s", scope, topic );
+		status += psa->closeAllSubscriptions(psa->admin,scope, topic);
+	}
+	hashMapIterator_destroy(subit);
+	celixThreadMutex_unlock(&manager->subscriptionsLock);
+
+	arrayList_removeElement(manager->psaList, psa);
+
+	celixThreadMutex_unlock(&manager->psaListLock);
+
+	logHelper_log(manager->loghelper, OSGI_LOGSERVICE_INFO, "PSTM: Removed PSA");
+
+	return status;
+}
+
+
+celix_status_t pubsub_topologyManager_subscriberAdding(void * handle, service_reference_pt reference, void **service) {
+	celix_status_t status = CELIX_SUCCESS;
+	pubsub_topology_manager_pt manager = handle;
+
+	status = bundleContext_getService(manager->context, reference, service);
+
+	return status;
+}
+
+celix_status_t pubsub_topologyManager_subscriberAdded(void * handle, service_reference_pt reference, void * service) {
+	celix_status_t status = CELIX_SUCCESS;
+	pubsub_topology_manager_pt manager = handle;
+	//subscriber_service_pt subscriber = (subscriber_service_pt)service;
+
+	pubsub_endpoint_pt sub = NULL;
+	if(pubsubEndpoint_createFromServiceReference(reference,&sub) == CELIX_SUCCESS){
+		celixThreadMutex_lock(&manager->subscriptionsLock);
+		char *sub_key = createScopeTopicKey(sub->scope, sub->topic);
+
+		array_list_pt sub_list_by_topic = hashMap_get(manager->subscriptions,sub_key);
+		if(sub_list_by_topic==NULL){
+			arrayList_create(&sub_list_by_topic);
+			hashMap_put(manager->subscriptions,strdup(sub_key),sub_list_by_topic);
+		}
+		free(sub_key);
+		arrayList_add(sub_list_by_topic,sub);
+
+		celixThreadMutex_unlock(&manager->subscriptionsLock);
+
+		int j;
+		celixThreadMutex_lock(&manager->psaListLock);
+		for(j=0;j<arrayList_size(manager->psaList);j++){
+
+			pubsub_admin_service_pt psa = (pubsub_admin_service_pt)arrayList_get(manager->psaList,j);
+			psa->addSubscription(psa->admin,sub);
+		}
+
+		// Inform discoveries for interest in the topic
+        celixThreadMutex_lock(&manager->discoveryListLock);
+		hash_map_iterator_pt iter = hashMapIterator_create(manager->discoveryList);
+        while(hashMapIterator_hasNext(iter)){
+            service_reference_pt disc_sr = (service_reference_pt)hashMapIterator_nextKey(iter);
+            publisher_endpoint_announce_pt disc = NULL;
+            bundleContext_getService(manager->context, disc_sr, (void**) &disc);
+            disc->interestedInTopic(disc->handle, sub->scope, sub->topic);
+            bundleContext_ungetService(manager->context, disc_sr, NULL);
+        }
+        hashMapIterator_destroy(iter);
+        celixThreadMutex_unlock(&manager->discoveryListLock);
+
+		celixThreadMutex_unlock(&manager->psaListLock);
+	}
+	else{
+		status=CELIX_INVALID_BUNDLE_CONTEXT;
+	}
+
+	return status;
+}
+
+celix_status_t pubsub_topologyManager_subscriberModified(void * handle, service_reference_pt reference, void * service) {
+	celix_status_t status = CELIX_SUCCESS;
+
+	// Nop...
+
+	return status;
+}
+
+celix_status_t pubsub_topologyManager_subscriberRemoved(void * handle, service_reference_pt reference, void * service) {
+	celix_status_t status = CELIX_SUCCESS;
+	pubsub_topology_manager_pt manager = handle;
+
+	pubsub_endpoint_pt subcmp = NULL;
+	if(pubsubEndpoint_createFromServiceReference(reference,&subcmp) == CELIX_SUCCESS){
+
+		int j,k;
+		celixThreadMutex_lock(&manager->subscriptionsLock);
+
+		// Inform discoveries that we not interested in the topic any more
+        celixThreadMutex_lock(&manager->discoveryListLock);
+        hash_map_iterator_pt iter = hashMapIterator_create(manager->discoveryList);
+        while(hashMapIterator_hasNext(iter)){
+            service_reference_pt disc_sr = (service_reference_pt)hashMapIterator_nextKey(iter);
+            publisher_endpoint_announce_pt disc = NULL;
+            bundleContext_getService(manager->context, disc_sr, (void**) &disc);
+            disc->uninterestedInTopic(disc->handle, subcmp->scope, subcmp->topic);
+            bundleContext_ungetService(manager->context, disc_sr, NULL);
+        }
+        hashMapIterator_destroy(iter);
+        celixThreadMutex_unlock(&manager->discoveryListLock);
+
+		char *sub_key = createScopeTopicKey(subcmp->scope,subcmp->topic);
+		array_list_pt sub_list_by_topic = hashMap_get(manager->subscriptions,sub_key);
+		free(sub_key);
+		if(sub_list_by_topic!=NULL){
+			for(j=0;j<arrayList_size(sub_list_by_topic);j++){
+				pubsub_endpoint_pt sub = arrayList_get(sub_list_by_topic,j);
+				if(pubsubEndpoint_equals(sub,subcmp)){
+					celixThreadMutex_lock(&manager->psaListLock);
+					for(k=0;k<arrayList_size(manager->psaList);k++){
+
+						pubsub_admin_service_pt psa = (pubsub_admin_service_pt)arrayList_get(manager->psaList,k);
+						psa->removeSubscription(psa->admin,sub);
+					}
+					celixThreadMutex_unlock(&manager->psaListLock);
+
+				}
+				arrayList_remove(sub_list_by_topic,j);
+
+				/* If it was the last subscriber for this topic, tell PSA to close the ZMQ socket */
+				if(arrayList_size(sub_list_by_topic)==0){
+					celixThreadMutex_lock(&manager->psaListLock);
+					for(k=0;k<arrayList_size(manager->psaList);k++){
+						pubsub_admin_service_pt psa = (pubsub_admin_service_pt)arrayList_get(manager->psaList,k);
+						psa->closeAllSubscriptions(psa->admin,sub->scope, sub->topic);
+					}
+					celixThreadMutex_unlock(&manager->psaListLock);
+				}
+
+				pubsubEndpoint_destroy(sub);
+
+			}
+		}
+
+		celixThreadMutex_unlock(&manager->subscriptionsLock);
+
+		pubsubEndpoint_destroy(subcmp);
+
+	}
+	else{
+		status=CELIX_INVALID_BUNDLE_CONTEXT;
+	}
+
+	return status;
+
+}
+
+celix_status_t pubsub_topologyManager_pubsubDiscoveryAdding(void* handle, service_reference_pt reference, void** service) {
+	celix_status_t status = CELIX_SUCCESS;
+	pubsub_topology_manager_pt manager = handle;
+
+	bundleContext_getService(manager->context, reference, service);
+
+	return status;
+}
+
+celix_status_t pubsub_topologyManager_pubsubDiscoveryAdded(void* handle, service_reference_pt reference, void* service) {
+	celix_status_t status = CELIX_SUCCESS;
+	pubsub_topology_manager_pt manager = (pubsub_topology_manager_pt)handle;
+	publisher_endpoint_announce_pt disc = (publisher_endpoint_announce_pt)service;
+
+	const char* fwUUID = NULL;
+
+	bundleContext_getProperty(manager->context,OSGI_FRAMEWORK_FRAMEWORK_UUID,&fwUUID);
+	if(fwUUID==NULL){
+		printf("PSD: ERRROR: Cannot retrieve fwUUID.\n");
+		return CELIX_INVALID_BUNDLE_CONTEXT;
+	}
+
+	celixThreadMutex_lock(&manager->publicationsLock);
+
+	celixThreadMutex_lock(&manager->discoveryListLock);
+	hashMap_put(manager->discoveryList, reference, NULL);
+	celixThreadMutex_unlock(&manager->discoveryListLock);
+
+	hash_map_iterator_pt iter = hashMapIterator_create(manager->publications);
+	while(hashMapIterator_hasNext(iter)){
+		array_list_pt pubEP_list = (array_list_pt)hashMapIterator_nextValue(iter);
+		for(int i = 0; i < arrayList_size(pubEP_list); i++) {
+			pubsub_endpoint_pt pubEP = (pubsub_endpoint_pt)arrayList_get(pubEP_list,i);
+			if( (strcmp(pubEP->frameworkUUID,fwUUID)==0) && (pubEP->endpoint!=NULL)){
+				status += disc->announcePublisher(disc->handle,pubEP);
+			}
+		}
+	}
+	hashMapIterator_destroy(iter);
+
+	celixThreadMutex_unlock(&manager->publicationsLock);
+
+	celixThreadMutex_lock(&manager->subscriptionsLock);
+	iter = hashMapIterator_create(manager->subscriptions);
+
+	while(hashMapIterator_hasNext(iter)) {
+	    array_list_pt l = (array_list_pt)hashMapIterator_nextValue(iter);
+	    int i;
+	    for(i=0;i<arrayList_size(l);i++){
+	        pubsub_endpoint_pt subEp = (pubsub_endpoint_pt)arrayList_get(l,i);
+
+	        disc->interestedInTopic(disc->handle, subEp->scope, subEp->topic);
+	    }
+	}
+	hashMapIterator_destroy(iter);
+    celixThreadMutex_unlock(&manager->subscriptionsLock);
+
+	return status;
+}
+
+celix_status_t pubsub_topologyManager_pubsubDiscoveryModified(void * handle, service_reference_pt reference, void * service) {
+	celix_status_t status = CELIX_SUCCESS;
+
+	status = pubsub_topologyManager_pubsubDiscoveryRemoved(handle, reference, service);
+	if (status == CELIX_SUCCESS) {
+		status = pubsub_topologyManager_pubsubDiscoveryAdded(handle, reference, service);
+	}
+
+	return status;
+}
+
+celix_status_t pubsub_topologyManager_pubsubDiscoveryRemoved(void * handle, service_reference_pt reference, void * service) {
+	celix_status_t status = CELIX_SUCCESS;
+
+	pubsub_topology_manager_pt manager = handle;
+
+	celixThreadMutex_lock(&manager->discoveryListLock);
+
+
+	if (hashMap_remove(manager->discoveryList, reference)) {
+		logHelper_log(manager->loghelper, OSGI_LOGSERVICE_INFO, "EndpointListener Removed");
+	}
+
+	celixThreadMutex_unlock(&manager->discoveryListLock);
+
+	return status;
+}
+
+
+celix_status_t pubsub_topologyManager_publisherTrackerAdded(void *handle, array_list_pt listeners) {
+
+	celix_status_t status = CELIX_SUCCESS;
+	pubsub_topology_manager_pt manager = handle;
+
+	int l_index;
+
+	for (l_index = 0; l_index < arrayList_size(listeners); l_index++) {
+
+		listener_hook_info_pt info = arrayList_get(listeners, l_index);
+
+		const char* fwUUID=NULL;
+		bundleContext_getProperty(info->context,OSGI_FRAMEWORK_FRAMEWORK_UUID,&fwUUID);
+
+		char* scope = pubsub_getScopeFromFilter(info->filter);
+		char* topic = pubsub_getTopicFromFilter(info->filter);
+		if(scope == NULL) {
+			scope = strdup(PUBSUB_PUBLISHER_SCOPE_DEFAULT);
+		}
+
+		//TODO: Can we use a better serviceID??
+		bundle_pt bundle = NULL;
+		long bundleId = -1;
+		bundleContext_getBundle(info->context,&bundle);
+		bundle_getBundleId(bundle,&bundleId);
+
+		if(fwUUID !=NULL && topic !=NULL){
+
+			pubsub_endpoint_pt pub = NULL;
+			if(pubsubEndpoint_create(fwUUID, scope, topic,bundleId,NULL,&pub) == CELIX_SUCCESS){
+
+				celixThreadMutex_lock(&manager->publicationsLock);
+				char *pub_key = createScopeTopicKey(scope, topic);
+				array_list_pt pub_list_by_topic = hashMap_get(manager->publications, pub_key);
+				if(pub_list_by_topic==NULL){
+					arrayList_create(&pub_list_by_topic);
+					hashMap_put(manager->publications,strdup(pub_key),pub_list_by_topic);
+				}
+				free(pub_key);
+				arrayList_add(pub_list_by_topic,pub);
+
+				celixThreadMutex_unlock(&manager->publicationsLock);
+
+				int j;
+				celixThreadMutex_lock(&manager->psaListLock);
+
+				for(j=0;j<arrayList_size(manager->psaList);j++){
+
+					pubsub_admin_service_pt psa = (pubsub_admin_service_pt)arrayList_get(manager->psaList,j);
+					status = psa->addPublication(psa->admin,pub);
+					if(status==CELIX_SUCCESS){
+						celixThreadMutex_lock(&manager->discoveryListLock);
+						hash_map_iterator_pt iter = hashMapIterator_create(manager->discoveryList);
+						while(hashMapIterator_hasNext(iter)){
+							service_reference_pt disc_sr = (service_reference_pt)hashMapIterator_nextKey(iter);
+							publisher_endpoint_announce_pt disc = NULL;
+							bundleContext_getService(manager->context, disc_sr, (void**) &disc);
+							disc->announcePublisher(disc->handle,pub);
+							bundleContext_ungetService(manager->context, disc_sr, NULL);
+						}
+						hashMapIterator_destroy(iter);
+						celixThreadMutex_unlock(&manager->discoveryListLock);
+					}
+				}
+
+				celixThreadMutex_unlock(&manager->psaListLock);
+
+			}
+			free(topic);
+
+		}
+		else{
+			status=CELIX_INVALID_BUNDLE_CONTEXT;
+		}
+        free(scope);
+
+	}
+
+	return status;
+
+}
+
+
+celix_status_t pubsub_topologyManager_publisherTrackerRemoved(void *handle, array_list_pt listeners) {
+	celix_status_t status = CELIX_SUCCESS;
+	pubsub_topology_manager_pt manager = handle;
+
+	int l_index;
+
+	for (l_index = 0; l_index < arrayList_size(listeners); l_index++) {
+
+		listener_hook_info_pt info = arrayList_get(listeners, l_index);
+
+		char* pub_scope = pubsub_getScopeFromFilter(info->filter);
+		char* pub_topic = pubsub_getTopicFromFilter(info->filter);
+
+		const char* fwUUID=NULL;
+		bundleContext_getProperty(info->context,OSGI_FRAMEWORK_FRAMEWORK_UUID,&fwUUID);
+
+		//TODO: Can we use a better serviceID??
+		bundle_pt bundle = NULL;
+		long bundleId = -1;
+		bundleContext_getBundle(info->context,&bundle);
+		bundle_getBundleId(bundle,&bundleId);
+
+		if(bundle !=NULL && pub_topic !=NULL && bundleId>0){
+
+			pubsub_endpoint_pt pubcmp = NULL;
+			if(pubsubEndpoint_create(fwUUID, pub_scope, pub_topic,bundleId,NULL,&pubcmp) == CELIX_SUCCESS){
+
+				int j,k;
+                celixThreadMutex_lock(&manager->psaListLock);
+                celixThreadMutex_lock(&manager->publicationsLock);
+
+                char *pub_key = createScopeTopicKey(pub_scope, pub_topic);
+				array_list_pt pub_list_by_topic = hashMap_get(manager->publications,pub_key);
+				if(pub_list_by_topic!=NULL){
+					for(j=0;j<arrayList_size(pub_list_by_topic);j++){
+						pubsub_endpoint_pt pub = arrayList_get(pub_list_by_topic,j);
+						if(pubsubEndpoint_equals(pub,pubcmp)){
+							for(k=0;k<arrayList_size(manager->psaList);k++){
+								pubsub_admin_service_pt psa = (pubsub_admin_service_pt)arrayList_get(manager->psaList,k);
+								status = psa->removePublication(psa->admin,pub);
+								if(status==CELIX_SUCCESS){
+									celixThreadMutex_lock(&manager->discoveryListLock);
+									hash_map_iterator_pt iter = hashMapIterator_create(manager->discoveryList);
+									while(hashMapIterator_hasNext(iter)){
+										service_reference_pt disc_sr = (service_reference_pt)hashMapIterator_nextKey(iter);
+										publisher_endpoint_announce_pt disc = NULL;
+										bundleContext_getService(manager->context, disc_sr, (void**) &disc);
+										disc->removePublisher(disc->handle,pub);
+										bundleContext_ungetService(manager->context, disc_sr, NULL);
+									}
+									hashMapIterator_destroy(iter);
+									celixThreadMutex_unlock(&manager->discoveryListLock);
+								}
+							}
+						}
+						arrayList_remove(pub_list_by_topic,j);
+
+						/* If it was the last publisher for this topic, tell PSA to close the ZMQ socket and then inform the discovery */
+						if(arrayList_size(pub_list_by_topic)==0){
+							for(k=0;k<arrayList_size(manager->psaList);k++){
+								pubsub_admin_service_pt psa = (pubsub_admin_service_pt)arrayList_get(manager->psaList,k);
+								psa->closeAllPublications(psa->admin,pub->scope, pub->topic);
+							}
+						}
+
+						pubsubEndpoint_destroy(pub);
+
+					}
+				}
+
+				celixThreadMutex_unlock(&manager->publicationsLock);
+				celixThreadMutex_unlock(&manager->psaListLock);
+
+				pubsubEndpoint_destroy(pubcmp);
+				free(pub_scope);
+				free(pub_topic);
+				free(pub_key);
+
+			}
+
+		}
+		else{
+			status=CELIX_INVALID_BUNDLE_CONTEXT;
+		}
+	}
+
+	return status;
+}
+
+celix_status_t pubsub_topologyManager_announcePublisher(void *handle, pubsub_endpoint_pt pubEP){
+	celix_status_t status = CELIX_SUCCESS;
+	printf("PSTM: New publisher discovered for topic %s [fwUUID=%s, ep=%s]\n",pubEP->topic,pubEP->frameworkUUID,pubEP->endpoint);
+
+	pubsub_topology_manager_pt manager = handle;
+	celixThreadMutex_lock(&manager->publicationsLock);
+	celixThreadMutex_lock(&manager->psaListLock);
+	int i;
+
+	char *pub_key = createScopeTopicKey(pubEP->scope, pubEP->topic);
+
+	array_list_pt pub_list_by_topic = hashMap_get(manager->publications,pub_key);
+	if(pub_list_by_topic==NULL){
+		arrayList_create(&pub_list_by_topic);
+		hashMap_put(manager->publications,strdup(pub_key),pub_list_by_topic);
+	}
+	free(pub_key);
+
+	/* Shouldn't be any other duplicate, since it's filtered out by the discovery */
+	pubsub_endpoint_pt p = NULL;
+	pubsubEndpoint_create(pubEP->frameworkUUID,pubEP->scope,pubEP->topic,pubEP->serviceID,pubEP->endpoint,&p);
+	arrayList_add(pub_list_by_topic,p);
+
+	for(i=0;i<arrayList_size(manager->psaList);i++){
+		pubsub_admin_service_pt psa = (pubsub_admin_service_pt)arrayList_get(manager->psaList,i);
+		status += psa->addPublication(psa->admin,p);
+	}
+
+	celixThreadMutex_unlock(&manager->psaListLock);
+	celixThreadMutex_unlock(&manager->publicationsLock);
+
+	return status;
+}
+
+celix_status_t pubsub_topologyManager_removePublisher(void *handle, pubsub_endpoint_pt pubEP){
+	celix_status_t status = CELIX_SUCCESS;
+	printf("PSTM: Publisher removed for topic %s [fwUUID=%s, ep=%s]\n",pubEP->topic,pubEP->frameworkUUID,pubEP->endpoint);
+
+	pubsub_topology_manager_pt manager = handle;
+	celixThreadMutex_lock(&manager->psaListLock);
+	celixThreadMutex_lock(&manager->publicationsLock);
+	int i;
+
+	char *pub_key = createScopeTopicKey(pubEP->scope, pubEP->topic);
+	array_list_pt pub_list_by_topic = hashMap_get(manager->publications,pub_key);
+	if(pub_list_by_topic==NULL){
+		printf("PSTM: ERROR: Cannot find topic for known endpoint [%s,%s,%s]. Something is inconsistent.\n",pub_key,pubEP->frameworkUUID,pubEP->endpoint);
+		status = CELIX_ILLEGAL_STATE;
+	}
+	else{
+
+		pubsub_endpoint_pt p = NULL;
+		bool found = false;
+
+		for(i=0;!found && i<arrayList_size(pub_list_by_topic);i++){
+			p = (pubsub_endpoint_pt)arrayList_get(pub_list_by_topic,i);
+			found = pubsubEndpoint_equals(p,pubEP);
+		}
+
+		if(found && p !=NULL){
+
+			for(i=0;i<arrayList_size(manager->psaList);i++){
+				pubsub_admin_service_pt psa = (pubsub_admin_service_pt)arrayList_get(manager->psaList,i);
+				status += psa->removePublication(psa->admin,p);
+			}
+
+			arrayList_removeElement(pub_list_by_topic,p);
+
+			/* If it was the last publisher for this topic, tell PSA to close the ZMQ socket */
+			if(arrayList_size(pub_list_by_topic)==0){
+
+				for(i=0;i<arrayList_size(manager->psaList);i++){
+					pubsub_admin_service_pt psa = (pubsub_admin_service_pt)arrayList_get(manager->psaList,i);
+					status += psa->closeAllPublications(psa->admin,p->scope, p->topic);
+				}
+			}
+
+			pubsubEndpoint_destroy(p);
+		}
+
+
+	}
+	free(pub_key);
+	celixThreadMutex_unlock(&manager->publicationsLock);
+	celixThreadMutex_unlock(&manager->psaListLock);
+
+
+	return status;
+}
+


[6/6] celix git commit: CELIX-389: Adds Celix Publish Subscribe donation.

Posted by pn...@apache.org.
CELIX-389: Adds Celix Publish Subscribe donation.


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

Branch: refs/heads/develop
Commit: f9a5fb11e28b642c33a84de8f3e53215e0065ad6
Parents: 3e67852
Author: Pepijn Noltes <pe...@gmail.com>
Authored: Mon Feb 6 15:21:04 2017 +0100
Committer: Pepijn Noltes <pe...@gmail.com>
Committed: Mon Feb 6 15:21:04 2017 +0100

----------------------------------------------------------------------
 celix-pubsub/cmake/FindCZMQ.cmake               |  42 +
 celix-pubsub/cmake/FindZMQ.cmake                |  42 +
 celix-pubsub/pubsub/CMakeLists.txt              |  48 ++
 celix-pubsub/pubsub/README.md                   |  71 ++
 celix-pubsub/pubsub/api/pubsub/publisher.h      |  88 +++
 celix-pubsub/pubsub/api/pubsub/subscriber.h     |  75 ++
 celix-pubsub/pubsub/deploy/CMakeLists.txt       | 123 +++
 celix-pubsub/pubsub/examples/CMakeLists.txt     |  19 +
 celix-pubsub/pubsub/examples/keys/README.md     |  19 +
 .../examples/keys/publisher/private/.gitkeep    |   0
 .../examples/keys/publisher/public/.gitkeep     |   0
 .../examples/keys/subscriber/private/.gitkeep   |   0
 .../examples/keys/subscriber/public/.gitkeep    |   0
 .../pubsub/examples/mp_pubsub/CMakeLists.txt    |  23 +
 .../examples/mp_pubsub/common/include/ew.h      |  53 ++
 .../examples/mp_pubsub/common/include/ide.h     |  49 ++
 .../mp_pubsub/common/include/kinematics.h       |  55 ++
 .../mp_pubsub/msg_descriptors/msg_ew.descriptor |   9 +
 .../msg_descriptors/msg_ide.descriptor          |   9 +
 .../msg_descriptors/msg_kinematics.descriptor   |  10 +
 .../examples/mp_pubsub/publisher/CMakeLists.txt |  48 ++
 .../private/include/mp_publisher_private.h      |  58 ++
 .../publisher/private/src/mp_pub_activator.c    | 150 ++++
 .../publisher/private/src/mp_publisher.c        | 161 ++++
 .../mp_pubsub/subscriber/CMakeLists.txt         |  48 ++
 .../private/include/mp_subscriber_private.h     |  51 ++
 .../subscriber/private/src/mp_sub_activator.c   | 117 +++
 .../subscriber/private/src/mp_subscriber.c      | 119 +++
 .../pubsub/examples/pubsub/CMakeLists.txt       |  24 +
 .../pubsub/examples/pubsub/common/include/poi.h |  55 ++
 .../pubsub/msg_descriptors/msg_poi1.descriptor  |  10 +
 .../pubsub/msg_descriptors/msg_poi2.descriptor  |  10 +
 .../pubsub/msg_descriptors/poi1.properties      |  18 +
 .../pubsub/msg_descriptors/poi2.properties      |  18 +
 .../examples/pubsub/publisher/CMakeLists.txt    |  52 ++
 .../private/include/pubsub_publisher_private.h  |  60 ++
 .../publisher/private/src/ps_pub_activator.c    | 157 ++++
 .../publisher/private/src/pubsub_publisher.c    | 164 ++++
 .../examples/pubsub/publisher2/CMakeLists.txt   |  54 ++
 .../examples/pubsub/subscriber/CMakeLists.txt   |  53 ++
 .../private/include/pubsub_subscriber_private.h |  52 ++
 .../subscriber/private/src/ps_sub_activator.c   | 123 +++
 .../subscriber/private/src/pubsub_subscriber.c  |  64 ++
 celix-pubsub/pubsub/keygen/CMakeLists.txt       |  34 +
 celix-pubsub/pubsub/keygen/ed_file.c            | 309 ++++++++
 celix-pubsub/pubsub/keygen/makecert.c           |  55 ++
 .../pubsub/pubsub_admin_udp_mc/CMakeLists.txt   |  57 ++
 .../pubsub/pubsub_admin_udp_mc/README.md        |  62 ++
 .../private/include/large_udp.h                 |  45 ++
 .../private/include/pubsub_admin_impl.h         |  71 ++
 .../include/pubsub_publish_service_private.h    |  55 ++
 .../private/include/topic_subscription.h        |  55 ++
 .../pubsub_admin_udp_mc/private/src/large_udp.c | 362 +++++++++
 .../private/src/psa_activator.c                 | 113 +++
 .../private/src/pubsub_admin_impl.c             | 670 ++++++++++++++++
 .../private/src/topic_publication.c             | 470 ++++++++++++
 .../private/src/topic_subscription.c            | 497 ++++++++++++
 .../pubsub/pubsub_admin_zmq/CMakeLists.txt      |  70 ++
 .../private/include/pubsub_admin_impl.h         |  86 +++
 .../include/pubsub_publish_service_private.h    |  47 ++
 .../private/include/topic_subscription.h        |  57 ++
 .../private/include/zmq_crypto.h                |  41 +
 .../private/src/psa_activator.c                 | 112 +++
 .../private/src/pubsub_admin_impl.c             | 699 +++++++++++++++++
 .../private/src/topic_publication.c             | 605 +++++++++++++++
 .../private/src/topic_subscription.c            | 741 ++++++++++++++++++
 .../pubsub_admin_zmq/private/src/zmq_crypto.c   | 281 +++++++
 .../public/include/dyn_msg_utils.h              |  39 +
 .../pubsub/pubsub_common/public/include/etcd.h  |  39 +
 .../include/publisher_endpoint_announce.h       |  36 +
 .../pubsub_common/public/include/pubsub_admin.h |  56 ++
 .../public/include/pubsub_common.h              |  51 ++
 .../public/include/pubsub_endpoint.h            |  49 ++
 .../public/include/pubsub_serializer.h          |  47 ++
 .../public/include/pubsub_topic_info.descriptor |  10 +
 .../pubsub_common/public/include/pubsub_utils.h |  39 +
 .../pubsub_common/public/src/dyn_msg_utils.c    | 156 ++++
 .../pubsub/pubsub_common/public/src/etcd.c      | 476 ++++++++++++
 .../pubsub_common/public/src/log_helper.c       | 209 +++++
 .../pubsub_common/public/src/pubsub_endpoint.c  | 156 ++++
 .../public/src/pubsub_serializer.c              | 105 +++
 .../pubsub_common/public/src/pubsub_utils.c     | 163 ++++
 .../pubsub/pubsub_discovery/CMakeLists.txt      |  43 ++
 .../private/include/etcd_common.h               |  28 +
 .../private/include/etcd_watcher.h              |  38 +
 .../private/include/etcd_writer.h               |  39 +
 .../private/include/pubsub_discovery_impl.h     |  73 ++
 .../pubsub_discovery/private/src/etcd_common.c  |  81 ++
 .../pubsub_discovery/private/src/etcd_watcher.c | 292 +++++++
 .../pubsub_discovery/private/src/etcd_writer.c  | 189 +++++
 .../private/src/psd_activator.c                 | 171 +++++
 .../private/src/pubsub_discovery_impl.c         | 468 ++++++++++++
 .../public/include/pubsub_discovery.h           |  26 +
 .../pubsub_topology_manager/CMakeLists.txt      |  43 ++
 .../private/include/pubsub_topology_manager.h   |  86 +++
 .../private/src/pstm_activator.c                | 233 ++++++
 .../private/src/pubsub_topology_manager.c       | 758 +++++++++++++++++++
 97 files changed, 12194 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/cmake/FindCZMQ.cmake
----------------------------------------------------------------------
diff --git a/celix-pubsub/cmake/FindCZMQ.cmake b/celix-pubsub/cmake/FindCZMQ.cmake
new file mode 100644
index 0000000..4f4891c
--- /dev/null
+++ b/celix-pubsub/cmake/FindCZMQ.cmake
@@ -0,0 +1,42 @@
+# 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.
+
+
+# - Try to find CZMQ
+# 	Once done this will define
+#  CZMQ_FOUND - System has Zmq
+#  CZMQ_INCLUDE_DIRS - The Zmq include directories
+#  CZMQ_LIBRARIES - The libraries needed to use Zmq
+#  CZMQ_DEFINITIONS - Compiler switches required for using Zmq
+
+find_path(CZMQ_INCLUDE_DIR czmq.h
+          /usr/include
+          /usr/local/include )
+
+find_library(CZMQ_LIBRARY NAMES czmq
+             PATHS /usr/lib /usr/local/lib /usr/lib64 /usr/local/lib64 )
+
+set(CZMQ_LIBRARIES ${CZMQ_LIBRARY} )
+set(CZMQ_INCLUDE_DIRS ${CZMQ_INCLUDE_DIR} )
+
+include(FindPackageHandleStandardArgs)
+# handle the QUIETLY and REQUIRED arguments and set CZMQ_FOUND to TRUE
+# if all listed variables are TRUE
+find_package_handle_standard_args(Czmq  DEFAULT_MSG
+                                  CZMQ_LIBRARY CZMQ_INCLUDE_DIR)
+
+mark_as_advanced(CZMQ_INCLUDE_DIR CZMQ_LIBRARY )

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/cmake/FindZMQ.cmake
----------------------------------------------------------------------
diff --git a/celix-pubsub/cmake/FindZMQ.cmake b/celix-pubsub/cmake/FindZMQ.cmake
new file mode 100644
index 0000000..b2c2663
--- /dev/null
+++ b/celix-pubsub/cmake/FindZMQ.cmake
@@ -0,0 +1,42 @@
+# 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.
+
+
+# - Try to find ZMQ
+# 	Once done this will define
+#  ZMQ_FOUND - System has Zmq
+#  ZMQ_INCLUDE_DIRS - The Zmq include directories
+#  ZMQ_LIBRARIES - The libraries needed to use Zmq
+#  ZMQ_DEFINITIONS - Compiler switches required for using Zmq
+
+find_path(ZMQ_INCLUDE_DIR zmq.h zmq_utils.h
+          /usr/include
+          /usr/local/include )
+
+find_library(ZMQ_LIBRARY NAMES zmq
+             PATHS /usr/lib /usr/local/lib /usr/lib64 /usr/local/lib64 )
+
+set(ZMQ_LIBRARIES ${ZMQ_LIBRARY} )
+set(ZMQ_INCLUDE_DIRS ${ZMQ_INCLUDE_DIR} )
+
+include(FindPackageHandleStandardArgs)
+# handle the QUIETLY and REQUIRED arguments and set ZMQ_FOUND to TRUE
+# if all listed variables are TRUE
+find_package_handle_standard_args(Zmq  DEFAULT_MSG
+                                  ZMQ_LIBRARY ZMQ_INCLUDE_DIR)
+
+mark_as_advanced(ZMQ_INCLUDE_DIR ZMQ_LIBRARY )

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/CMakeLists.txt b/celix-pubsub/pubsub/CMakeLists.txt
new file mode 100644
index 0000000..c61aaeb
--- /dev/null
+++ b/celix-pubsub/pubsub/CMakeLists.txt
@@ -0,0 +1,48 @@
+# 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.
+
+celix_subproject(PUBSUB "Option to build the pubsub bundles" OFF)
+if (PUBSUB)
+
+	include_directories("${PROJECT_SOURCE_DIR}/utils/public/include")
+	include_directories("${PROJECT_SOURCE_DIR}/framework/public/include")
+
+	option(ENABLE_ZMQ_SECURITY "Enable security for ZeroMQ" OFF)
+	
+	set (PUBSUB_SERIALIZER_SRC "${PROJECT_SOURCE_DIR}/pubsub/pubsub_common/public/src/pubsub_serializer.c")
+	set (SERIALIZER_PATH "" CACHE FILEPATH "Path to the directory which will contain the serializer (include / src).")
+	set (SERIALIZER_LIB_INCLUDE_DIR "" CACHE FILEPATH "Path to the include dir of the addiotional libs.")
+	set (SERIALIZER_LIB_PATH "" CACHE FILEPATH "Path to the additional library.")
+	if (EXISTS ${SERIALIZER_PATH})
+		file (GLOB PUBSUB_SERIALIZER_SRC ${SERIALIZER_PATH}/src/*.c)
+		
+		if (SERIALIZER_LIB_PATH)
+			get_filename_component(SERIALIZER_LIB_DIR ${SERIALIZER_LIB_PATH} DIRECTORY)
+			get_filename_component(SERIALIZER_LIB_FULLNAME ${SERIALIZER_LIB_PATH} NAME_WE)
+			string (REPLACE "lib" "" SERIALIZER_LIBRARY ${SERIALIZER_LIB_FULLNAME})
+		endif()
+	endif()
+	
+	add_subdirectory(pubsub_topology_manager)
+	add_subdirectory(pubsub_discovery)
+	add_subdirectory(pubsub_admin_zmq)
+	add_subdirectory(pubsub_admin_udp_mc)
+	add_subdirectory(examples)
+	add_subdirectory(deploy)
+	add_subdirectory(keygen)
+	
+endif(PUBSUB)

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/README.md
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/README.md b/celix-pubsub/pubsub/README.md
new file mode 100644
index 0000000..5980695
--- /dev/null
+++ b/celix-pubsub/pubsub/README.md
@@ -0,0 +1,71 @@
+# PubSubAdmin
+
+This subdirectory contains an implementation for a publish-subscribe remote services system, that use dfi library for message serialization.
+For low-level communication, UDP and ZMQ is used.
+
+# Description
+
+This publisher / subscriber implementation is based on the concepts of the remote service admin (i.e. rsa / topology / discovery pattern).
+
+Publishers are senders of data, subscribers can receive data. Publishers can publish/send data to certain channels (called 'topics' further on), subscribers can subscribe to these topics. For every topic a publisher service is created by the pubsub admin. This publisher is announced through etcd. So etcd is used for discovery of the publishers. Subscribers are also registered as a service by the pubsub admin and will watch etcd for changes and when a new publisher is announced, the subscriber will check if the topic matches its interests. If the subscriber is interested in/subscribed to a certain topic, a connection between publisher and subscriber will be instantiated by the pubsub admin.
+
+The dfi library is used for message serialization. The publisher / subscriber implementation will arrange that every message which will be send gets an unique id. 
+
+For communication between publishers and subscribers UDP and ZeroMQ can be used. When using ZeroMQ it's also possible to setup a secure connection to encrypt the traffic being send between publishers and subscribers. This connection can be secured with ZeroMQ by using a curve25519 key pair per topic.
+
+The publisher/subscriber implementation supports sending of a single message and sending of multipart messages.
+
+## Getting started
+
+To get the ZeroMQ pubsub admin running, [ZeroMQ](https://github.com/zeromq/libzmq) and [CZMQ](https://github.com/zeromq/czmq) needs to be installed.
+
+Also, to make use of encrypted traffic, [OpenSSL] is required.
+[OpenSSL github repo](https://github.com/openssl/openssl)
+
+## Running instructions
+
+### Running PSA ZMQ
+
+For ZeroMQ without encryption, skip the steps 1-12 below
+1. Run `touch ~/pubsub.keys`
+1. Run `echo "aes_key:{AES_KEY here}" >> ~/pubsub.keys`
+1. Run `echo "aes_iv:{AES_IV here}" >> ~/pubsub.keys`
+1. Run `touch ~/pubsub.conf`
+1. Run `echo "keys.file.path=$HOME" >> ~/pubsub.conf`
+1. Run `echo "keys.file.name=pubsub.keys" >> ~/pubsub.conf`
+1. To generate ZMQ keypairs
+1. Run `pubsub/keygen/makecert cert_topic1.pub cert_topic1.key`
+1. To encrypt files
+1. Run `pubsub/keygen/ed_file ~/pubsub.keys cert_topic1.key cert_topic1.key.enc`
+1. Store the keys in the pubsub/examples/keys/ directory
+1. Build project to include these keys
+
+For ZeroMQ without encryption, start here
+
+1. Run `etcd`
+
+1. Open second terminal on pubsub root
+1. Run `cd deploy/pubsub/pubsub_publisher_zmq`
+1. Run `cat ~/pubsub.conf >> config.properties` only for ZeroMQ with encryption
+1. Run `sh run.sh`
+
+1. Open third terminal on pubsub root
+1. Run `cd deploy/pubsub/pubsub_subscriber_zmq`
+1. Run `cat ~/pubsub.conf >> config.properties` only for ZeroMQ with encryption
+1. Run `sh run.sh`
+
+### Running PSA UDP-Multicast
+
+1. Open a terminal
+1. Run `etcd`
+
+1. Open second terminal on project build location
+1. Run `cd deploy/pubsub/pubsub_publisher_udp_mc`
+1. Run `sh run.sh`
+
+1. Open third terminal on project build location
+1. Run `cd deploy/pubsub/pubsub_subscriber_udp_mc`
+1. Run `sh run.sh`
+
+Design information can be found at pubsub\_admin\_udp_mc/README.md
+

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/api/pubsub/publisher.h
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/api/pubsub/publisher.h b/celix-pubsub/pubsub/api/pubsub/publisher.h
new file mode 100644
index 0000000..58ac589
--- /dev/null
+++ b/celix-pubsub/pubsub/api/pubsub/publisher.h
@@ -0,0 +1,88 @@
+/**
+ *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.
+ */
+/*
+ * publisher.h
+ *
+ *  \date       Jan 7, 2016
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#ifndef __PUBSUB_PUBLISHER_H_
+#define __PUBSUB_PUBLISHER_H_
+
+#include <stdlib.h>
+
+#define PUBSUB_PUBLISHER_SERVICE_NAME           "pubsub.publisher"
+#define PUBSUB_PUBLISHER_SERVICE_VERSION        "1.0.0"
+ 
+//properties
+#define PUBSUB_PUBLISHER_TOPIC                  "pubsub.topic"
+#define PUBSUB_PUBLISHER_SCOPE                  "pubsub.scope"
+#define PUBSUB_PUBLISHER_STRATEGY               "pubsub.strategy"
+#define PUBSUB_PUBLISHER_CONFIG                 "pubsub.config"
+ 
+#define PUBSUB_PUBLISHER_SCOPE_DEFAULT			"default"
+//flags
+#define PUBSUB_PUBLISHER_FIRST_MSG  01
+#define PUBSUB_PUBLISHER_PART_MSG   02
+#define PUBSUB_PUBLISHER_LAST_MSG   04
+
+struct pubsub_release_callback_struct {
+    void *handle;
+    void (*release)(char *buf, void *handle);
+};
+typedef struct pubsub_release_callback_struct pubsub_release_callback_t;
+typedef struct pubsub_release_callback_struct* pubsub_release_callback_pt;
+ 
+ 
+struct pubsub_publisher {
+    void *handle;
+ 
+    /**
+     * Every msg is identifiable by msg type string. Because masg type string are performance wise not preferable (string compares),
+     * a "local" (int / platform dependent) unique id will be generated runtime
+     * with use of a distributed key/value store or communication between  participation parties.
+     * this is called the local message type id. This local message type id can be requested with the localMsgIdForMsgType method.
+     * When return is successful the msgTypeId is always greater than 0. (Note this can be used to specify/detect uninitialized msg type ids in the consumer code).
+     *
+     * Returns 0 on success.
+     */
+    int (*localMsgTypeIdForMsgType)(void *handle, const char *msgType, unsigned int *msgTypeId);
+  
+    /**
+     * send is a async function, but the msg can be safely deleted after send returns.
+     * Returns 0 on success.
+     */
+    int (*send)(void *handle, unsigned int msgTypeId, void *msg);
+ 
+  
+    /**
+     * sendMultipart is a async function, but the msg can be safely deleted after send returns.
+     * The first (primary) message of a multipart message must have the flag PUBLISHER_PRIMARY_MSG
+     * The last message of a multipart message must have the flag PUBLISHER_LAST_MSG
+     * Returns 0 on success.
+     */
+    int (*sendMultipart)(void *handle, unsigned int msgTypeId, void *msg, int flags);
+ 
+};
+typedef struct pubsub_publisher pubsub_publisher_t;
+typedef struct pubsub_publisher* pubsub_publisher_pt;
+
+#endif // __PUBSUB_PUBLISHER_H_

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/api/pubsub/subscriber.h
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/api/pubsub/subscriber.h b/celix-pubsub/pubsub/api/pubsub/subscriber.h
new file mode 100644
index 0000000..cbbe96c
--- /dev/null
+++ b/celix-pubsub/pubsub/api/pubsub/subscriber.h
@@ -0,0 +1,75 @@
+/**
+ *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.
+ */
+/*
+ * subscriber.h
+ *
+ *  \date       Jan 7, 2016
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#ifndef __PUBSUB_SUBSCRIBER_H_
+#define __PUBSUB_SUBSCRIBER_H_
+
+#include <stdbool.h>
+
+#define PUBSUB_SUBSCRIBER_SERVICE_NAME          "pubsub.subscriber"
+#define PUBSUB_SUBSCRIBER_SERVICE_VERSION       "1.0.0"
+ 
+//properties
+#define PUBSUB_SUBSCRIBER_TOPIC                "pubsub.topic"
+#define PUBSUB_SUBSCRIBER_SCOPE                "pubsub.scope"
+#define PUBSUB_SUBSCRIBER_STRATEGY             "pubsub.strategy"
+#define PUBSUB_SUBSCRIBER_CONFIG               "pubsub.config"
+
+#define PUBSUB_SUBSCRIBER_SCOPE_DEFAULT        "default"
+ 
+struct pubsub_multipart_callbacks_struct {
+    void *handle;
+    int (*localMsgTypeIdForMsgType)(void *handle, const char *msgType, unsigned int *msgId);
+    int (*getMultipart)(void *handle, unsigned int msgTypeId, bool retain, void **part);
+};
+typedef struct pubsub_multipart_callbacks_struct pubsub_multipart_callbacks_t;
+typedef struct pubsub_multipart_callbacks_struct* pubsub_multipart_callbacks_pt;
+ 
+struct pubsub_subscriber_struct {
+    void *handle;
+     
+    /**
+     * When a new message for a topic is available the receive will be called.
+     * 
+     * msgType contains fully qualified name of the type and msgTypeId is a local id which presents the type for performance reasons.
+     * Release can be used to instruct the pubsubadmin to release (free) the message when receive function returns. Set it to false to take
+     * over ownership of the msg (e.g. take the responsibility to free it).
+     *
+     * The callbacks argument is only valid inside the receive function, use the getMultipart callback, with retain=true, to keep multipart messages in memory.
+     * results of the localMsgTypeIdForMsgType callback are valid during the complete lifecycle of the component, not just a single receive call.
+     *
+     * Return 0 implies a successful handling. If return is not 0, the msg will always be released by the pubsubadmin.
+     *
+     * this method can be  NULL.
+     */
+    int (*receive)(void *handle, const char *msgType, unsigned int msgTypeId, void *msg, pubsub_multipart_callbacks_t *callbacks, bool *release);
+
+};
+typedef struct pubsub_subscriber_struct pubsub_subscriber_t;
+typedef struct pubsub_subscriber_struct* pubsub_subscriber_pt;
+
+
+#endif //  __PUBSUB_SUBSCRIBER_H_

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/deploy/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/deploy/CMakeLists.txt b/celix-pubsub/pubsub/deploy/CMakeLists.txt
new file mode 100644
index 0000000..5a3838b
--- /dev/null
+++ b/celix-pubsub/pubsub/deploy/CMakeLists.txt
@@ -0,0 +1,123 @@
+# 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.
+
+# ZMQ
+add_deploy("pubsub_zmq"
+    GROUP "pubsub"
+    BUNDLES
+       shell
+       shell_tui
+       org.apache.celix.pubsub_discovery.etcd.PubsubDiscovery
+       org.apache.celix.pubsub_topology_manager.PubSubTopologyManager
+       org.apache.celix.pubsub_admin.PubSubAdmin
+       org.apache.celix.pubsub_publisher.PoiPublisher
+       org.apache.celix.pubsub_subscriber.PoiSubscriber
+)
+
+add_deploy("pubsub_publisher_zmq" 
+    GROUP "pubsub"
+    BUNDLES
+       shell
+       shell_tui
+       org.apache.celix.pubsub_discovery.etcd.PubsubDiscovery
+       org.apache.celix.pubsub_topology_manager.PubSubTopologyManager
+       org.apache.celix.pubsub_admin.PubSubAdmin
+       org.apache.celix.pubsub_publisher.PoiPublisher
+       org.apache.celix.pubsub_publisher.PoiPublisher2
+   	PROPERTIES
+	    pubsub.scope=my_small_scope
+   
+)
+
+add_deploy("pubsub_subscriber_zmq"
+    GROUP "pubsub"
+    BUNDLES
+       shell
+       shell_tui
+       org.apache.celix.pubsub_discovery.etcd.PubsubDiscovery
+       org.apache.celix.pubsub_topology_manager.PubSubTopologyManager
+       org.apache.celix.pubsub_admin.PubSubAdmin
+       org.apache.celix.pubsub_subscriber.PoiSubscriber
+)
+
+add_deploy("pubsub_subscriber2_zmq" 
+    GROUP "pubsub"
+    BUNDLES
+       shell
+       shell_tui
+       org.apache.celix.pubsub_discovery.etcd.PubsubDiscovery
+       org.apache.celix.pubsub_topology_manager.PubSubTopologyManager
+       org.apache.celix.pubsub_admin.PubSubAdmin
+       org.apache.celix.pubsub_subscriber.PoiSubscriber
+)
+
+# UDP Multicast
+add_deploy("pubsub_publisher_udp_mc" 
+    GROUP "pubsub"
+    BUNDLES
+       shell
+       shell_tui
+       org.apache.celix.pubsub_discovery.etcd.PubsubDiscovery
+       org.apache.celix.pubsub_topology_manager.PubSubTopologyManager
+       org.apache.celix.pubsub_admin.PubSubAdminUdpMc
+       org.apache.celix.pubsub_publisher.PoiPublisher
+)
+
+add_deploy("pubsub_subscriber_udp_mc" 
+    GROUP "pubsub"
+    BUNDLES
+       shell
+       shell_tui
+       org.apache.celix.pubsub_discovery.etcd.PubsubDiscovery
+       org.apache.celix.pubsub_topology_manager.PubSubTopologyManager
+       org.apache.celix.pubsub_admin.PubSubAdminUdpMc
+       org.apache.celix.pubsub_subscriber.PoiSubscriber
+)
+
+add_deploy("pubsub_subscriber2_udp_mc" 
+    GROUP "pubsub"
+    BUNDLES
+       shell
+       shell_tui
+       org.apache.celix.pubsub_discovery.etcd.PubsubDiscovery
+       org.apache.celix.pubsub_topology_manager.PubSubTopologyManager
+       org.apache.celix.pubsub_admin.PubSubAdminUdpMc
+       org.apache.celix.pubsub_subscriber.PoiSubscriber
+)
+
+# ZMQ Multipart
+add_deploy("pubsub_mp_subscriber_zmq" 
+    GROUP "pubsub"
+    BUNDLES
+       shell
+       shell_tui
+       org.apache.celix.pubsub_discovery.etcd.PubsubDiscovery
+       org.apache.celix.pubsub_topology_manager.PubSubTopologyManager
+       org.apache.celix.pubsub_admin.PubSubAdmin
+       org.apache.celix.pubsub_subscriber.MpSubscriber
+)
+
+add_deploy("pubsub_mp_publisher_zmq" 
+    GROUP "pubsub"
+    BUNDLES
+       shell
+       shell_tui
+       org.apache.celix.pubsub_discovery.etcd.PubsubDiscovery
+       org.apache.celix.pubsub_topology_manager.PubSubTopologyManager
+       org.apache.celix.pubsub_admin.PubSubAdmin
+       org.apache.celix.pubsub_publisher.MpPublisher
+)

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/examples/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/examples/CMakeLists.txt b/celix-pubsub/pubsub/examples/CMakeLists.txt
new file mode 100644
index 0000000..22ca5ca
--- /dev/null
+++ b/celix-pubsub/pubsub/examples/CMakeLists.txt
@@ -0,0 +1,19 @@
+# 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.
+
+add_subdirectory(pubsub)
+add_subdirectory(mp_pubsub)

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/examples/keys/README.md
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/examples/keys/README.md b/celix-pubsub/pubsub/examples/keys/README.md
new file mode 100644
index 0000000..8517415
--- /dev/null
+++ b/celix-pubsub/pubsub/examples/keys/README.md
@@ -0,0 +1,19 @@
+
+Store the AES key for encrypting and decrypting the encoded secret keys safe in a file!
+Default file is `/etc/pubsub.keys` with the following format:
+```
+aes_key:{32 character AES key here}
+aes_iv:{16 character AES iv here}
+```
+
+Use the $PROJECT_BUILD/pubsub/keygen/makecert for generating keypairs
+Use the $PROJECT_BUILD/pubsub/keygen/ed_file for encrypting and decrypting private keys
+
+Public keys need to be stored in the 'public' folder having the following format:
+- pub_{topic}.pub
+- sub_{topic}.pub
+
+Secret keys need to be stored in the 'private' folder having the following format:
+- pub_{topic}.key.enc
+- sub_{topic}.key.enc
+These files need to be encrypted using the 'ed_file' executable.

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/examples/keys/publisher/private/.gitkeep
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/examples/keys/publisher/private/.gitkeep b/celix-pubsub/pubsub/examples/keys/publisher/private/.gitkeep
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/examples/keys/publisher/public/.gitkeep
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/examples/keys/publisher/public/.gitkeep b/celix-pubsub/pubsub/examples/keys/publisher/public/.gitkeep
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/examples/keys/subscriber/private/.gitkeep
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/examples/keys/subscriber/private/.gitkeep b/celix-pubsub/pubsub/examples/keys/subscriber/private/.gitkeep
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/examples/keys/subscriber/public/.gitkeep
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/examples/keys/subscriber/public/.gitkeep b/celix-pubsub/pubsub/examples/keys/subscriber/public/.gitkeep
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/examples/mp_pubsub/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/examples/mp_pubsub/CMakeLists.txt b/celix-pubsub/pubsub/examples/mp_pubsub/CMakeLists.txt
new file mode 100644
index 0000000..c828832
--- /dev/null
+++ b/celix-pubsub/pubsub/examples/mp_pubsub/CMakeLists.txt
@@ -0,0 +1,23 @@
+# 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_directories("common/include")
+
+add_subdirectory(publisher)
+add_subdirectory(subscriber)
+
+

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/examples/mp_pubsub/common/include/ew.h
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/examples/mp_pubsub/common/include/ew.h b/celix-pubsub/pubsub/examples/mp_pubsub/common/include/ew.h
new file mode 100644
index 0000000..81ca5f3
--- /dev/null
+++ b/celix-pubsub/pubsub/examples/mp_pubsub/common/include/ew.h
@@ -0,0 +1,53 @@
+/**
+ *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.
+ */
+/*
+ * ew.h
+ *
+ *  \date       Jan 15, 2016
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#ifndef EW_H_
+#define EW_H_
+
+#define MIN_AREA	50.0F
+#define MAX_AREA	15000.0F
+
+#define MSG_EW_NAME	"ew" //Has to match the message name in the msg descriptor!
+
+typedef enum color{
+	GREEN,
+	BLUE,
+	RED,
+	BLACK,
+	WHITE,
+	LAST_COLOR
+} color_e;
+
+const char* color_tostring[] = {"GREEN","BLUE","RED","BLACK","WHITE"};
+
+struct ew_data{
+	double area;
+	color_e color;
+};
+
+typedef struct ew_data* ew_data_pt;
+
+#endif /* EW_H_ */

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/examples/mp_pubsub/common/include/ide.h
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/examples/mp_pubsub/common/include/ide.h b/celix-pubsub/pubsub/examples/mp_pubsub/common/include/ide.h
new file mode 100644
index 0000000..2b9588d
--- /dev/null
+++ b/celix-pubsub/pubsub/examples/mp_pubsub/common/include/ide.h
@@ -0,0 +1,49 @@
+/**
+ *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.
+ */
+/*
+ * ide.h
+ *
+ *  \date       Jan 15, 2016
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#ifndef IDE_H_
+#define IDE_H_
+
+#define MSG_IDE_NAME	"ide" //Has to match the message name in the msg descriptor!
+
+typedef enum shape{
+	SQUARE,
+	CIRCLE,
+	TRIANGLE,
+	RECTANGLE,
+	HEXAGON,
+	LAST_SHAPE
+} shape_e;
+
+const char* shape_tostring[] = {"SQUARE","CIRCLE","TRIANGLE","RECTANGLE","HEXAGON"};
+
+struct ide{
+	shape_e shape;
+};
+
+typedef struct ide* ide_pt;
+
+#endif /* IDE_H_ */

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/examples/mp_pubsub/common/include/kinematics.h
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/examples/mp_pubsub/common/include/kinematics.h b/celix-pubsub/pubsub/examples/mp_pubsub/common/include/kinematics.h
new file mode 100644
index 0000000..5601509
--- /dev/null
+++ b/celix-pubsub/pubsub/examples/mp_pubsub/common/include/kinematics.h
@@ -0,0 +1,55 @@
+/**
+ *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.
+ */
+/*
+ * kinematics.h
+ *
+ *  \date       Nov 12, 2015
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#ifndef KINEMATICS_H_
+#define KINEMATICS_H_
+
+#define MIN_LAT	-90.0F
+#define MAX_LAT	 90.0F
+#define MIN_LON	-180.0F
+#define MAX_LON	 180.0F
+
+#define MIN_OCCUR 1
+#define MAX_OCCUR 5
+
+#define MSG_KINEMATICS_NAME	"kinematics" //Has to match the message name in the msg descriptor!
+
+struct position{
+	double lat;
+	double lon;
+};
+
+typedef struct position position_t;
+
+struct kinematics{
+	position_t position;
+	int occurrences;
+};
+
+typedef struct kinematics* kinematics_pt;
+
+
+#endif /* KINEMATICS_H_ */

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/examples/mp_pubsub/msg_descriptors/msg_ew.descriptor
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/examples/mp_pubsub/msg_descriptors/msg_ew.descriptor b/celix-pubsub/pubsub/examples/mp_pubsub/msg_descriptors/msg_ew.descriptor
new file mode 100644
index 0000000..7eb8c29
--- /dev/null
+++ b/celix-pubsub/pubsub/examples/mp_pubsub/msg_descriptors/msg_ew.descriptor
@@ -0,0 +1,9 @@
+:header
+type=message
+name=ew
+version=1.0.0
+:annotations
+classname=org.example.Ew
+:types
+:message
+{Di area color}

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/examples/mp_pubsub/msg_descriptors/msg_ide.descriptor
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/examples/mp_pubsub/msg_descriptors/msg_ide.descriptor b/celix-pubsub/pubsub/examples/mp_pubsub/msg_descriptors/msg_ide.descriptor
new file mode 100644
index 0000000..f26286d
--- /dev/null
+++ b/celix-pubsub/pubsub/examples/mp_pubsub/msg_descriptors/msg_ide.descriptor
@@ -0,0 +1,9 @@
+:header
+type=message
+name=ide
+version=1.0.0
+:annotations
+classname=org.example.Ide
+:types
+:message
+{i shape}

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/examples/mp_pubsub/msg_descriptors/msg_kinematics.descriptor
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/examples/mp_pubsub/msg_descriptors/msg_kinematics.descriptor b/celix-pubsub/pubsub/examples/mp_pubsub/msg_descriptors/msg_kinematics.descriptor
new file mode 100644
index 0000000..447b645
--- /dev/null
+++ b/celix-pubsub/pubsub/examples/mp_pubsub/msg_descriptors/msg_kinematics.descriptor
@@ -0,0 +1,10 @@
+:header
+type=message
+name=kinematics
+version=1.0.0
+:annotations
+classname=org.example.Kinematics
+:types
+position={DD lat long}
+:message
+{lposition;N position occurrences}

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/examples/mp_pubsub/publisher/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/examples/mp_pubsub/publisher/CMakeLists.txt b/celix-pubsub/pubsub/examples/mp_pubsub/publisher/CMakeLists.txt
new file mode 100644
index 0000000..36c2429
--- /dev/null
+++ b/celix-pubsub/pubsub/examples/mp_pubsub/publisher/CMakeLists.txt
@@ -0,0 +1,48 @@
+# 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_directories("private/include")
+include_directories("${PROJECT_SOURCE_DIR}/framework/public/include")
+include_directories("${PROJECT_SOURCE_DIR}/pubsub/pubsub_common/public/include")
+include_directories("${PROJECT_SOURCE_DIR}/pubsub/api/pubsub")
+include_directories("${PROJECT_SOURCE_DIR}/pubsub/examples/mp_pubsub/common/include")
+
+add_bundle(org.apache.celix.pubsub_publisher.MpPublisher
+    SYMBOLIC_NAME "apache_celix_pubsub_mp_publisher"
+    VERSION "1.0.0"
+    SOURCES 
+    	private/src/mp_pub_activator.c
+    	private/src/mp_publisher.c
+    	${PROJECT_SOURCE_DIR}/pubsub/pubsub_common/public/src/pubsub_utils.c
+)
+
+bundle_files(org.apache.celix.pubsub_publisher.MpPublisher
+	${PROJECT_SOURCE_DIR}/pubsub/examples/mp_pubsub/msg_descriptors/msg_ew.descriptor
+	${PROJECT_SOURCE_DIR}/pubsub/examples/mp_pubsub/msg_descriptors/msg_ide.descriptor
+	${PROJECT_SOURCE_DIR}/pubsub/examples/mp_pubsub/msg_descriptors/msg_kinematics.descriptor
+	DESTINATION "META-INF/descriptors"
+)
+
+bundle_files(org.apache.celix.pubsub_publisher.MpPublisher
+		${PROJECT_SOURCE_DIR}/pubsub/examples/keys/publisher
+    DESTINATION "META-INF/keys"
+)
+
+bundle_files(org.apache.celix.pubsub_publisher.MpPublisher
+		${PROJECT_SOURCE_DIR}/pubsub/examples/keys/subscriber/public
+    DESTINATION "META-INF/keys/subscriber"
+)

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/examples/mp_pubsub/publisher/private/include/mp_publisher_private.h
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/examples/mp_pubsub/publisher/private/include/mp_publisher_private.h b/celix-pubsub/pubsub/examples/mp_pubsub/publisher/private/include/mp_publisher_private.h
new file mode 100644
index 0000000..a9c070f
--- /dev/null
+++ b/celix-pubsub/pubsub/examples/mp_pubsub/publisher/private/include/mp_publisher_private.h
@@ -0,0 +1,58 @@
+/**
+ *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.
+ */
+/*
+ * mp_publisher_private.h
+ *
+ *  \date       Sep 21, 2010
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#ifndef MP_PUBLISHER_PRIVATE_H_
+#define MP_PUBLISHER_PRIVATE_H_
+
+#include <celixbool.h>
+
+#include "publisher.h"
+
+struct pubsub_sender {
+	array_list_pt trackers;
+	const char *ident;
+	long bundleId;
+};
+
+typedef struct pubsub_sender * pubsub_sender_pt;
+
+typedef struct send_thread_struct{
+	pubsub_publisher_pt service;
+	pubsub_sender_pt publisher;
+} *send_thread_struct_pt;
+
+pubsub_sender_pt publisher_create(array_list_pt trackers,const char* ident,long bundleId);
+
+void publisher_start(pubsub_sender_pt client);
+void publisher_stop(pubsub_sender_pt client);
+
+void publisher_destroy(pubsub_sender_pt client);
+
+celix_status_t publisher_publishSvcAdded(void * handle, service_reference_pt reference, void * service);
+celix_status_t publisher_publishSvcRemoved(void * handle, service_reference_pt reference, void * service);
+
+
+#endif /* MP_PUBLISHER_PRIVATE_H_ */

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/examples/mp_pubsub/publisher/private/src/mp_pub_activator.c
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/examples/mp_pubsub/publisher/private/src/mp_pub_activator.c b/celix-pubsub/pubsub/examples/mp_pubsub/publisher/private/src/mp_pub_activator.c
new file mode 100644
index 0000000..231157a
--- /dev/null
+++ b/celix-pubsub/pubsub/examples/mp_pubsub/publisher/private/src/mp_pub_activator.c
@@ -0,0 +1,150 @@
+/**
+ *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.
+ */
+/*
+ * mp_pub_activator.c
+ *
+ *  \date       Sep 21, 2010
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#include <sys/cdefs.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bundle_activator.h"
+#include "service_tracker.h"
+#include "constants.h"
+
+#include "pubsub_common.h"
+#include "pubsub_utils.h"
+#include "mp_publisher_private.h"
+
+#define PUB_TOPIC "multipart"
+
+struct publisherActivator {
+	pubsub_sender_pt client;
+	array_list_pt trackerList;//List<service_tracker_pt>
+};
+
+celix_status_t bundleActivator_create(bundle_context_pt context, void **userData) {
+	struct publisherActivator * act = malloc(sizeof(*act));
+
+	const char* fwUUID = NULL;
+
+	bundleContext_getProperty(context,OSGI_FRAMEWORK_FRAMEWORK_UUID,&fwUUID);
+	if(fwUUID==NULL){
+		printf("MP_PUBLISHER: Cannot retrieve fwUUID.\n");
+		return CELIX_INVALID_BUNDLE_CONTEXT;
+	}
+
+	bundle_pt bundle = NULL;
+	long bundleId = 0;
+	bundleContext_getBundle(context,&bundle);
+	bundle_getBundleId(bundle,&bundleId);
+
+	arrayList_create(&(act->trackerList));
+	act->client = publisher_create(act->trackerList,fwUUID,bundleId);
+	*userData = act;
+
+	return CELIX_SUCCESS;
+}
+
+celix_status_t bundleActivator_start(void * userData, bundle_context_pt context) {
+
+	struct publisherActivator * act = (struct publisherActivator *) userData;
+
+	int i;
+
+	array_list_pt topic_list = pubsub_getTopicsFromString(PUB_TOPIC);
+
+	if(topic_list !=NULL){
+
+		char filter[128];
+
+		for(i=0; i<arrayList_size(topic_list);i++){
+			char* topic = arrayList_get(topic_list,i);
+			if(strlen(topic)<MAX_TOPIC_LEN){
+
+				bundle_pt bundle = NULL;
+				long bundleId = 0;
+				bundleContext_getBundle(context,&bundle);
+				bundle_getBundleId(bundle,&bundleId);
+
+				service_tracker_pt tracker = NULL;
+				memset(filter,0,128);
+
+				snprintf(filter, 128, "(&(%s=%s)(%s=%s))", (char*) OSGI_FRAMEWORK_OBJECTCLASS, PUBSUB_PUBLISHER_SERVICE_NAME, PUBSUB_PUBLISHER_TOPIC,topic);
+
+				service_tracker_customizer_pt customizer = NULL;
+
+				serviceTrackerCustomizer_create(act->client,NULL,publisher_publishSvcAdded,NULL,publisher_publishSvcRemoved,&customizer);
+				serviceTracker_createWithFilter(context, filter, customizer, &tracker);
+
+				arrayList_add(act->trackerList,tracker);
+			}
+			else{
+				printf("Topic %s too long. Skipping publication.\n",topic);
+			}
+			free(topic);
+		}
+		arrayList_destroy(topic_list);
+
+	}
+
+	publisher_start(act->client);
+
+	for(i=0;i<arrayList_size(act->trackerList);i++){
+		service_tracker_pt tracker = arrayList_get(act->trackerList,i);
+		serviceTracker_open(tracker);
+	}
+
+	return CELIX_SUCCESS;
+}
+
+celix_status_t bundleActivator_stop(void * userData, bundle_context_pt __attribute__((unused)) context) {
+	struct publisherActivator * act = (struct publisherActivator *) userData;
+	int i;
+
+	for(i=0;i<arrayList_size(act->trackerList);i++){
+		service_tracker_pt tracker = arrayList_get(act->trackerList,i);
+		serviceTracker_close(tracker);
+	}
+
+	publisher_stop(act->client);
+
+	return CELIX_SUCCESS;
+}
+
+celix_status_t bundleActivator_destroy(void * userData, bundle_context_pt  __attribute__((unused)) context) {
+	struct publisherActivator * act = (struct publisherActivator *) userData;
+	int i;
+
+	for(i=0;i<arrayList_size(act->trackerList);i++){
+		service_tracker_pt tracker = arrayList_get(act->trackerList,i);
+		serviceTracker_destroy(tracker);
+	}
+
+	publisher_destroy(act->client);
+	arrayList_destroy(act->trackerList);
+
+	free(act);
+
+	return CELIX_SUCCESS;
+}

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/examples/mp_pubsub/publisher/private/src/mp_publisher.c
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/examples/mp_pubsub/publisher/private/src/mp_publisher.c b/celix-pubsub/pubsub/examples/mp_pubsub/publisher/private/src/mp_publisher.c
new file mode 100644
index 0000000..851d9c1
--- /dev/null
+++ b/celix-pubsub/pubsub/examples/mp_pubsub/publisher/private/src/mp_publisher.c
@@ -0,0 +1,161 @@
+/**
+ *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.
+ */
+/*
+ * mp_publisher.c
+ *
+ *  \date       Sep 21, 2010
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <unistd.h>
+
+#include "service_tracker.h"
+#include "celix_threads.h"
+
+#include "pubsub_common.h"
+#include "ew.h"
+#include "ide.h"
+#include "kinematics.h"
+#include "mp_publisher_private.h"
+
+
+static bool stop=false;
+static celix_thread_t tid;
+
+static double randDouble(double min, double max){
+	double ret = min + (((double)rand()) / (((double)RAND_MAX)/(max-min))) ;
+	return ret;
+}
+
+static unsigned int randInt(unsigned int min, unsigned int max){
+	double scaled = ((double)rand())/((double)RAND_MAX);
+	return (max - min +1)*scaled + min;
+}
+
+static void* send_thread(void* arg){
+
+	send_thread_struct_pt st_struct = (send_thread_struct_pt)arg;
+
+	pubsub_publisher_pt publish_svc = (pubsub_publisher_pt)st_struct->service;
+
+	unsigned int kin_msg_id = 0;
+	unsigned int ide_msg_id = 0;
+	unsigned int ew_msg_id = 0;
+
+	if( publish_svc->localMsgTypeIdForMsgType(publish_svc->handle,(const char*)MSG_KINEMATICS_NAME,&kin_msg_id) != 0 ){
+		printf("MP_PUBLISHER: Cannot retrieve msgId for message '%s'\n",MSG_KINEMATICS_NAME);
+		return NULL;
+	}
+
+	if( publish_svc->localMsgTypeIdForMsgType(publish_svc->handle,(const char*)MSG_IDE_NAME,&ide_msg_id) != 0 ){
+		printf("MP_PUBLISHER: Cannot retrieve msgId for message '%s'\n",MSG_IDE_NAME);
+		return NULL;
+	}
+
+	if( publish_svc->localMsgTypeIdForMsgType(publish_svc->handle,(const char*)MSG_EW_NAME,&ew_msg_id) != 0 ){
+		printf("MP_PUBLISHER: Cannot retrieve msgId for message '%s'\n",MSG_EW_NAME);
+		return NULL;
+	}
+
+	kinematics_pt kin_data = calloc(1,sizeof(*kin_data));
+	ide_pt ide_data = calloc(1,sizeof(*ide_data));
+	ew_data_pt ew_data = calloc(1,sizeof(*ew_data));
+
+	unsigned int counter = 1;
+
+	while(stop==false){
+		kin_data->position.lat = randDouble(MIN_LAT,MAX_LAT);
+		kin_data->position.lon = randDouble(MIN_LON,MAX_LON);
+		kin_data->occurrences = randInt(MIN_OCCUR,MAX_OCCUR);
+		publish_svc->sendMultipart(publish_svc->handle,kin_msg_id,kin_data, PUBSUB_PUBLISHER_FIRST_MSG);
+		printf("Track#%u kin_data: pos=[%f, %f] occurrences=%d\n",counter,kin_data->position.lat,kin_data->position.lon, kin_data->occurrences);
+
+		ide_data->shape = (shape_e)randInt(0,LAST_SHAPE-1);
+		publish_svc->sendMultipart(publish_svc->handle,ide_msg_id,ide_data, PUBSUB_PUBLISHER_PART_MSG);
+		printf("Track#%u ide_data: shape=%s\n",counter,shape_tostring[(int)ide_data->shape]);
+
+		ew_data->area = randDouble(MIN_AREA,MAX_AREA);
+		ew_data->color = (color_e)randInt(0,LAST_COLOR-1);
+		publish_svc->sendMultipart(publish_svc->handle,ew_msg_id,ew_data, PUBSUB_PUBLISHER_LAST_MSG);
+		printf("Track#%u ew_data: area=%f color=%s\n",counter,ew_data->area,color_tostring[(int)ew_data->color]);
+
+		printf("\n");
+		sleep(2);
+		counter++;
+	}
+
+	free(ew_data);
+	free(ide_data);
+	free(kin_data);
+	free(st_struct);
+
+	return NULL;
+
+}
+
+pubsub_sender_pt publisher_create(array_list_pt trackers,const char* ident,long bundleId) {
+	pubsub_sender_pt publisher = malloc(sizeof(*publisher));
+
+	publisher->trackers = trackers;
+	publisher->ident = ident;
+	publisher->bundleId = bundleId;
+
+	return publisher;
+}
+
+void publisher_start(pubsub_sender_pt client) {
+	printf("MP_PUBLISHER: starting up...\n");
+}
+
+void publisher_stop(pubsub_sender_pt client) {
+	printf("MP_PUBLISHER: stopping...\n");
+}
+
+void publisher_destroy(pubsub_sender_pt client) {
+	client->trackers = NULL;
+	client->ident = NULL;
+	free(client);
+}
+
+celix_status_t publisher_publishSvcAdded(void * handle, service_reference_pt reference, void * service){
+	pubsub_publisher_pt publish_svc = (pubsub_publisher_pt)service;
+	pubsub_sender_pt manager = (pubsub_sender_pt)handle;
+
+	printf("MP_PUBLISHER: new publish service exported (%s).\n",manager->ident);
+
+	send_thread_struct_pt data = calloc(1,sizeof(struct send_thread_struct));
+	data->service = publish_svc;
+	data->publisher = manager;
+
+	celixThread_create(&tid,NULL,send_thread,(void*)data);
+	return CELIX_SUCCESS;
+}
+
+celix_status_t publisher_publishSvcRemoved(void * handle, service_reference_pt reference, void * service){
+	//publish_service_pt publish_svc = (publish_service_pt)service;
+	pubsub_sender_pt manager = (pubsub_sender_pt)handle;
+	printf("MP_PUBLISHER: publish service unexported (%s)!\n",manager->ident);
+	stop=true;
+	celixThread_join(tid,NULL);
+	return CELIX_SUCCESS;
+}

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/examples/mp_pubsub/subscriber/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/examples/mp_pubsub/subscriber/CMakeLists.txt b/celix-pubsub/pubsub/examples/mp_pubsub/subscriber/CMakeLists.txt
new file mode 100644
index 0000000..503a708
--- /dev/null
+++ b/celix-pubsub/pubsub/examples/mp_pubsub/subscriber/CMakeLists.txt
@@ -0,0 +1,48 @@
+# 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_directories("private/include")
+include_directories("${PROJECT_SOURCE_DIR}/framework/public/include")
+include_directories("${PROJECT_SOURCE_DIR}/pubsub/pubsub_common/public/include")
+include_directories("${PROJECT_SOURCE_DIR}/pubsub/api/pubsub")
+include_directories("${PROJECT_SOURCE_DIR}/pubsub/examples/mp_pubsub/common/include")
+
+add_bundle( org.apache.celix.pubsub_subscriber.MpSubscriber
+    SYMBOLIC_NAME "apache_celix_pubsub_mp_subscriber"
+    VERSION "1.0.0"
+    SOURCES 
+		private/src/mp_sub_activator.c
+		private/src/mp_subscriber.c
+		${PROJECT_SOURCE_DIR}/pubsub/pubsub_common/public/src/pubsub_utils.c
+)
+
+bundle_files( org.apache.celix.pubsub_subscriber.MpSubscriber
+	    ${PROJECT_SOURCE_DIR}/pubsub/examples/mp_pubsub/msg_descriptors/msg_ew.descriptor
+	    ${PROJECT_SOURCE_DIR}/pubsub/examples/mp_pubsub/msg_descriptors/msg_ide.descriptor
+	    ${PROJECT_SOURCE_DIR}/pubsub/examples/mp_pubsub/msg_descriptors/msg_kinematics.descriptor
+	DESTINATION "META-INF/descriptors"
+)
+
+bundle_files(org.apache.celix.pubsub_subscriber.MpSubscriber
+		${PROJECT_SOURCE_DIR}/pubsub/examples/keys/subscriber
+    DESTINATION "META-INF/keys"
+)
+
+bundle_files(org.apache.celix.pubsub_subscriber.MpSubscriber
+		${PROJECT_SOURCE_DIR}/pubsub/examples/keys/publisher/public
+    DESTINATION "META-INF/keys/publisher"
+)

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/examples/mp_pubsub/subscriber/private/include/mp_subscriber_private.h
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/examples/mp_pubsub/subscriber/private/include/mp_subscriber_private.h b/celix-pubsub/pubsub/examples/mp_pubsub/subscriber/private/include/mp_subscriber_private.h
new file mode 100644
index 0000000..1cc7270
--- /dev/null
+++ b/celix-pubsub/pubsub/examples/mp_pubsub/subscriber/private/include/mp_subscriber_private.h
@@ -0,0 +1,51 @@
+/**
+ *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.
+ */
+/*
+ * mp_subscriber_private.h
+ *
+ *  \date       Sep 21, 2010
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#ifndef PUBSUB_SUBSCRIBER_PRIVATE_H_
+#define PUBSUB_SUBSCRIBER_PRIVATE_H_
+
+
+#include <string.h>
+
+#include "celixbool.h"
+
+#include "pubsub_common.h"
+#include "subscriber.h"
+
+struct pubsub_receiver {
+	char * name;
+};
+
+typedef struct pubsub_receiver* pubsub_receiver_pt;
+
+pubsub_receiver_pt subscriber_create(char* topics);
+void subscriber_start(pubsub_receiver_pt client);
+void subscriber_stop(pubsub_receiver_pt client);
+void subscriber_destroy(pubsub_receiver_pt client);
+
+int pubsub_subscriber_recv(void* handle, const char* msgType, unsigned int msgTypeId, void* msg,pubsub_multipart_callbacks_t *callbacks, bool* release);
+
+#endif /* PUBSUB_SUBSCRIBER_PRIVATE_H_ */

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/examples/mp_pubsub/subscriber/private/src/mp_sub_activator.c
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/examples/mp_pubsub/subscriber/private/src/mp_sub_activator.c b/celix-pubsub/pubsub/examples/mp_pubsub/subscriber/private/src/mp_sub_activator.c
new file mode 100644
index 0000000..ecd4245
--- /dev/null
+++ b/celix-pubsub/pubsub/examples/mp_pubsub/subscriber/private/src/mp_sub_activator.c
@@ -0,0 +1,117 @@
+/**
+ *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.
+ */
+/*
+ * mp_sub_activator.c
+ *
+ *  \date       Sep 21, 2010
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#include <stdlib.h>
+
+#include "bundle_activator.h"
+
+#include "pubsub_common.h"
+#include "pubsub_utils.h"
+#include "mp_subscriber_private.h"
+
+#define SUB_TOPIC "multipart"
+
+struct subscriberActivator {
+	array_list_pt registrationList; //List<service_registration_pt>
+	pubsub_subscriber_pt subsvc;
+};
+
+celix_status_t bundleActivator_create(bundle_context_pt context, void **userData) {
+	struct subscriberActivator * act = calloc(1,sizeof(struct subscriberActivator));
+	*userData = act;
+	arrayList_create(&(act->registrationList));
+	return CELIX_SUCCESS;
+}
+
+celix_status_t bundleActivator_start(void * userData, bundle_context_pt context) {
+	struct subscriberActivator * act = (struct subscriberActivator *) userData;
+
+
+	pubsub_subscriber_pt subsvc = calloc(1,sizeof(*subsvc));
+	pubsub_receiver_pt sub = subscriber_create(SUB_TOPIC);
+	subsvc->handle = sub;
+	subsvc->receive = pubsub_subscriber_recv;
+
+	act->subsvc = subsvc;
+
+	array_list_pt topic_list = pubsub_getTopicsFromString(SUB_TOPIC);
+
+	if(topic_list !=NULL){
+
+		int i;
+		for(i=0; i<arrayList_size(topic_list);i++){
+			char* topic = arrayList_get(topic_list,i);
+			if(strlen(topic)<MAX_TOPIC_LEN){
+				properties_pt props = properties_create();
+				properties_set(props, PUBSUB_SUBSCRIBER_TOPIC,topic);
+				service_registration_pt reg = NULL;
+				bundleContext_registerService(context, PUBSUB_SUBSCRIBER_SERVICE_NAME, subsvc, props, &reg);
+				arrayList_add(act->registrationList,reg);
+			}
+			else{
+				printf("Topic %s too long. Skipping subscription.\n",topic);
+			}
+			free(topic);
+		}
+		arrayList_destroy(topic_list);
+
+	}
+
+	subscriber_start((pubsub_receiver_pt)act->subsvc->handle);
+
+	return CELIX_SUCCESS;
+}
+
+celix_status_t bundleActivator_stop(void * userData, bundle_context_pt context) {
+	struct subscriberActivator * act = (struct subscriberActivator *) userData;
+
+	int i;
+	for(i=0; i<arrayList_size(act->registrationList);i++){
+		service_registration_pt reg = arrayList_get(act->registrationList,i);
+		serviceRegistration_unregister(reg);
+
+	}
+
+	subscriber_stop((pubsub_receiver_pt)act->subsvc->handle);
+
+	return CELIX_SUCCESS;
+}
+
+celix_status_t bundleActivator_destroy(void * userData, bundle_context_pt context) {
+
+	struct subscriberActivator * act = (struct subscriberActivator *) userData;
+
+	act->subsvc->receive = NULL;
+	subscriber_destroy((pubsub_receiver_pt)act->subsvc->handle);
+	act->subsvc->handle = NULL;
+	free(act->subsvc);
+	act->subsvc = NULL;
+
+	arrayList_destroy(act->registrationList);
+	free(act);
+
+	return CELIX_SUCCESS;
+}

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/examples/mp_pubsub/subscriber/private/src/mp_subscriber.c
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/examples/mp_pubsub/subscriber/private/src/mp_subscriber.c b/celix-pubsub/pubsub/examples/mp_pubsub/subscriber/private/src/mp_subscriber.c
new file mode 100644
index 0000000..a5ad03a
--- /dev/null
+++ b/celix-pubsub/pubsub/examples/mp_pubsub/subscriber/private/src/mp_subscriber.c
@@ -0,0 +1,119 @@
+/**
+ *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.
+ */
+/*
+ * mp_subscriber.c
+ *
+ *  \date       Sep 21, 2010
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "ew.h"
+#include "ide.h"
+#include "kinematics.h"
+#include "mp_subscriber_private.h"
+
+pubsub_receiver_pt subscriber_create(char* topics) {
+	pubsub_receiver_pt sub = calloc(1,sizeof(*sub));
+	sub->name = strdup(topics);
+	return sub;
+}
+
+
+void subscriber_start(pubsub_receiver_pt subscriber){
+	printf("MP_SUBSCRIBER: starting up...\n");
+}
+
+void subscriber_stop(pubsub_receiver_pt subscriber){
+	printf("MP_SUBSCRIBER: stopping...\n");
+}
+
+void subscriber_destroy(pubsub_receiver_pt subscriber){
+	if(subscriber->name!=NULL){
+		free(subscriber->name);
+	}
+	subscriber->name=NULL;
+	free(subscriber);
+}
+
+int pubsub_subscriber_recv(void* handle, const char* msgType, unsigned int msgTypeId, void* msg,pubsub_multipart_callbacks_t *callbacks, bool* release){
+
+	unsigned int kin_msg_id = 0;
+	unsigned int ide_msg_id = 0;
+	unsigned int ew_msg_id = 0;
+
+	if( callbacks->localMsgTypeIdForMsgType(callbacks->handle,(const char*)MSG_KINEMATICS_NAME,&kin_msg_id) != 0 ){
+		printf("MP_SUBSCRIBER: Cannot retrieve msgId for message '%s'\n",MSG_KINEMATICS_NAME);
+		return -1;
+	}
+
+	if( callbacks->localMsgTypeIdForMsgType(callbacks->handle,(const char*)MSG_IDE_NAME,&ide_msg_id) != 0 ){
+		printf("MP_SUBSCRIBER: Cannot retrieve msgId for message '%s'\n",MSG_IDE_NAME);
+		return -1;
+	}
+
+	if( callbacks->localMsgTypeIdForMsgType(callbacks->handle,(const char*)MSG_EW_NAME,&ew_msg_id) != 0 ){
+		printf("MP_SUBSCRIBER: Cannot retrieve msgId for message '%s'\n",MSG_EW_NAME);
+		return -1;
+	}
+
+	if(msgTypeId!=kin_msg_id){
+		printf("MP_SUBSCRIBER: Multipart Message started with wrong message (expected %u, got %u)\n",msgTypeId,kin_msg_id);
+		return -1;
+	}
+
+	kinematics_pt kin_data = (kinematics_pt)msg;
+
+	void* ide_msg = NULL;
+	callbacks->getMultipart(callbacks->handle,ide_msg_id,false,&ide_msg);
+
+	void* ew_msg = NULL;
+	callbacks->getMultipart(callbacks->handle,ew_msg_id,false,&ew_msg);
+
+	if(kin_data==NULL){
+		printf("MP_SUBSCRIBER: Unexpected NULL data for message '%s'\n",MSG_KINEMATICS_NAME);
+	}
+	else{
+		printf("kin_data: pos=[%f, %f] occurrences=%d\n",kin_data->position.lat,kin_data->position.lon, kin_data->occurrences);
+	}
+
+	if(ide_msg==NULL){
+		printf("MP_SUBSCRIBER: Unexpected NULL data for message '%s'\n",MSG_IDE_NAME);
+	}
+	else{
+		ide_pt ide_data = (ide_pt)ide_msg;
+		printf("ide_data: shape=%s\n",shape_tostring[(int)ide_data->shape]);
+	}
+
+	if(ew_msg==NULL){
+		printf("MP_SUBSCRIBER: Unexpected NULL data for message '%s'\n",MSG_EW_NAME);
+	}
+	else{
+		ew_data_pt ew_data = (ew_data_pt)ew_msg;
+		printf("ew_data: area=%f color=%s\n",ew_data->area,color_tostring[(int)ew_data->color]);
+	}
+
+	printf("\n");
+
+	return 0;
+
+}

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/examples/pubsub/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/examples/pubsub/CMakeLists.txt b/celix-pubsub/pubsub/examples/pubsub/CMakeLists.txt
new file mode 100644
index 0000000..73b3e52
--- /dev/null
+++ b/celix-pubsub/pubsub/examples/pubsub/CMakeLists.txt
@@ -0,0 +1,24 @@
+# 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_directories("common/include")
+
+add_subdirectory(publisher)
+add_subdirectory(publisher2)
+add_subdirectory(subscriber)
+
+

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/examples/pubsub/common/include/poi.h
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/examples/pubsub/common/include/poi.h b/celix-pubsub/pubsub/examples/pubsub/common/include/poi.h
new file mode 100644
index 0000000..7bb077e
--- /dev/null
+++ b/celix-pubsub/pubsub/examples/pubsub/common/include/poi.h
@@ -0,0 +1,55 @@
+/**
+ *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.
+ */
+/*
+ * poi.h
+ *
+ *  \date       Nov 12, 2015
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#ifndef POI_H_
+#define POI_H_
+
+#define MIN_LAT	-90.0F
+#define MAX_LAT	 90.0F
+#define MIN_LON	-180.0F
+#define MAX_LON	 180.0F
+
+#define MSG_POI_NAME	"poi" //Has to match the message name in the msg descriptor!
+
+struct poi{
+	double lat;
+	double lon;
+};
+
+typedef struct poi1 poi1_t;
+
+struct location{
+	struct poi position;
+	char* name;
+	char* description;
+	char* extra;
+	char* data;
+};
+
+typedef struct location* location_t;
+
+
+#endif /* POI_H_ */

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/examples/pubsub/msg_descriptors/msg_poi1.descriptor
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/examples/pubsub/msg_descriptors/msg_poi1.descriptor b/celix-pubsub/pubsub/examples/pubsub/msg_descriptors/msg_poi1.descriptor
new file mode 100644
index 0000000..e547b62
--- /dev/null
+++ b/celix-pubsub/pubsub/examples/pubsub/msg_descriptors/msg_poi1.descriptor
@@ -0,0 +1,10 @@
+:header
+type=message
+name=poi1
+version=1.0.0
+:annotations
+classname=org.example.PointOfInterest
+:types
+location={DD lat long}
+:message
+{llocation;tttt location name description extra data}

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/examples/pubsub/msg_descriptors/msg_poi2.descriptor
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/examples/pubsub/msg_descriptors/msg_poi2.descriptor b/celix-pubsub/pubsub/examples/pubsub/msg_descriptors/msg_poi2.descriptor
new file mode 100644
index 0000000..0c369b5
--- /dev/null
+++ b/celix-pubsub/pubsub/examples/pubsub/msg_descriptors/msg_poi2.descriptor
@@ -0,0 +1,10 @@
+:header
+type=message
+name=poi2
+version=1.0.0
+:annotations
+classname=org.example.PointOfInterest
+:types
+location={DD lat long}
+:message
+{llocation;tttt location name description extra data}

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/examples/pubsub/msg_descriptors/poi1.properties
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/examples/pubsub/msg_descriptors/poi1.properties b/celix-pubsub/pubsub/examples/pubsub/msg_descriptors/poi1.properties
new file mode 100644
index 0000000..bd06c13
--- /dev/null
+++ b/celix-pubsub/pubsub/examples/pubsub/msg_descriptors/poi1.properties
@@ -0,0 +1,18 @@
+#
+# included in the bundle at location META-INF/topics/[pub|sub]/poi2.properties
+#
+
+#topic info
+topic.name=poi1
+topic.id=poi1
+
+#Interface info
+interface.name=org.example.unknown
+interface.version=1.0.0
+interface.messages=poi1 poi2
+
+# Version info
+interface.message.consumer.range@poi1=[0.0.0,1.0.0)
+interface.message.provider.version@poi1=0.0.0
+interface.message.consumer.range@poi2=[0.0.0,1.0.0)
+interface.message.provider.version@poi2=0.0.0

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/examples/pubsub/msg_descriptors/poi2.properties
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/examples/pubsub/msg_descriptors/poi2.properties b/celix-pubsub/pubsub/examples/pubsub/msg_descriptors/poi2.properties
new file mode 100644
index 0000000..2edbdf6
--- /dev/null
+++ b/celix-pubsub/pubsub/examples/pubsub/msg_descriptors/poi2.properties
@@ -0,0 +1,18 @@
+#
+# included in the bundle at location META-INF/topics/[pub|sub]/poi2.properties
+#
+
+#topic info
+topic.name=poi2
+topic.id=poi2
+
+#Interface info
+interface.name=org.example.unknown
+interface.version=1.0.0
+interface.messages=poi1 poi2
+
+# Version info
+interface.message.consumer.range@poi1=[0.0.0,1.0.0)
+interface.message.provider.version@poi1=0.0.0
+interface.message.consumer.range@poi2=[0.0.0,1.0.0)
+interface.message.provider.version@poi2=0.0.0

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/examples/pubsub/publisher/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/examples/pubsub/publisher/CMakeLists.txt b/celix-pubsub/pubsub/examples/pubsub/publisher/CMakeLists.txt
new file mode 100644
index 0000000..4a5feda
--- /dev/null
+++ b/celix-pubsub/pubsub/examples/pubsub/publisher/CMakeLists.txt
@@ -0,0 +1,52 @@
+# 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_directories("private/include")
+include_directories("${PROJECT_SOURCE_DIR}/framework/public/include")
+include_directories("${PROJECT_SOURCE_DIR}/pubsub/pubsub_common/public/include")
+include_directories("${PROJECT_SOURCE_DIR}/pubsub/api/pubsub")
+
+add_bundle(org.apache.celix.pubsub_publisher.PoiPublisher
+    SYMBOLIC_NAME "apache_celix_pubsub_poi_publisher"
+    VERSION "1.0.0"
+    SOURCES 
+    	private/src/ps_pub_activator.c
+    	private/src/pubsub_publisher.c
+    	${PROJECT_SOURCE_DIR}/pubsub/pubsub_common/public/src/pubsub_utils.c	
+)
+
+bundle_files(org.apache.celix.pubsub_publisher.PoiPublisher
+		${PROJECT_SOURCE_DIR}/pubsub/examples/pubsub/msg_descriptors/msg_poi1.descriptor
+		${PROJECT_SOURCE_DIR}/pubsub/examples/pubsub/msg_descriptors/msg_poi2.descriptor
+    DESTINATION "META-INF/descriptors"
+)
+
+bundle_files(org.apache.celix.pubsub_publisher.PoiPublisher
+		${PROJECT_SOURCE_DIR}/pubsub/examples/pubsub/msg_descriptors/poi1.properties
+		${PROJECT_SOURCE_DIR}/pubsub/examples/pubsub/msg_descriptors/poi2.properties
+    DESTINATION "META-INF/topics/pub"
+)
+
+bundle_files(org.apache.celix.pubsub_publisher.PoiPublisher
+		${PROJECT_SOURCE_DIR}/pubsub/examples/keys/publisher
+    DESTINATION "META-INF/keys"
+)
+
+bundle_files(org.apache.celix.pubsub_publisher.PoiPublisher
+		${PROJECT_SOURCE_DIR}/pubsub/examples/keys/subscriber/public
+    DESTINATION "META-INF/keys/subscriber"
+)

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/examples/pubsub/publisher/private/include/pubsub_publisher_private.h
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/examples/pubsub/publisher/private/include/pubsub_publisher_private.h b/celix-pubsub/pubsub/examples/pubsub/publisher/private/include/pubsub_publisher_private.h
new file mode 100644
index 0000000..834dada
--- /dev/null
+++ b/celix-pubsub/pubsub/examples/pubsub/publisher/private/include/pubsub_publisher_private.h
@@ -0,0 +1,60 @@
+/**
+ *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.
+ */
+/*
+ * pubsub_publisher_private.h
+ *
+ *  \date       Sep 21, 2010
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#ifndef PUBSUB_PUBLISHER_PRIVATE_H_
+#define PUBSUB_PUBLISHER_PRIVATE_H_
+
+#include <celixbool.h>
+#include <pthread.h>
+#include "publisher.h"
+
+struct pubsub_sender {
+	array_list_pt trackers;
+	const char *ident;
+	hash_map_pt tid_map; //service -> tid
+	long bundleId;
+};
+
+typedef struct pubsub_sender * pubsub_sender_pt;
+
+typedef struct send_thread_struct{
+	pubsub_publisher_pt service;
+	pubsub_sender_pt publisher;
+	const char *topic;
+} *send_thread_struct_pt;
+
+pubsub_sender_pt publisher_create(array_list_pt trackers, const char* ident,long bundleId);
+
+void publisher_start(pubsub_sender_pt client);
+void publisher_stop(pubsub_sender_pt client);
+
+void publisher_destroy(pubsub_sender_pt client);
+
+celix_status_t publisher_publishSvcAdded(void * handle, service_reference_pt reference, void * service);
+celix_status_t publisher_publishSvcRemoved(void * handle, service_reference_pt reference, void * service);
+
+
+#endif /* PUBSUB_PUBLISHER_PRIVATE_H_ */

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/examples/pubsub/publisher/private/src/ps_pub_activator.c
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/examples/pubsub/publisher/private/src/ps_pub_activator.c b/celix-pubsub/pubsub/examples/pubsub/publisher/private/src/ps_pub_activator.c
new file mode 100644
index 0000000..e4a8ba8
--- /dev/null
+++ b/celix-pubsub/pubsub/examples/pubsub/publisher/private/src/ps_pub_activator.c
@@ -0,0 +1,157 @@
+/**
+ *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.
+ */
+/*
+ * ps_pub_activator.c
+ *
+ *  \date       Sep 21, 2010
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#include <sys/cdefs.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bundle_activator.h"
+#include "service_tracker.h"
+#include "constants.h"
+
+#include "pubsub_common.h"
+#include "pubsub_utils.h"
+#include "publisher.h"
+#include "pubsub_publisher_private.h"
+
+#define PUB_TOPIC "poi1;poi2"
+
+struct publisherActivator {
+	pubsub_sender_pt client;
+	array_list_pt trackerList;//List<service_tracker_pt>
+};
+
+celix_status_t bundleActivator_create(bundle_context_pt context, void **userData) {
+	struct publisherActivator * act = malloc(sizeof(*act));
+
+	const char* fwUUID = NULL;
+
+	bundleContext_getProperty(context,OSGI_FRAMEWORK_FRAMEWORK_UUID,&fwUUID);
+	if(fwUUID==NULL){
+		printf("PUBLISHER: Cannot retrieve fwUUID.\n");
+		return CELIX_INVALID_BUNDLE_CONTEXT;
+	}
+
+	bundle_pt bundle = NULL;
+	long bundleId = 0;
+	bundleContext_getBundle(context,&bundle);
+	bundle_getBundleId(bundle,&bundleId);
+
+	arrayList_create(&(act->trackerList));
+	act->client = publisher_create(act->trackerList,fwUUID,bundleId);
+	*userData = act;
+
+	return CELIX_SUCCESS;
+}
+
+celix_status_t bundleActivator_start(void * userData, bundle_context_pt context) {
+
+	struct publisherActivator * act = (struct publisherActivator *) userData;
+
+	int i;
+	array_list_pt topic_list = pubsub_getTopicsFromString(PUB_TOPIC);
+
+	if(topic_list !=NULL){
+
+		char filter[128];
+		for(i=0; i<arrayList_size(topic_list);i++){
+			char* topic = arrayList_get(topic_list,i);
+			if(strlen(topic)<MAX_TOPIC_LEN){
+
+				bundle_pt bundle = NULL;
+				long bundleId = 0;
+				bundleContext_getBundle(context,&bundle);
+				bundle_getBundleId(bundle,&bundleId);
+
+				service_tracker_pt tracker = NULL;
+				memset(filter,0,128);
+#ifdef USE_SCOPE
+				char *scope;
+				asprintf(&scope, "my_scope_%d", i);
+				snprintf(filter, 128, "(&(&(%s=%s)(%s=%s))(%s=%s))",
+						(char*) OSGI_FRAMEWORK_OBJECTCLASS, PUBSUB_PUBLISHER_SERVICE_NAME,
+						PUBSUB_PUBLISHER_TOPIC, topic,
+						PUBLISHER_SCOPE, scope);
+				free(scope);
+#else
+				snprintf(filter, 128, "(&(%s=%s)(%s=%s))",
+				          (char*) OSGI_FRAMEWORK_OBJECTCLASS, PUBSUB_PUBLISHER_SERVICE_NAME,
+				                  PUBSUB_PUBLISHER_TOPIC, topic);
+#endif
+				service_tracker_customizer_pt customizer = NULL;
+				serviceTrackerCustomizer_create(act->client,NULL,publisher_publishSvcAdded,NULL,publisher_publishSvcRemoved,&customizer);
+				serviceTracker_createWithFilter(context, filter, customizer, &tracker);
+
+				arrayList_add(act->trackerList,tracker);
+			}
+			else{
+				printf("Topic %s too long. Skipping publication.\n",topic);
+			}
+			free(topic);
+		}
+		arrayList_destroy(topic_list);
+
+	}
+
+	publisher_start(act->client);
+
+	for(i=0;i<arrayList_size(act->trackerList);i++){
+		service_tracker_pt tracker = arrayList_get(act->trackerList,i);
+		serviceTracker_open(tracker);
+	}
+
+	return CELIX_SUCCESS;
+}
+
+celix_status_t bundleActivator_stop(void * userData, bundle_context_pt __attribute__((unused)) context) {
+	struct publisherActivator * act = (struct publisherActivator *) userData;
+	int i;
+
+	for(i=0;i<arrayList_size(act->trackerList);i++){
+		service_tracker_pt tracker = arrayList_get(act->trackerList,i);
+		serviceTracker_close(tracker);
+	}
+	publisher_stop(act->client);
+
+	return CELIX_SUCCESS;
+}
+
+celix_status_t bundleActivator_destroy(void * userData, bundle_context_pt  __attribute__((unused)) context) {
+	struct publisherActivator * act = (struct publisherActivator *) userData;
+	int i;
+
+	for(i=0;i<arrayList_size(act->trackerList);i++){
+		service_tracker_pt tracker = arrayList_get(act->trackerList,i);
+		serviceTracker_destroy(tracker);
+	}
+
+	publisher_destroy(act->client);
+	arrayList_destroy(act->trackerList);
+
+	free(act);
+	printf("PUBLISHER: bundleActivator_destroy\n");
+	return CELIX_SUCCESS;
+}


[5/6] celix git commit: CELIX-389: Adds Celix Publish Subscribe donation.

Posted by pn...@apache.org.
http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/examples/pubsub/publisher/private/src/pubsub_publisher.c
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/examples/pubsub/publisher/private/src/pubsub_publisher.c b/celix-pubsub/pubsub/examples/pubsub/publisher/private/src/pubsub_publisher.c
new file mode 100644
index 0000000..94331d9
--- /dev/null
+++ b/celix-pubsub/pubsub/examples/pubsub/publisher/private/src/pubsub_publisher.c
@@ -0,0 +1,164 @@
+/**
+ *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.
+ */
+/*
+ * pubsub_publisher.c
+ *
+ *  \date       Sep 21, 2010
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <unistd.h>
+
+#include "service_tracker.h"
+#include "celix_threads.h"
+
+#include "pubsub_common.h"
+#include "poi.h"
+
+#include "pubsub_publisher_private.h"
+
+static bool stop=false;
+
+static double randCoordinate(double min, double max){
+
+	double ret = min + (((double)rand()) / (((double)RAND_MAX)/(max-min))) ;
+
+	return ret;
+
+}
+
+static void* send_thread(void* arg){
+
+	send_thread_struct_pt st_struct = (send_thread_struct_pt)arg;
+
+	pubsub_publisher_pt publish_svc = (pubsub_publisher_pt)st_struct->service;
+	pubsub_sender_pt publisher = (pubsub_sender_pt)st_struct->publisher;
+
+	char fwUUID[9];
+	memset(fwUUID,0,9);
+	memcpy(fwUUID,publisher->ident,8);
+
+	//poi_t point = calloc(1,sizeof(*point));
+	location_t place = calloc(1,sizeof(*place));
+
+	char* desc = calloc(64,sizeof(char));
+	snprintf(desc,64,"fw-%s [TID=%lu]", fwUUID, (unsigned long)pthread_self());
+
+	char* name = calloc(64,sizeof(char));
+	snprintf(name,64,"Bundle#%ld",publisher->bundleId);
+
+	place->name = name;
+	place->description = desc;
+	place->extra = "DONT PANIC";
+	printf("TOPIC : %s\n",st_struct->topic);
+	unsigned int msgId = 0;
+	if( publish_svc->localMsgTypeIdForMsgType(publish_svc->handle,st_struct->topic,&msgId) == 0 ){
+
+		while(stop==false){
+			place->position.lat = randCoordinate(MIN_LAT,MAX_LAT);
+			place->position.lon = randCoordinate(MIN_LON,MAX_LON);
+			int nr_char = (int)randCoordinate(5,100000);
+			//int nr_char = 25;
+			place->data = calloc(nr_char, 1);
+			for(int i = 0; i < (nr_char-1); i++) {
+				place->data[i] = i%10 + '0';
+			}
+			if(publish_svc->send) {
+				publish_svc->send(publish_svc->handle,msgId,place);
+			} else {
+				printf("No send for %s\n", st_struct->topic);
+			}
+			printf("Sent %s [%f, %f] (%s, %s) data len = %d\n",st_struct->topic, place->position.lat, place->position.lon,place->name,place->description, nr_char);
+			free(place->data);
+			sleep(2);
+		}
+	}
+	else{
+		printf("PUBLISHER: Cannot retrieve msgId for message '%s'\n",MSG_POI_NAME);
+	}
+
+	free(place->description);
+	free(place->name);
+	free(place);
+
+	free(st_struct);
+
+
+	return NULL;
+
+}
+
+pubsub_sender_pt publisher_create(array_list_pt trackers,const char* ident,long bundleId) {
+	pubsub_sender_pt publisher = malloc(sizeof(*publisher));
+
+	publisher->trackers = trackers;
+	publisher->ident = ident;
+	publisher->bundleId = bundleId;
+	publisher->tid_map = hashMap_create(NULL, NULL, NULL, NULL);
+
+	return publisher;
+}
+
+void publisher_start(pubsub_sender_pt client) {
+	printf("PUBLISHER: starting up...\n");
+}
+
+void publisher_stop(pubsub_sender_pt client) {
+	printf("PUBLISHER: stopping...\n");
+}
+
+void publisher_destroy(pubsub_sender_pt client) {
+	hashMap_destroy(client->tid_map, false, false);
+	client->trackers = NULL;
+	client->ident = NULL;
+	free(client);
+}
+
+celix_status_t publisher_publishSvcAdded(void * handle, service_reference_pt reference, void * service){
+	pubsub_publisher_pt publish_svc = (pubsub_publisher_pt)service;
+	pubsub_sender_pt manager = (pubsub_sender_pt)handle;
+
+	printf("PUBLISHER: new publish service exported (%s).\n",manager->ident);
+
+	send_thread_struct_pt data = calloc(1,sizeof(struct send_thread_struct));
+	const char *value = NULL;
+	serviceReference_getProperty(reference, PUBSUB_PUBLISHER_TOPIC, &value);
+	data->service = publish_svc;
+	data->publisher = manager;
+	data->topic = value;
+	celix_thread_t *tid = malloc(sizeof(*tid));
+	stop=false;
+	celixThread_create(tid,NULL,send_thread,(void*)data);
+	hashMap_put(manager->tid_map, publish_svc, tid);
+	return CELIX_SUCCESS;
+}
+
+celix_status_t publisher_publishSvcRemoved(void * handle, service_reference_pt reference, void * service){
+	pubsub_sender_pt manager = (pubsub_sender_pt)handle;
+	celix_thread_t *tid = hashMap_get(manager->tid_map, service);
+	printf("PUBLISHER: publish service unexporting (%s) %li!\n",manager->ident, tid->thread);
+	stop=true;
+	celixThread_join(*tid,NULL);
+	free(tid);
+	return CELIX_SUCCESS;
+}

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/examples/pubsub/publisher2/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/examples/pubsub/publisher2/CMakeLists.txt b/celix-pubsub/pubsub/examples/pubsub/publisher2/CMakeLists.txt
new file mode 100644
index 0000000..270a881
--- /dev/null
+++ b/celix-pubsub/pubsub/examples/pubsub/publisher2/CMakeLists.txt
@@ -0,0 +1,54 @@
+# 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_directories("../publisher/private/include")
+include_directories("${PROJECT_SOURCE_DIR}/framework/public/include")
+include_directories("${PROJECT_SOURCE_DIR}/pubsub/pubsub_common/public/include")
+include_directories("${PROJECT_SOURCE_DIR}/pubsub/api/pubsub")
+
+add_bundle(org.apache.celix.pubsub_publisher.PoiPublisher2
+    SYMBOLIC_NAME "apache_celix_pubsub_poi_publisher2"
+    VERSION "1.0.0"
+    SOURCES 
+    	../publisher/private/src/ps_pub_activator.c
+    	../publisher/private/src/pubsub_publisher.c
+    	${PROJECT_SOURCE_DIR}/pubsub/pubsub_common/public/src/pubsub_utils.c
+)
+
+bundle_files(org.apache.celix.pubsub_publisher.PoiPublisher2
+	${PROJECT_SOURCE_DIR}/pubsub/examples/pubsub/msg_descriptors/msg_poi1.descriptor
+	${PROJECT_SOURCE_DIR}/pubsub/examples/pubsub/msg_descriptors/msg_poi2.descriptor
+    DESTINATION "META-INF/descriptors"
+)
+
+bundle_files(org.apache.celix.pubsub_publisher.PoiPublisher2
+		${PROJECT_SOURCE_DIR}/pubsub/examples/pubsub/msg_descriptors/poi1.properties
+		${PROJECT_SOURCE_DIR}/pubsub/examples/pubsub/msg_descriptors/poi2.properties
+    DESTINATION "META-INF/topics/pub"
+)
+
+bundle_files(org.apache.celix.pubsub_publisher.PoiPublisher2
+		${PROJECT_SOURCE_DIR}/pubsub/examples/keys/publisher
+    DESTINATION "META-INF/keys"
+)
+
+bundle_files(org.apache.celix.pubsub_publisher.PoiPublisher2
+		${PROJECT_SOURCE_DIR}/pubsub/examples/keys/subscriber/public
+    DESTINATION "META-INF/keys/subscriber"
+)
+
+

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/examples/pubsub/subscriber/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/examples/pubsub/subscriber/CMakeLists.txt b/celix-pubsub/pubsub/examples/pubsub/subscriber/CMakeLists.txt
new file mode 100644
index 0000000..047dbb7
--- /dev/null
+++ b/celix-pubsub/pubsub/examples/pubsub/subscriber/CMakeLists.txt
@@ -0,0 +1,53 @@
+# 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_directories("private/include")
+include_directories("${PROJECT_SOURCE_DIR}/framework/public/include")
+include_directories("${PROJECT_SOURCE_DIR}/pubsub/pubsub_common/public/include")
+include_directories("${PROJECT_SOURCE_DIR}/pubsub/api/pubsub")
+include_directories("${PROJECT_SOURCE_DIR}/pubsub/examples/pubsub/common/include")
+
+add_bundle(org.apache.celix.pubsub_subscriber.PoiSubscriber
+    SYMBOLIC_NAME "apache_celix_pubsub_poi_subscriber" 
+    VERSION "1.0.0"
+    SOURCES 
+    	private/src/ps_sub_activator.c
+    	private/src/pubsub_subscriber.c
+    	${PROJECT_SOURCE_DIR}/pubsub/pubsub_common/public/src/pubsub_utils.c
+)
+
+bundle_files(org.apache.celix.pubsub_subscriber.PoiSubscriber
+	    ${PROJECT_SOURCE_DIR}/pubsub/examples/pubsub/msg_descriptors/msg_poi1.descriptor
+	    ${PROJECT_SOURCE_DIR}/pubsub/examples/pubsub/msg_descriptors/msg_poi2.descriptor
+    DESTINATION "META-INF/descriptors"
+)
+
+bundle_files(org.apache.celix.pubsub_subscriber.PoiSubscriber
+		${PROJECT_SOURCE_DIR}/pubsub/examples/pubsub/msg_descriptors/poi1.properties
+		${PROJECT_SOURCE_DIR}/pubsub/examples/pubsub/msg_descriptors/poi2.properties
+    DESTINATION "META-INF/topics/sub"
+)
+
+bundle_files(org.apache.celix.pubsub_subscriber.PoiSubscriber
+		${PROJECT_SOURCE_DIR}/pubsub/examples/keys/subscriber
+    DESTINATION "META-INF/keys"
+)
+
+bundle_files(org.apache.celix.pubsub_subscriber.PoiSubscriber
+		${PROJECT_SOURCE_DIR}/pubsub/examples/keys/publisher/public
+    DESTINATION "META-INF/keys/publisher"
+)

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/examples/pubsub/subscriber/private/include/pubsub_subscriber_private.h
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/examples/pubsub/subscriber/private/include/pubsub_subscriber_private.h b/celix-pubsub/pubsub/examples/pubsub/subscriber/private/include/pubsub_subscriber_private.h
new file mode 100644
index 0000000..c6072df
--- /dev/null
+++ b/celix-pubsub/pubsub/examples/pubsub/subscriber/private/include/pubsub_subscriber_private.h
@@ -0,0 +1,52 @@
+/**
+ *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.
+ */
+/*
+ * pubsub_subscriber_private.h
+ *
+ *  \date       Sep 21, 2010
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#ifndef PUBSUB_SUBSCRIBER_PRIVATE_H_
+#define PUBSUB_SUBSCRIBER_PRIVATE_H_
+
+
+#include <string.h>
+
+#include "celixbool.h"
+
+#include "pubsub_common.h"
+#include "subscriber.h"
+
+struct pubsub_receiver {
+	char * name;
+};
+
+typedef struct pubsub_receiver* pubsub_receiver_pt;
+
+pubsub_receiver_pt subscriber_create(char* topics);
+void subscriber_start(pubsub_receiver_pt client);
+void subscriber_stop(pubsub_receiver_pt client);
+void subscriber_destroy(pubsub_receiver_pt client);
+
+int pubsub_subscriber_recv(void* handle, const char* msgType, unsigned int msgTypeId, void* msg,pubsub_multipart_callbacks_t *callbacks, bool* release);
+
+
+#endif /* PUBSUB_SUBSCRIBER_PRIVATE_H_ */

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/examples/pubsub/subscriber/private/src/ps_sub_activator.c
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/examples/pubsub/subscriber/private/src/ps_sub_activator.c b/celix-pubsub/pubsub/examples/pubsub/subscriber/private/src/ps_sub_activator.c
new file mode 100644
index 0000000..efd34c9
--- /dev/null
+++ b/celix-pubsub/pubsub/examples/pubsub/subscriber/private/src/ps_sub_activator.c
@@ -0,0 +1,123 @@
+/**
+ *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.
+ */
+/*
+ * ps_sub_activator.c
+ *
+ *  \date       Sep 21, 2010
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#include <stdlib.h>
+
+#include "bundle_activator.h"
+
+#include "pubsub_common.h"
+#include "pubsub_utils.h"
+#include "pubsub_subscriber_private.h"
+
+#define SUB_TOPIC "poi1;poi2"
+
+struct subscriberActivator {
+	array_list_pt registrationList; //List<service_registration_pt>
+	pubsub_subscriber_pt subsvc;
+};
+
+celix_status_t bundleActivator_create(bundle_context_pt context, void **userData) {
+	struct subscriberActivator * act = calloc(1,sizeof(struct subscriberActivator));
+	*userData = act;
+	arrayList_create(&(act->registrationList));
+	return CELIX_SUCCESS;
+}
+
+celix_status_t bundleActivator_start(void * userData, bundle_context_pt context) {
+	struct subscriberActivator * act = (struct subscriberActivator *) userData;
+
+
+	pubsub_subscriber_pt subsvc = calloc(1,sizeof(*subsvc));
+	pubsub_receiver_pt sub = subscriber_create(SUB_TOPIC);
+	subsvc->handle = sub;
+	subsvc->receive = pubsub_subscriber_recv;
+
+	act->subsvc = subsvc;
+
+	array_list_pt topic_list = pubsub_getTopicsFromString(SUB_TOPIC);
+
+	if(topic_list !=NULL){
+
+		int i;
+		for(i=0; i<arrayList_size(topic_list);i++){
+			char* topic = arrayList_get(topic_list,i);
+			if(strlen(topic)<MAX_TOPIC_LEN){
+				properties_pt props = properties_create();
+				properties_set(props, PUBSUB_SUBSCRIBER_TOPIC,topic);
+#ifdef USE_SCOPE
+				char *scope;
+				asprintf(&scope, "my_scope_%d", i);
+				properties_set(props,SUBSCRIBER_SCOPE,scope);
+				free(scope);
+#endif
+				service_registration_pt reg = NULL;
+				bundleContext_registerService(context, PUBSUB_SUBSCRIBER_SERVICE_NAME, subsvc, props, &reg);
+				arrayList_add(act->registrationList,reg);
+			}
+			else{
+				printf("Topic %s too long. Skipping subscription.\n",topic);
+			}
+			free(topic);
+		}
+		arrayList_destroy(topic_list);
+
+	}
+
+	subscriber_start((pubsub_receiver_pt)act->subsvc->handle);
+
+	return CELIX_SUCCESS;
+}
+
+celix_status_t bundleActivator_stop(void * userData, bundle_context_pt context) {
+	struct subscriberActivator * act = (struct subscriberActivator *) userData;
+
+	int i;
+	for(i=0; i<arrayList_size(act->registrationList);i++){
+		service_registration_pt reg = arrayList_get(act->registrationList,i);
+		serviceRegistration_unregister(reg);
+
+	}
+
+	subscriber_stop((pubsub_receiver_pt)act->subsvc->handle);
+
+	return CELIX_SUCCESS;
+}
+
+celix_status_t bundleActivator_destroy(void * userData, bundle_context_pt context) {
+
+	struct subscriberActivator * act = (struct subscriberActivator *) userData;
+
+	act->subsvc->receive = NULL;
+	subscriber_destroy((pubsub_receiver_pt)act->subsvc->handle);
+	act->subsvc->handle = NULL;
+	free(act->subsvc);
+	act->subsvc = NULL;
+
+	arrayList_destroy(act->registrationList);
+	free(act);
+
+	return CELIX_SUCCESS;
+}

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/examples/pubsub/subscriber/private/src/pubsub_subscriber.c
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/examples/pubsub/subscriber/private/src/pubsub_subscriber.c b/celix-pubsub/pubsub/examples/pubsub/subscriber/private/src/pubsub_subscriber.c
new file mode 100644
index 0000000..a137253
--- /dev/null
+++ b/celix-pubsub/pubsub/examples/pubsub/subscriber/private/src/pubsub_subscriber.c
@@ -0,0 +1,64 @@
+/**
+ *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.
+ */
+/*
+ * pubsub_subscriber.c
+ *
+ *  \date       Sep 21, 2010
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "poi.h"
+#include "pubsub_subscriber_private.h"
+
+pubsub_receiver_pt subscriber_create(char* topics) {
+	pubsub_receiver_pt sub = calloc(1,sizeof(*sub));
+	sub->name = strdup(topics);
+	return sub;
+}
+
+
+void subscriber_start(pubsub_receiver_pt subscriber){
+	printf("Subscriber started...\n");
+}
+
+void subscriber_stop(pubsub_receiver_pt subscriber){
+	printf("Subscriber stopped...\n");
+}
+
+void subscriber_destroy(pubsub_receiver_pt subscriber){
+	if(subscriber->name!=NULL){
+		free(subscriber->name);
+	}
+	subscriber->name=NULL;
+	free(subscriber);
+}
+
+int pubsub_subscriber_recv(void* handle, const char* msgType, unsigned int msgTypeId, void* msg,pubsub_multipart_callbacks_t *callbacks, bool* release){
+
+	location_t place = (location_t)msg;
+	int nrchars = 25;
+	printf("Recv (%s): [%f, %f] (%s, %s) data_len = %ld data =%*.*s\n",msgType, place->position.lat, place->position.lon,place->name,place->description, strlen(place->data) + 1, nrchars, nrchars, place->data);
+
+	return 0;
+
+}

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/keygen/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/keygen/CMakeLists.txt b/celix-pubsub/pubsub/keygen/CMakeLists.txt
new file mode 100644
index 0000000..4cb4f5a
--- /dev/null
+++ b/celix-pubsub/pubsub/keygen/CMakeLists.txt
@@ -0,0 +1,34 @@
+# 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.
+
+if (ENABLE_ZMQ_SECURITY)
+
+	find_package(ZMQ REQUIRED)
+	find_package(CZMQ REQUIRED)
+	find_package(OpenSSL 1.1.0 REQUIRED)
+	
+	include_directories("${ZMQ_INCLUDE_DIR}")
+	include_directories("${CZMQ_INCLUDE_DIR}")
+	include_directories("${OPENSSL_INCLUDE_DIR}")
+	
+	add_executable(makecert makecert.c)
+	target_link_libraries(makecert ${CZMQ_LIBRARIES})
+	
+	add_executable(ed_file ed_file.c)
+	target_link_libraries(ed_file ${ZMQ_LIBRARIES} ${CZMQ_LIBRARIES} ${OPENSSL_CRYPTO_LIBRARY})
+
+endif()

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/keygen/ed_file.c
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/keygen/ed_file.c b/celix-pubsub/pubsub/keygen/ed_file.c
new file mode 100644
index 0000000..a0fc7e2
--- /dev/null
+++ b/celix-pubsub/pubsub/keygen/ed_file.c
@@ -0,0 +1,309 @@
+/**
+ *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.
+ */
+/*
+ * ed_file.c
+ *
+ *  \date       Dec 2, 2016
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#include <czmq.h>
+#include <openssl/evp.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <strings.h>
+
+#define MAX_KEY_FILE_LENGTH 256
+#define MAX_LINE_LENGTH 64
+#define AES_KEY_LENGTH 32
+#define AES_IV_LENGTH 16
+
+#define KEY_TO_GET "aes_key"
+#define IV_TO_GET "aes_iv"
+
+int generate_sha256_hash(char* text, unsigned char* digest);
+int encrypt_aes(unsigned char *plaintext, int plaintext_len, unsigned char *key, unsigned char *iv, unsigned char *ciphertext);
+int decrypt_aes(unsigned char *ciphertext, int ciphertext_len, unsigned char *key, unsigned char *iv, unsigned char *plaintext);
+
+static char* read_keys_file_content(const char *filePath);
+static void parse_key_lines(char *keysBuffer, char **key, char **iv);
+static void parse_key_line(char *line, char **key, char **iv);
+
+int main(int argc, const char* argv[])
+{
+	if (argc < 4){
+		printf("Usage: %s <key_file> <input_file> <output_file> [options]\n", argv[0]);
+		printf("Default behavior: encrypting a file\n");
+		printf("Options:\n");
+		printf("\t-d\tSpecify to decrypt a file\n");
+		printf("\n");
+		return EXIT_FAILURE;
+	}
+
+	int rc = 0;
+
+	const char* keys_file_path = argv[1];
+	const char* input_file_path = argv[2];
+	const char* output_file_path = argv[3];
+
+	bool decryptParam = false;
+	if (argc > 4 && strcmp(argv[4], "-d") == 0){
+		decryptParam = true;
+	}
+
+	if (!zsys_file_exists(keys_file_path)){
+		printf("Keys file '%s' doesn't exist!\n", keys_file_path);
+		return EXIT_FAILURE;
+	}
+
+	if (!zsys_file_exists(input_file_path)){
+		printf("Input file does not exist!\n");
+		return EXIT_FAILURE;
+	}
+
+	char* keys_data = read_keys_file_content(keys_file_path);
+	if (keys_data == NULL){
+		return EXIT_FAILURE;
+	}
+
+	char* key = NULL;
+	char* iv = NULL;
+	parse_key_lines(keys_data, &key, &iv);
+	free(keys_data);
+
+	if (key == NULL || iv == NULL){
+		printf("Loading AES key and/or AES iv failed!\n");
+		free(key);
+		free(iv);
+		return EXIT_FAILURE;
+	}
+
+	printf("Using AES Key \t\t'%s'\n", key);
+	printf("Using AES IV \t\t'%s'\n", iv);
+	printf("Input file path \t'%s'\n", input_file_path);
+	printf("Output file path \t'%s'\n", output_file_path);
+	printf("Decrypting \t\t'%s'\n\n", (decryptParam) ? "true" : "false");
+
+	unsigned char key_digest[EVP_MAX_MD_SIZE];
+	unsigned char iv_digest[EVP_MAX_MD_SIZE];
+	generate_sha256_hash((char*) key, key_digest);
+	generate_sha256_hash((char*) iv, iv_digest);
+
+	zchunk_t* input_chunk = zchunk_slurp (input_file_path, 0);
+	if (input_chunk == NULL){
+		printf("Input file not correct!\n");
+		free(key);
+		free(iv);
+		return EXIT_FAILURE;
+	}
+
+	//Load input data from file
+	int input_file_size = (int) zchunk_size (input_chunk);
+	char* input_file_data = zchunk_strdup(input_chunk);
+	zchunk_destroy (&input_chunk);
+
+	int output_len;
+	unsigned char output[input_file_size];
+	if (decryptParam){
+		output_len = decrypt_aes((unsigned char*) input_file_data, input_file_size, key_digest, iv_digest, output);
+		output[output_len] = '\0';
+	}else{
+		output_len = encrypt_aes((unsigned char*) input_file_data, input_file_size, key_digest, iv_digest, output);
+	}
+
+	//Write output data to file
+	zfile_t* output_file = zfile_new (".", output_file_path);
+	zchunk_t* output_chunk = zchunk_new(output, output_len);
+	rc = zfile_output (output_file);
+	if (rc != 0){
+		printf("Problem with opening file for writing!\n");
+		zchunk_destroy (&output_chunk);
+		zfile_close (output_file);
+		zfile_destroy (&output_file);
+		free(input_file_data);
+		free(key);
+		free(iv);
+
+		return EXIT_FAILURE;
+	}
+
+	rc = zfile_write (output_file, output_chunk, 0);
+	if (rc != 0){
+		printf("Problem with writing output to file!\n");
+	}
+	printf("Output written to file:\n");
+	if (decryptParam){
+		printf("%s\n", output);
+	}else{
+		BIO_dump_fp (stdout, (const char *) output, output_len);
+	}
+
+	zchunk_destroy (&output_chunk);
+	zfile_close (output_file);
+	zfile_destroy (&output_file);
+	free(input_file_data);
+	free(key);
+	free(iv);
+
+	return EXIT_SUCCESS;
+}
+
+int generate_sha256_hash(char* text, unsigned char* digest)
+{
+	unsigned int digest_len;
+
+	EVP_MD_CTX * mdctx = EVP_MD_CTX_new();
+	EVP_DigestInit_ex(mdctx, EVP_sha256(), NULL);
+	EVP_DigestUpdate(mdctx, text, strlen(text));
+	EVP_DigestFinal_ex(mdctx, digest, &digest_len);
+	EVP_MD_CTX_free(mdctx);
+
+	return digest_len;
+}
+
+int encrypt_aes(unsigned char *plaintext, int plaintext_len, unsigned char *key, unsigned char *iv, unsigned char *ciphertext)
+{
+	int len;
+	int ciphertext_len;
+
+	EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
+
+	EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv);
+	EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len);
+	ciphertext_len = len;
+	EVP_EncryptFinal_ex(ctx, ciphertext + len, &len);
+	ciphertext_len += len;
+
+	EVP_CIPHER_CTX_free(ctx);
+
+	return ciphertext_len;
+}
+
+int decrypt_aes(unsigned char *ciphertext, int ciphertext_len, unsigned char *key, unsigned char *iv, unsigned char *plaintext)
+{
+	int len;
+	int plaintext_len;
+
+	EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
+
+	EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv);
+	EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len);
+	plaintext_len = len;
+	EVP_DecryptFinal_ex(ctx, plaintext + len, &len);
+	plaintext_len += len;
+
+	EVP_CIPHER_CTX_free(ctx);
+
+	return plaintext_len;
+}
+
+static char* read_keys_file_content(const char *keys_file_path){
+	char* keys_file_full_path = strndup(keys_file_path, MAX_KEY_FILE_LENGTH);
+	char* keys_file_name = NULL;
+
+	char* sep_kf_at = strrchr(keys_file_path, '/');
+	if (sep_kf_at != NULL){
+		*sep_kf_at = '\0';
+		keys_file_name = sep_kf_at + 1;
+	}else{
+		keys_file_name = (char*) keys_file_path;
+		keys_file_path = (const char*) ".";
+	}
+
+	printf("Keys file path: %s\n", keys_file_full_path);
+
+	int rc = 0;
+
+	zfile_t* keys_file = zfile_new (keys_file_path, keys_file_name);
+	rc = zfile_input (keys_file);
+	if (rc != 0){
+		printf("Keys file '%s' not readable!\n", keys_file_full_path);
+		zfile_destroy(&keys_file);
+		free(keys_file_full_path);
+		return NULL;
+	}
+
+	ssize_t keys_file_size = zsys_file_size (keys_file_full_path);
+	zchunk_t* keys_chunk = zfile_read (keys_file, keys_file_size, 0);
+	if (keys_chunk == NULL){
+		printf("Can't read file '%s'!\n", keys_file_full_path);
+		zfile_close(keys_file);
+		zfile_destroy(&keys_file);
+		free(keys_file_full_path);
+		return NULL;
+	}
+
+	char* keys_data = zchunk_strdup(keys_chunk);
+	zchunk_destroy(&keys_chunk);
+	zfile_close(keys_file);
+	zfile_destroy (&keys_file);
+
+	return keys_data;
+}
+
+static void parse_key_lines(char *keysBuffer, char **key, char **iv){
+	char *line = NULL, *saveLinePointer = NULL;
+
+	bool firstTime = true;
+	do {
+		if (firstTime){
+			line = strtok_r(keysBuffer, "\n", &saveLinePointer);
+			firstTime = false;
+		}else {
+			line = strtok_r(NULL, "\n", &saveLinePointer);
+		}
+
+		if (line == NULL){
+			break;
+		}
+
+		parse_key_line(line, key, iv);
+
+	} while((*key == NULL || *iv == NULL) && line != NULL);
+
+}
+
+static void parse_key_line(char *line, char **key, char **iv){
+	char *detectedKey = NULL, *detectedValue= NULL;
+
+	char* sep_at = strchr(line, ':');
+	if (sep_at == NULL){
+		return;
+	}
+
+	*sep_at = '\0'; // overwrite first separator, creating two strings.
+	detectedKey = line;
+	detectedValue = sep_at + 1;
+
+	if (detectedKey == NULL || detectedValue == NULL){
+		return;
+	}
+	if (detectedKey[0] == '\0' || detectedValue[0] == '\0'){
+		return;
+	}
+
+	if (*key == NULL && strcmp(detectedKey, KEY_TO_GET) == 0){
+		*key = strndup(detectedValue, AES_KEY_LENGTH);
+	} else if (*iv == NULL && strcmp(detectedKey, IV_TO_GET) == 0){
+		*iv = strndup(detectedValue, AES_IV_LENGTH);
+	}
+}
+

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/keygen/makecert.c
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/keygen/makecert.c b/celix-pubsub/pubsub/keygen/makecert.c
new file mode 100644
index 0000000..166111e
--- /dev/null
+++ b/celix-pubsub/pubsub/keygen/makecert.c
@@ -0,0 +1,55 @@
+/**
+ *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.
+ */
+/*
+ * makecert.c
+ *
+ *  \date       Dec 2, 2016
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#include <string.h>
+
+#include "czmq.h"
+
+int main (int argc, const char * argv[])
+{
+
+	const char * cert_name_public = "certificate.pub";
+	const char * cert_name_secret = "certificate.key";
+	if (argc == 3 && strcmp(argv[1], argv[2]) != 0){
+		cert_name_public = argv[1];
+		cert_name_secret = argv[2];
+	}
+
+	zcert_t * cert = zcert_new();
+
+	char *timestr = zclock_timestr ();
+	zcert_set_meta (cert, "date-created", timestr);
+	free (timestr);
+
+	zcert_save_public(cert, cert_name_public);
+	zcert_save_secret(cert, cert_name_secret);
+	zcert_print (cert);
+	printf("\n");
+	printf("I: CURVE certificate created in %s and %s\n", cert_name_public, cert_name_secret);
+	zcert_destroy (&cert);
+
+	return 0;
+}

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_admin_udp_mc/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_admin_udp_mc/CMakeLists.txt b/celix-pubsub/pubsub/pubsub_admin_udp_mc/CMakeLists.txt
new file mode 100644
index 0000000..7c8f620
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_admin_udp_mc/CMakeLists.txt
@@ -0,0 +1,57 @@
+# 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.
+
+find_package(Jansson REQUIRED)
+
+include_directories("${PROJECT_SOURCE_DIR}/utils/public/include")
+include_directories("${PROJECT_SOURCE_DIR}/log_service/public/include")
+include_directories("${PROJECT_SOURCE_DIR}/dfi/public/include")
+include_directories("${PROJECT_SOURCE_DIR}/pubsub/pubsub_common/public/include")
+include_directories("${PROJECT_SOURCE_DIR}/pubsub/api/pubsub")
+include_directories("private/include")
+include_directories("public/include")
+include_directories("${JANSSON_INCLUDE_DIR}")
+if (SERIALIZER_PATH)
+	include_directories("${SERIALIZER_PATH}/include")
+endif()
+if (SERIALIZER_LIB_INCLUDE_DIR)
+	include_directories("${SERIALIZER_LIB_INCLUDE_DIR}")
+endif()
+if (SERIALIZER_LIB_DIR)
+	link_directories("${SERIALIZER_LIB_DIR}")
+endif()
+
+add_bundle(org.apache.celix.pubsub_admin.PubSubAdminUdpMc
+    BUNDLE_SYMBOLICNAME "apache_celix_pubsub_admin_udp_multicast"
+    VERSION "1.0.0"
+    SOURCES
+    	private/src/psa_activator.c
+    	private/src/pubsub_admin_impl.c
+    	private/src/topic_subscription.c
+    	private/src/topic_publication.c
+    	private/src/large_udp.c
+    	${PROJECT_SOURCE_DIR}/pubsub/pubsub_common/public/src/dyn_msg_utils.c
+    	${PROJECT_SOURCE_DIR}/pubsub/pubsub_common/public/src/pubsub_endpoint.c
+    	${PROJECT_SOURCE_DIR}/pubsub/pubsub_common/public/src/log_helper.c
+    	${PUBSUB_SERIALIZER_SRC}
+)
+
+set_target_properties(org.apache.celix.pubsub_admin.PubSubAdminUdpMc PROPERTIES INSTALL_RPATH "$ORIGIN")
+target_link_libraries(org.apache.celix.pubsub_admin.PubSubAdminUdpMc ${CELIX_LIBRARIES} ${JANSSON_LIBRARIES} ${SERIALIZER_LIBRARY})
+
+install_bundle(org.apache.celix.pubsub_admin.PubSubAdminUdpMc)
+

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_admin_udp_mc/README.md
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_admin_udp_mc/README.md b/celix-pubsub/pubsub/pubsub_admin_udp_mc/README.md
new file mode 100644
index 0000000..19c7b86
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_admin_udp_mc/README.md
@@ -0,0 +1,62 @@
+#PUBSUB-Admin UDP Multicast
+
+---
+
+##Description
+
+This description is particular for the UDP-Multicast PUB-SUB. 
+
+The UDP multicast pubsub admin is used to transfer user data transparent via UDP multicast. UDP packets can contain approximately  
+64kB . To overcome this limit the admin has a protocol on top of UDP which fragments the data to be send and these  
+fragments are reassembled at the reception side.
+
+### IP Addresses
+
+To use UDP-multicast 2 IP adresses are needed:
+
+1. IP address which is bound to an (ethernet) interface
+2. The multicast address (in the range 224.X.X.X - 239.X.X.X)
+
+When the PubSubAdmin starts it determines the bound IP address. This is done in the order:
+
+1. The first IP number bound to the interface which is set by the "PSA_INTERFACE" property
+2. The interfaces are iterated and the first IP number found is used. (typically this is 127.0.0.1 (localhost)
+
+The  Multicass IP address is determined in the order:
+
+1. If the `PSA_IP` property is defined, this IP will be used as multicast.
+2. If the `PSA_MC_PREFIX` property, is defined, this property is used as the first 2 numbers of the multicast address extended with the last 2 numbers of the bound IP.
+3. If the `PSA_MC_PREFIX` property is not defined `224.100` is used.
+
+### Discovery
+
+When a publisher request for a topic a TopicSender is created by a ServiceFactory. This TopicSender uses the multicast address as described above with a random chosen portnumber. The combination of the multicast-IP address with the portnumber and protocol(udp) is the endpoint.  
+This endpoint is published by the PubSubDiscovery within its topic in ETCD (i.e. udp://224.100.10.20:40123).
+ 
+A subscriber, interested in the topic, is informed by the the ToplogyManager that there is a new endpoint. The TopicReceiver at the subscriber side creates a listening socket based on this endpoint. 
+
+Now a data-connection is created and data send by the publisher will be received by the subscriber.  
+
+---
+
+##Properties
+
+<table border="1">
+    <tr><th>Property</th><th>Description</th></tr>
+    <tr><td>PSA_INTERFACE</td><td>Interface which has to be used for multicast communication</td></tr>
+    <tr><td>PSA_IP</td><td>Multicast IP address used by the bundle</td></tr>
+    <tr><td>PSA_MC_PREFIX</td><td>First 2 digits of the MC IP address </td></tr>
+</table>
+
+---
+
+##Shortcomings
+
+1. Per topic a random portnr is used for creating an endpoint. It is theoretical possible that for 2 topic the same endpoint is created.
+2. For every message a 32 bit random message ID is generated to discriminate segments of different messages which could be sent at the same time. It is theoretically possible that there are 2 equal message ID's at the same time. But since the mesage ID is valid only during the transmission of a message (maximum some milliseconds with large messages) this is not very plausible.
+3. When sending large messages, these messages are segmented and sent after each other. This could cause UDP-buffer overflows in the kernel. A solution could be to add a delay between sending of the segements but this will introduce extra latency.
+4. A Hash is created, using the message definition, to identify the message type. When 2 messages generate the same hash something will terribly go wrong. A check should be added to prevent this (or another way to identify the message type). This problem is also valid for the other admins.
+
+
+
+

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_admin_udp_mc/private/include/large_udp.h
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_admin_udp_mc/private/include/large_udp.h b/celix-pubsub/pubsub/pubsub_admin_udp_mc/private/include/large_udp.h
new file mode 100644
index 0000000..a21e654
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_admin_udp_mc/private/include/large_udp.h
@@ -0,0 +1,45 @@
+/**
+ *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.
+ */
+/*
+ * large_udp.h
+ *
+ *  \date       Mar 1, 2016
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#ifndef _LARGE_UDP_H_
+#define _LARGE_UDP_H_
+#include <stdbool.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+typedef struct largeUdp  *largeUdp_pt;
+
+largeUdp_pt largeUdp_create(unsigned int maxNrUdpReceptions);
+void largeUdp_destroy(largeUdp_pt handle);
+
+int largeUdp_sendto(largeUdp_pt handle, int fd, void *buf, size_t count, int flags, struct sockaddr_in *dest_addr, size_t addrlen);
+int largeUdp_sendmsg(largeUdp_pt handle, int fd, struct iovec *largeMsg_iovec, int len, int flags, struct sockaddr_in *dest_addr, size_t addrlen);
+bool largeUdp_dataAvailable(largeUdp_pt handle, int fd, unsigned int *index, unsigned int *size);
+int largeUdp_read(largeUdp_pt handle, unsigned int index, void ** buffer, unsigned int size);
+
+#endif /* _LARGE_UDP_H_ */

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_admin_udp_mc/private/include/pubsub_admin_impl.h
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_admin_udp_mc/private/include/pubsub_admin_impl.h b/celix-pubsub/pubsub/pubsub_admin_udp_mc/private/include/pubsub_admin_impl.h
new file mode 100644
index 0000000..19a56a8
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_admin_udp_mc/private/include/pubsub_admin_impl.h
@@ -0,0 +1,71 @@
+/**
+ *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.
+ */
+/*
+ * pubsub_admin_impl.h
+ *
+ *  \date       Dec 5, 2013
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#ifndef PUBSUB_ADMIN_IMPL_H_
+#define PUBSUB_ADMIN_IMPL_H_
+
+#include "pubsub_admin.h"
+#include "log_helper.h"
+
+struct pubsub_admin {
+
+	bundle_context_pt bundle_context;
+	log_helper_pt loghelper;
+
+	celix_thread_mutex_t localPublicationsLock;
+	hash_map_pt localPublications;//<topic(string),service_factory_pt>
+
+	celix_thread_mutex_t externalPublicationsLock;
+	hash_map_pt externalPublications;//<topic(string),List<pubsub_ep>>
+
+	celix_thread_mutex_t subscriptionsLock;
+	hash_map_pt subscriptions; //<topic(string),topic_subscription>
+
+	celix_thread_mutex_t pendingSubscriptionsLock;
+	hash_map_pt pendingSubscriptions; //<topic(string),List<pubsub_ep>>
+
+	char* ifIpAddress; // The local interface which is used for multicast communication
+    char* mcIpAddress; // The multicast IP address
+
+	int sendSocket;
+    void* zmq_context; // to be removed
+
+};
+
+celix_status_t pubsubAdmin_create(bundle_context_pt context, pubsub_admin_pt *admin);
+celix_status_t pubsubAdmin_stop(pubsub_admin_pt admin);
+celix_status_t pubsubAdmin_destroy(pubsub_admin_pt admin);
+
+celix_status_t pubsubAdmin_addSubscription(pubsub_admin_pt admin,pubsub_endpoint_pt subEP);
+celix_status_t pubsubAdmin_removeSubscription(pubsub_admin_pt admin,pubsub_endpoint_pt subEP);
+
+celix_status_t pubsubAdmin_addPublication(pubsub_admin_pt admin,pubsub_endpoint_pt pubEP);
+celix_status_t pubsubAdmin_removePublication(pubsub_admin_pt admin,pubsub_endpoint_pt pubEP);
+
+celix_status_t pubsubAdmin_closeAllPublications(pubsub_admin_pt admin,char* scope, char* topic);
+celix_status_t pubsubAdmin_closeAllSubscriptions(pubsub_admin_pt admin,char* scope, char* topic);
+
+#endif /* PUBSUB_ADMIN_IMPL_H_ */

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_admin_udp_mc/private/include/pubsub_publish_service_private.h
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_admin_udp_mc/private/include/pubsub_publish_service_private.h b/celix-pubsub/pubsub/pubsub_admin_udp_mc/private/include/pubsub_publish_service_private.h
new file mode 100644
index 0000000..57c7963
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_admin_udp_mc/private/include/pubsub_publish_service_private.h
@@ -0,0 +1,55 @@
+/**
+ *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.
+ */
+/*
+ * pubsub_publish_service_private.h
+ *
+ *  \date       Sep 24, 2015
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#ifndef PUBSUB_PUBLISH_SERVICE_PRIVATE_H_
+#define PUBSUB_PUBLISH_SERVICE_PRIVATE_H_
+
+#include "publisher.h"
+#include "pubsub_endpoint.h"
+#include "pubsub_common.h"
+
+#define UDP_BASE_PORT	49152
+#define UDP_MAX_PORT	65000
+
+typedef struct pubsub_udp_msg {
+    struct pubsub_msg_header header;
+    unsigned int payloadSize;
+    char payload[];
+} *pubsub_udp_msg_pt;
+
+typedef struct topic_publication *topic_publication_pt;
+celix_status_t pubsub_topicPublicationCreate(int sendSocket, pubsub_endpoint_pt pubEP,char* bindIP, topic_publication_pt *out);
+celix_status_t pubsub_topicPublicationDestroy(topic_publication_pt pub);
+
+celix_status_t pubsub_topicPublicationAddPublisherEP(topic_publication_pt pub,pubsub_endpoint_pt ep);
+celix_status_t pubsub_topicPublicationRemovePublisherEP(topic_publication_pt pub,pubsub_endpoint_pt ep);
+
+celix_status_t pubsub_topicPublicationStart(bundle_context_pt bundle_context,topic_publication_pt pub,service_factory_pt* svcFactory);
+celix_status_t pubsub_topicPublicationStop(topic_publication_pt pub);
+
+array_list_pt pubsub_topicPublicationGetPublisherList(topic_publication_pt pub);
+
+#endif /* PUBSUB_PUBLISH_SERVICE_PRIVATE_H_ */

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_admin_udp_mc/private/include/topic_subscription.h
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_admin_udp_mc/private/include/topic_subscription.h b/celix-pubsub/pubsub/pubsub_admin_udp_mc/private/include/topic_subscription.h
new file mode 100644
index 0000000..4ec705b
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_admin_udp_mc/private/include/topic_subscription.h
@@ -0,0 +1,55 @@
+/**
+ *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.
+ */
+/*
+ * topic_subscription.h
+ *
+ *  \date       Sep 22, 2015
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#ifndef TOPIC_SUBSCRIPTION_H_
+#define TOPIC_SUBSCRIPTION_H_
+
+#include "celix_threads.h"
+#include "array_list.h"
+#include "celixbool.h"
+#include "service_tracker.h"
+
+#include "pubsub_endpoint.h"
+#include "pubsub_common.h"
+
+typedef struct topic_subscription* topic_subscription_pt;
+
+celix_status_t pubsub_topicSubscriptionCreate(char* ifIp,bundle_context_pt bundle_context, char* scope, char* topic,topic_subscription_pt* out);
+celix_status_t pubsub_topicSubscriptionDestroy(topic_subscription_pt ts);
+celix_status_t pubsub_topicSubscriptionStart(topic_subscription_pt ts);
+celix_status_t pubsub_topicSubscriptionStop(topic_subscription_pt ts);
+
+celix_status_t pubsub_topicSubscriptionConnectPublisher(topic_subscription_pt ts, char* pubURL);
+celix_status_t pubsub_topicSubscriptionDisconnectPublisher(topic_subscription_pt ts, char* pubURL);
+
+celix_status_t pubsub_topicSubscriptionAddSubscriber(topic_subscription_pt ts, pubsub_endpoint_pt subEP);
+celix_status_t pubsub_topicSubscriptionRemoveSubscriber(topic_subscription_pt ts, pubsub_endpoint_pt subEP);
+
+celix_status_t pubsub_topicIncreaseNrSubscribers(topic_subscription_pt subscription);
+celix_status_t pubsub_topicDecreaseNrSubscribers(topic_subscription_pt subscription);
+unsigned int pubsub_topicGetNrSubscribers(topic_subscription_pt subscription);
+
+#endif /*TOPIC_SUBSCRIPTION_H_ */

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_admin_udp_mc/private/src/large_udp.c
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_admin_udp_mc/private/src/large_udp.c b/celix-pubsub/pubsub/pubsub_admin_udp_mc/private/src/large_udp.c
new file mode 100644
index 0000000..e5cd5b5
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_admin_udp_mc/private/src/large_udp.c
@@ -0,0 +1,362 @@
+/**
+ *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.
+ */
+/*
+ * large_udp.c
+ *
+ *  \date       Mar 1, 2016
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#include "large_udp.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <array_list.h>
+#include <pthread.h>
+
+#define MAX_UDP_MSG_SIZE 65535   /* 2^16 -1 */
+#define IP_HEADER_SIZE  20
+#define UDP_HEADER_SIZE 8
+//#define MTU_SIZE    1500
+#define MTU_SIZE    8000
+#define MAX_MSG_VECTOR_LEN 64
+
+//#define NO_IP_FRAGMENTATION
+
+struct largeUdp {
+    unsigned int maxNrLists;
+    array_list_pt udpPartLists;
+    pthread_mutex_t dbLock;
+};
+
+typedef struct udpPartList {
+    unsigned int msg_ident;
+    unsigned int msg_size;
+    unsigned int nrPartsRemaining;
+    char *data;
+} *udpPartList_pt;
+
+
+typedef struct msg_part_header {
+    unsigned int msg_ident;
+    unsigned int total_msg_size;
+    unsigned int part_msg_size;
+    unsigned int offset;
+} msg_part_header_t;
+
+#ifdef NO_IP_FRAGMENTATION
+    #define MAX_PART_SIZE   (MTU_SIZE - (IP_HEADER_SIZE + UDP_HEADER_SIZE + sizeof(struct msg_part_header) ))
+#else
+    #define MAX_PART_SIZE   (MAX_UDP_MSG_SIZE - (IP_HEADER_SIZE + UDP_HEADER_SIZE + sizeof(struct msg_part_header) ))
+#endif
+
+typedef struct msg_part {
+    msg_part_header_t header;
+    char data[MAX_PART_SIZE];
+} msg_part_t;
+
+//
+// Create a handle
+//
+largeUdp_pt largeUdp_create(unsigned int maxNrUdpReceptions)
+{
+    printf("## Creating large UDP\n");
+    largeUdp_pt handle = calloc(sizeof(*handle), 1);
+    if(handle != NULL) {
+        handle->maxNrLists = maxNrUdpReceptions;
+        if(arrayList_create(&handle->udpPartLists) != CELIX_SUCCESS) {
+            free(handle);
+            handle = NULL;
+        }
+        pthread_mutex_init(&handle->dbLock, 0);
+    }
+
+    return handle;
+}
+
+//
+// Destroys the handle
+//
+void largeUdp_destroy(largeUdp_pt handle)
+{
+    printf("### Destroying large UDP\n");
+    if(handle != NULL) {
+        pthread_mutex_lock(&handle->dbLock);
+        int nrUdpLists = arrayList_size(handle->udpPartLists);
+        int i;
+        for(i=0; i < nrUdpLists; i++) {
+            udpPartList_pt udpPartList = arrayList_remove(handle->udpPartLists, i);
+            if(udpPartList) {
+                if(udpPartList->data) {
+                    free(udpPartList->data);
+                    udpPartList->data = NULL;
+                }
+                free(udpPartList);
+            }
+        }
+        arrayList_destroy(handle->udpPartLists);
+        handle->udpPartLists = NULL;
+        pthread_mutex_unlock(&handle->dbLock);
+        pthread_mutex_destroy(&handle->dbLock);
+        free(handle);
+    }
+}
+
+//
+// Write large data to UDP. This function splits the data in chunks and sends these chunks with a header over UDP.
+//
+int largeUdp_sendmsg(largeUdp_pt handle, int fd, struct iovec *largeMsg_iovec, int len, int flags, struct sockaddr_in *dest_addr, size_t addrlen)
+{
+    int n;
+    int result = 0;
+    msg_part_header_t header;
+
+    int written = 0;
+    header.msg_ident = rand();
+    header.total_msg_size = 0;
+    for(n = 0; n < len ;n++) {
+    	header.total_msg_size += largeMsg_iovec[n].iov_len;
+    }
+    int nr_buffers = (header.total_msg_size / MAX_PART_SIZE) + 1;
+
+    struct iovec msg_iovec[MAX_MSG_VECTOR_LEN];
+    struct msghdr msg;
+    msg.msg_name = dest_addr;
+    msg.msg_namelen = addrlen;
+    msg.msg_flags = 0;
+    msg.msg_iov = msg_iovec;
+    msg.msg_iovlen = 2; // header and payload;
+    msg.msg_control = NULL;
+    msg.msg_controllen = 0;
+
+    msg.msg_iov[0].iov_base = &header;
+    msg.msg_iov[0].iov_len = sizeof(header);
+
+    for(n = 0; n < nr_buffers; n++) {
+
+        header.part_msg_size = (((header.total_msg_size - n * MAX_PART_SIZE) >  MAX_PART_SIZE) ?  MAX_PART_SIZE  : (header.total_msg_size - n * MAX_PART_SIZE));
+        header.offset = n * MAX_PART_SIZE;
+        int remainingOffset = header.offset;
+        int recvPart = 0;
+        // find the start of the part
+        while(remainingOffset > largeMsg_iovec[recvPart].iov_len) {
+        	remainingOffset -= largeMsg_iovec[recvPart].iov_len;
+        	recvPart++;
+        }
+        int remainingData = header.part_msg_size;
+        int sendPart = 1;
+        msg.msg_iovlen = 1;
+
+        // fill in the output iovec from the input iovec in such a way that all UDP frames are filled maximal.
+        while(remainingData > 0) {
+        	int partLen = ( (largeMsg_iovec[recvPart].iov_len - remainingOffset) <= remainingData ? (largeMsg_iovec[recvPart].iov_len -remainingOffset) : remainingData);
+        	msg.msg_iov[sendPart].iov_base = largeMsg_iovec[recvPart].iov_base + remainingOffset;
+        	msg.msg_iov[sendPart].iov_len = partLen;
+        	remainingData -= partLen;
+        	remainingOffset = 0;
+        	sendPart++;
+        	recvPart++;
+        	msg.msg_iovlen++;
+        }
+        int tmp, tmptot;
+        for(tmp = 0, tmptot=0; tmp < msg.msg_iovlen; tmp++) {
+        	tmptot += msg.msg_iov[tmp].iov_len;
+        }
+
+        int w = sendmsg(fd, &msg, 0);
+        if(w == -1) {
+            perror("send()");
+            result =  -1;
+            break;
+        }
+        written += w;
+    }
+
+    return (result == 0 ? written : result);
+}
+
+//
+// Write large data to UDP. This function splits the data in chunks and sends these chunks with a header over UDP.
+//
+int largeUdp_sendto(largeUdp_pt handle, int fd, void *buf, size_t count, int flags, struct sockaddr_in *dest_addr, size_t addrlen)
+{
+    int n;
+    int nr_buffers = (count / MAX_PART_SIZE) + 1;
+    int result = 0;
+    msg_part_header_t header;
+
+    int written = 0;
+    header.msg_ident = rand();
+    header.total_msg_size = count;
+    char *databuf = buf;
+
+    struct iovec msg_iovec[2];
+    struct msghdr msg;
+    msg.msg_name = dest_addr;
+    msg.msg_namelen = addrlen;
+    msg.msg_flags = 0;
+    msg.msg_iov = msg_iovec;
+    msg.msg_iovlen = 2; // header and payload;
+    msg.msg_control = NULL;
+    msg.msg_controllen = 0;
+
+    msg.msg_iov[0].iov_base = &header;
+    msg.msg_iov[0].iov_len = sizeof(header);
+
+    for(n = 0; n < nr_buffers; n++) {
+
+        header.part_msg_size = (((header.total_msg_size - n * MAX_PART_SIZE) >  MAX_PART_SIZE) ?  MAX_PART_SIZE  : (header.total_msg_size - n * MAX_PART_SIZE));
+        header.offset = n * MAX_PART_SIZE;
+        msg.msg_iov[1].iov_base = &databuf[header.offset];
+        msg.msg_iov[1].iov_len = header.part_msg_size;
+        int w = sendmsg(fd, &msg, 0);
+        if(w == -1) {
+            perror("send()");
+            result =  -1;
+            break;
+        }
+        written += w;
+        //usleep(1000); // TODO: If not slept a UDP buffer overflow occurs and parts are missing at the reception side (at least via localhost)
+    }
+
+    return (result == 0 ? written : result);
+}
+
+//
+// Reads data from the filedescriptor which has date (determined by epoll()) and stores it in the internal structure
+// If the message is completely reassembled true is returned and the index and size have valid values
+//
+bool largeUdp_dataAvailable(largeUdp_pt handle, int fd, unsigned int *index, unsigned int *size) {
+    msg_part_header_t header;
+    int result = false;
+    // Only read the header, we don't know yet where to store the payload
+    if(recv(fd, &header, sizeof(header), MSG_PEEK) < 0) {
+        perror("read()");
+        return false;
+    }
+
+    struct iovec msg_vec[2];
+    struct msghdr msg;
+    msg.msg_name = NULL;
+    msg.msg_namelen = 0;
+    msg.msg_flags = 0;
+    msg.msg_iov = msg_vec;
+    msg.msg_iovlen = 2; // header and payload;
+    msg.msg_control = NULL;
+    msg.msg_controllen = 0;
+
+    msg.msg_iov[0].iov_base = &header;
+    msg.msg_iov[0].iov_len = sizeof(header);
+
+    pthread_mutex_lock(&handle->dbLock);
+
+    int nrUdpLists = arrayList_size(handle->udpPartLists);
+    int i;
+    bool found = false;
+    for(i = 0; i < nrUdpLists; i++) {
+        udpPartList_pt udpPartList = arrayList_get(handle->udpPartLists, i);
+        if(udpPartList->msg_ident == header.msg_ident) {
+            found = true;
+
+            //sanity check
+            if(udpPartList->msg_size != header.total_msg_size) {
+                // Corruption occurred. Remove the existing administration and build up a new one.
+                arrayList_remove(handle->udpPartLists, i);
+                free(udpPartList->data);
+                free(udpPartList);
+                found = false;
+                break;
+            }
+
+            msg.msg_iov[1].iov_base = &udpPartList->data[header.offset];
+            msg.msg_iov[1].iov_len = header.part_msg_size;
+            recvmsg(fd, &msg, 0);
+
+            udpPartList->nrPartsRemaining--;
+            if(udpPartList->nrPartsRemaining == 0) {
+                *index = i;
+                *size = udpPartList->msg_size;
+                result = true;
+                break;
+            } else {
+                result = false; // not complete
+                break;
+            }
+        }
+    }
+
+    if(found == false) {
+        udpPartList_pt udpPartList = NULL;
+        if(nrUdpLists == handle->maxNrLists) {
+            // remove list at index 0
+            udpPartList = arrayList_remove(handle->udpPartLists, 0);
+            fprintf(stderr, "ERROR: Removing entry for id %d: %d parts not received\n",udpPartList->msg_ident, udpPartList->nrPartsRemaining );
+            free(udpPartList->data);
+            free(udpPartList);
+            nrUdpLists--;
+        }
+        udpPartList = calloc(sizeof(*udpPartList), 1);
+        udpPartList->msg_ident =  header.msg_ident;
+        udpPartList->msg_size =  header.total_msg_size;
+        udpPartList->nrPartsRemaining = header.total_msg_size / MAX_PART_SIZE;
+        udpPartList->data = calloc(sizeof(char), header.total_msg_size);
+
+        msg.msg_iov[1].iov_base = &udpPartList->data[header.offset];
+        msg.msg_iov[1].iov_len = header.part_msg_size;
+        recvmsg(fd, &msg, 0);
+
+        arrayList_add(handle->udpPartLists, udpPartList);
+
+        if(udpPartList->nrPartsRemaining == 0) {
+            *index = nrUdpLists;
+            *size = udpPartList->msg_size;
+            result = true;
+        } else {
+            result = false;
+        }
+
+    }
+    pthread_mutex_unlock(&handle->dbLock);
+
+    return result;
+}
+
+//
+// Read out the message which is indicated available by the largeUdp_dataAvailable function
+//
+int largeUdp_read(largeUdp_pt handle, unsigned int index, void ** buffer, unsigned int size)
+{
+    int result = 0;
+    pthread_mutex_lock(&handle->dbLock);
+
+    udpPartList_pt udpPartList = arrayList_remove(handle->udpPartLists, index);
+    if(udpPartList) {
+    	*buffer = udpPartList->data;
+        free(udpPartList);
+    } else {
+    	result = -1;
+    }
+    pthread_mutex_unlock(&handle->dbLock);
+
+    return result;
+}

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_admin_udp_mc/private/src/psa_activator.c
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_admin_udp_mc/private/src/psa_activator.c b/celix-pubsub/pubsub/pubsub_admin_udp_mc/private/src/psa_activator.c
new file mode 100644
index 0000000..053c757
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_admin_udp_mc/private/src/psa_activator.c
@@ -0,0 +1,113 @@
+/**
+ *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.
+ */
+/*
+ * psa_activator.c
+ *
+ *  \date       Sep 30, 2011
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#include <stdlib.h>
+
+#include "bundle_activator.h"
+#include "service_registration.h"
+
+#include "pubsub_admin_impl.h"
+
+struct activator {
+	pubsub_admin_pt admin;
+	pubsub_admin_service_pt adminService;
+	service_registration_pt registration;
+};
+
+celix_status_t bundleActivator_create(bundle_context_pt context, void **userData) {
+	celix_status_t status = CELIX_SUCCESS;
+	struct activator *activator;
+
+	activator = calloc(1, sizeof(*activator));
+	if (!activator) {
+		status = CELIX_ENOMEM;
+	}
+	else{
+		*userData = activator;
+		status = pubsubAdmin_create(context, &(activator->admin));
+	}
+
+	return status;
+}
+
+celix_status_t bundleActivator_start(void * userData, bundle_context_pt context) {
+	celix_status_t status = CELIX_SUCCESS;
+	struct activator *activator = userData;
+	pubsub_admin_service_pt pubsubAdminSvc = calloc(1, sizeof(*pubsubAdminSvc));
+
+	if (!pubsubAdminSvc) {
+		status = CELIX_ENOMEM;
+	}
+	else{
+		pubsubAdminSvc->admin = activator->admin;
+
+		pubsubAdminSvc->addPublication = pubsubAdmin_addPublication;
+		pubsubAdminSvc->removePublication = pubsubAdmin_removePublication;
+
+		pubsubAdminSvc->addSubscription = pubsubAdmin_addSubscription;
+		pubsubAdminSvc->removeSubscription = pubsubAdmin_removeSubscription;
+
+		pubsubAdminSvc->closeAllPublications = pubsubAdmin_closeAllPublications;
+		pubsubAdminSvc->closeAllSubscriptions = pubsubAdmin_closeAllSubscriptions;
+
+		activator->adminService = pubsubAdminSvc;
+
+		status = bundleContext_registerService(context, PUBSUB_ADMIN_SERVICE, pubsubAdminSvc, NULL, &activator->registration);
+
+	}
+
+
+	return status;
+}
+
+celix_status_t bundleActivator_stop(void * userData, bundle_context_pt context) {
+	celix_status_t status = CELIX_SUCCESS;
+	struct activator *activator = userData;
+
+	serviceRegistration_unregister(activator->registration);
+	activator->registration = NULL;
+
+	pubsubAdmin_stop(activator->admin);
+
+	free(activator->adminService);
+	activator->adminService = NULL;
+
+	return status;
+}
+
+celix_status_t bundleActivator_destroy(void * userData, bundle_context_pt context) {
+	celix_status_t status = CELIX_SUCCESS;
+	struct activator *activator = userData;
+
+	pubsubAdmin_destroy(activator->admin);
+	activator->admin = NULL;
+
+	free(activator);
+
+	return status;
+}
+
+


[3/6] celix git commit: CELIX-389: Adds Celix Publish Subscribe donation.

Posted by pn...@apache.org.
http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_admin_zmq/private/src/pubsub_admin_impl.c
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_admin_zmq/private/src/pubsub_admin_impl.c b/celix-pubsub/pubsub/pubsub_admin_zmq/private/src/pubsub_admin_impl.c
new file mode 100644
index 0000000..47bf094
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_admin_zmq/private/src/pubsub_admin_impl.c
@@ -0,0 +1,699 @@
+/**
+ *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.
+ */
+/*
+ * pubsub_admin_impl.c
+ *
+ *  \date       Sep 30, 2011
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#include "pubsub_admin_impl.h"
+#include <zmq.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+#ifndef ANDROID
+#include <ifaddrs.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "constants.h"
+#include "utils.h"
+#include "hash_map.h"
+#include "array_list.h"
+#include "bundle_context.h"
+#include "bundle.h"
+#include "service_reference.h"
+#include "service_registration.h"
+#include "log_helper.h"
+#include "log_service.h"
+#include "celix_threads.h"
+#include "service_factory.h"
+
+#include "topic_subscription.h"
+#include "pubsub_publish_service_private.h"
+#include "pubsub_endpoint.h"
+#include "pubsub_utils.h"
+#include "subscriber.h"
+
+#define MAX_KEY_FOLDER_PATH_LENGTH 512
+
+static const char *DEFAULT_IP = "127.0.0.1";
+
+static celix_status_t pubsubAdmin_getIpAdress(const char* interface, char** ip);
+static celix_status_t pubsubAdmin_addSubscriptionToPendingList(pubsub_admin_pt admin,pubsub_endpoint_pt subEP);
+static celix_status_t pubsubAdmin_addAnySubscription(pubsub_admin_pt admin,pubsub_endpoint_pt subEP);
+
+celix_status_t pubsubAdmin_create(bundle_context_pt context, pubsub_admin_pt *admin) {
+	celix_status_t status = CELIX_SUCCESS;
+
+#ifdef USE_ZMQ_SECURITY
+	if (!zsys_has_curve()){
+		printf("PSA: zeromq curve unsupported\n");
+		return CELIX_SERVICE_EXCEPTION;
+	}
+#endif
+
+	*admin = calloc(1, sizeof(**admin));
+
+	if (!*admin) {
+		status = CELIX_ENOMEM;
+	}
+	else{
+
+		const char *ip = NULL;
+		char *detectedIp = NULL;
+		(*admin)->bundle_context= context;
+		(*admin)->localPublications = hashMap_create(utils_stringHash, NULL, utils_stringEquals, NULL);
+		(*admin)->subscriptions = hashMap_create(utils_stringHash, NULL, utils_stringEquals, NULL);
+		(*admin)->pendingSubscriptions = hashMap_create(utils_stringHash, NULL, utils_stringEquals, NULL);
+		(*admin)->externalPublications = hashMap_create(utils_stringHash, NULL, utils_stringEquals, NULL);
+
+		celixThreadMutex_create(&(*admin)->localPublicationsLock, NULL);
+		celixThreadMutex_create(&(*admin)->subscriptionsLock, NULL);
+		celixThreadMutex_create(&(*admin)->pendingSubscriptionsLock, NULL);
+		celixThreadMutex_create(&(*admin)->externalPublicationsLock, NULL);
+
+		if (logHelper_create(context, &(*admin)->loghelper) == CELIX_SUCCESS) {
+			logHelper_start((*admin)->loghelper);
+		}
+
+		bundleContext_getProperty(context,PSA_IP , &ip);
+
+#ifndef ANDROID
+		if (ip == NULL) {
+			const char *interface = NULL;
+
+			bundleContext_getProperty(context, PSA_ITF, &interface);
+			if (pubsubAdmin_getIpAdress(interface, &detectedIp) != CELIX_SUCCESS) {
+				logHelper_log((*admin)->loghelper, OSGI_LOGSERVICE_WARNING, "PSA: Could not retrieve IP adress for interface %s", interface);
+			}
+
+			ip = detectedIp;
+		}
+#endif
+
+		if (ip != NULL) {
+			logHelper_log((*admin)->loghelper, OSGI_LOGSERVICE_INFO, "PSA: Using %s for service annunciation", ip);
+			(*admin)->ipAddress = strdup(ip);
+		}
+		else {
+			logHelper_log((*admin)->loghelper, OSGI_LOGSERVICE_WARNING, "PSA: No IP address for service annunciation set. Using %s", DEFAULT_IP);
+			(*admin)->ipAddress = strdup(DEFAULT_IP);
+		}
+
+		if (detectedIp != NULL) {
+			free(detectedIp);
+		}
+
+        const char* basePortStr = NULL;
+        const char* maxPortStr = NULL;
+        char* endptrBase = NULL;
+        char* endptrMax = NULL;
+        bundleContext_getPropertyWithDefault(context, PSA_ZMQ_BASE_PORT, "PSA_ZMQ_DEFAULT_BASE_PORT", &basePortStr);
+        bundleContext_getPropertyWithDefault(context, PSA_ZMQ_MAX_PORT, "PSA_ZMQ_DEFAULT_MAX_PORT", &maxPortStr);
+        (*admin)->basePort = strtol(basePortStr, &endptrBase, 10);
+        (*admin)->maxPort = strtol(maxPortStr, &endptrMax, 10);
+        if (*endptrBase != '\0') {
+            (*admin)->basePort = PSA_ZMQ_DEFAULT_BASE_PORT;
+        }
+        if (*endptrMax != '\0') {
+            (*admin)->maxPort = PSA_ZMQ_DEFAULT_MAX_PORT;
+        }
+
+        printf("PSA Using base port %u to max port %u\n", (*admin)->basePort, (*admin)->maxPort);
+
+        // Disable Signal Handling by CZMQ
+		setenv("ZSYS_SIGHANDLER", "false", true);
+
+		const char *nrZmqThreads = NULL;
+		bundleContext_getProperty(context, "PSA_NR_ZMQ_THREADS", &nrZmqThreads);
+
+		if(nrZmqThreads != NULL) {
+			char *endPtr = NULL;
+			unsigned int nrThreads = strtoul(nrZmqThreads, &endPtr, 10);
+			if(endPtr != nrZmqThreads && nrThreads > 0 && nrThreads < 50) {
+				zsys_set_io_threads(nrThreads);
+				logHelper_log((*admin)->loghelper, OSGI_LOGSERVICE_INFO, "PSA: Using %d threads for ZMQ", nrThreads);
+				printf("PSA: Using %d threads for ZMQ\n", nrThreads);
+			}
+		}
+
+#ifdef USE_ZMQ_SECURITY
+		// Setup authenticator
+		zactor_t* auth = zactor_new (zauth, NULL);
+		zstr_sendx(auth, "VERBOSE", NULL);
+
+		// Load all public keys of subscribers into the application
+		// This step is done for authenticating subscribers
+		char curve_folder_path[MAX_KEY_FOLDER_PATH_LENGTH];
+		char* keys_bundle_dir = pubsub_getKeysBundleDir(context);
+		snprintf(curve_folder_path, MAX_KEY_FOLDER_PATH_LENGTH, "%s/META-INF/keys/subscriber/public", keys_bundle_dir);
+		zstr_sendx (auth, "CURVE", curve_folder_path, NULL);
+		free(keys_bundle_dir);
+
+		(*admin)->zmq_auth = auth;
+#endif
+
+	}
+
+	return status;
+}
+
+
+celix_status_t pubsubAdmin_destroy(pubsub_admin_pt admin)
+{
+	celix_status_t status = CELIX_SUCCESS;
+
+	free(admin->ipAddress);
+
+	celixThreadMutex_lock(&admin->pendingSubscriptionsLock);
+	hash_map_iterator_pt iter = hashMapIterator_create(admin->pendingSubscriptions);
+	while(hashMapIterator_hasNext(iter)){
+		hash_map_entry_pt entry = hashMapIterator_nextEntry(iter);
+		free((char*)hashMapEntry_getKey(entry));
+		arrayList_destroy((array_list_pt)hashMapEntry_getValue(entry));
+	}
+	hashMapIterator_destroy(iter);
+	hashMap_destroy(admin->pendingSubscriptions,false,false);
+	celixThreadMutex_unlock(&admin->pendingSubscriptionsLock);
+
+	celixThreadMutex_lock(&admin->subscriptionsLock);
+	hashMap_destroy(admin->subscriptions,false,false);
+	celixThreadMutex_unlock(&admin->subscriptionsLock);
+
+	celixThreadMutex_lock(&admin->localPublicationsLock);
+	hashMap_destroy(admin->localPublications,true,false);
+	celixThreadMutex_unlock(&admin->localPublicationsLock);
+
+	celixThreadMutex_lock(&admin->externalPublicationsLock);
+	iter = hashMapIterator_create(admin->externalPublications);
+	while(hashMapIterator_hasNext(iter)){
+		hash_map_entry_pt entry = hashMapIterator_nextEntry(iter);
+		free((char*)hashMapEntry_getKey(entry));
+		arrayList_destroy((array_list_pt)hashMapEntry_getValue(entry));
+	}
+	hashMapIterator_destroy(iter);
+	hashMap_destroy(admin->externalPublications,false,false);
+	celixThreadMutex_unlock(&admin->externalPublicationsLock);
+
+	celixThreadMutex_destroy(&admin->pendingSubscriptionsLock);
+	celixThreadMutex_destroy(&admin->subscriptionsLock);
+	celixThreadMutex_destroy(&admin->localPublicationsLock);
+	celixThreadMutex_destroy(&admin->externalPublicationsLock);
+
+	logHelper_stop(admin->loghelper);
+
+	logHelper_destroy(&admin->loghelper);
+
+#ifdef USE_ZMQ_SECURITY
+	if (admin->zmq_auth != NULL){
+		zactor_destroy(&(admin->zmq_auth));
+	}
+#endif
+
+	free(admin);
+
+	return status;
+}
+
+static celix_status_t pubsubAdmin_addAnySubscription(pubsub_admin_pt admin,pubsub_endpoint_pt subEP){
+	celix_status_t status = CELIX_SUCCESS;
+
+	celixThreadMutex_lock(&admin->subscriptionsLock);
+
+	topic_subscription_pt any_sub = hashMap_get(admin->subscriptions,PUBSUB_ANY_SUB_TOPIC);
+
+	if(any_sub==NULL){
+
+		int i;
+
+		status += pubsub_topicSubscriptionCreate(admin->bundle_context, PUBSUB_SUBSCRIBER_SCOPE_DEFAULT, PUBSUB_ANY_SUB_TOPIC, &any_sub);
+
+		if (status == CELIX_SUCCESS){
+
+			/* Connect all internal publishers */
+			celixThreadMutex_lock(&admin->localPublicationsLock);
+			hash_map_iterator_pt lp_iter =hashMapIterator_create(admin->localPublications);
+			while(hashMapIterator_hasNext(lp_iter)){
+				service_factory_pt factory = (service_factory_pt)hashMapIterator_nextValue(lp_iter);
+				topic_publication_pt topic_pubs = (topic_publication_pt)factory->handle;
+				array_list_pt topic_publishers = pubsub_topicPublicationGetPublisherList(topic_pubs);
+
+				if(topic_publishers!=NULL){
+					for(i=0;i<arrayList_size(topic_publishers);i++){
+						pubsub_endpoint_pt pubEP = (pubsub_endpoint_pt)arrayList_get(topic_publishers,i);
+						if(pubEP->endpoint !=NULL){
+							status += pubsub_topicSubscriptionConnectPublisher(any_sub,pubEP->endpoint);
+						}
+					}
+				}
+			}
+			hashMapIterator_destroy(lp_iter);
+			celixThreadMutex_unlock(&admin->localPublicationsLock);
+
+			/* Connect also all external publishers */
+			celixThreadMutex_lock(&admin->externalPublicationsLock);
+			hash_map_iterator_pt extp_iter =hashMapIterator_create(admin->externalPublications);
+			while(hashMapIterator_hasNext(extp_iter)){
+				array_list_pt ext_pub_list = (array_list_pt)hashMapIterator_nextValue(extp_iter);
+				if(ext_pub_list!=NULL){
+					for(i=0;i<arrayList_size(ext_pub_list);i++){
+						pubsub_endpoint_pt pubEP = (pubsub_endpoint_pt)arrayList_get(ext_pub_list,i);
+						if(pubEP->endpoint !=NULL){
+							status += pubsub_topicSubscriptionConnectPublisher(any_sub,pubEP->endpoint);
+						}
+					}
+				}
+			}
+			hashMapIterator_destroy(extp_iter);
+			celixThreadMutex_unlock(&admin->externalPublicationsLock);
+
+
+			pubsub_topicSubscriptionAddSubscriber(any_sub,subEP);
+
+			status += pubsub_topicSubscriptionStart(any_sub);
+
+		}
+
+		if (status == CELIX_SUCCESS){
+			hashMap_put(admin->subscriptions,strdup(PUBSUB_ANY_SUB_TOPIC),any_sub);
+		}
+
+	}
+
+	celixThreadMutex_unlock(&admin->subscriptionsLock);
+
+	return status;
+}
+
+celix_status_t pubsubAdmin_addSubscription(pubsub_admin_pt admin,pubsub_endpoint_pt subEP){
+	celix_status_t status = CELIX_SUCCESS;
+
+	printf("PSA: Received subscription [FWUUID=%s bundleID=%ld scope=%s, topic=%s]\n",subEP->frameworkUUID,subEP->serviceID,subEP->scope, subEP->topic);
+
+	if(strcmp(subEP->topic,PUBSUB_ANY_SUB_TOPIC)==0){
+		return pubsubAdmin_addAnySubscription(admin,subEP);
+	}
+
+	/* Check if we already know some publisher about this topic, otherwise let's put the subscription in the pending hashmap */
+	celixThreadMutex_lock(&admin->localPublicationsLock);
+	celixThreadMutex_lock(&admin->externalPublicationsLock);
+
+    char* scope_topic = createScopeTopicKey(subEP->scope, subEP->topic);
+
+	service_factory_pt factory = (service_factory_pt)hashMap_get(admin->localPublications,scope_topic);
+	array_list_pt ext_pub_list = (array_list_pt)hashMap_get(admin->externalPublications,scope_topic);
+
+	if(factory==NULL && ext_pub_list==NULL){ //No (local or external) publishers yet for this topic
+		celixThreadMutex_lock(&admin->pendingSubscriptionsLock);
+		pubsubAdmin_addSubscriptionToPendingList(admin,subEP);
+		celixThreadMutex_unlock(&admin->pendingSubscriptionsLock);
+	} else {
+		int i;
+		topic_subscription_pt subscription = hashMap_get(admin->subscriptions, scope_topic);
+
+		if(subscription == NULL) {
+			status += pubsub_topicSubscriptionCreate(admin->bundle_context,subEP->scope, subEP->topic,&subscription);
+
+			if (status==CELIX_SUCCESS){
+
+				/* Try to connect internal publishers */
+				if(factory!=NULL){
+					topic_publication_pt topic_pubs = (topic_publication_pt)factory->handle;
+					array_list_pt topic_publishers = pubsub_topicPublicationGetPublisherList(topic_pubs);
+
+					if(topic_publishers!=NULL){
+						for(i=0;i<arrayList_size(topic_publishers);i++){
+							pubsub_endpoint_pt pubEP = (pubsub_endpoint_pt)arrayList_get(topic_publishers,i);
+							if(pubEP->endpoint !=NULL){
+								status += pubsub_topicSubscriptionConnectPublisher(subscription,pubEP->endpoint);
+							}
+						}
+					}
+
+				}
+
+				/* Look also for external publishers */
+				if(ext_pub_list!=NULL){
+					for(i=0;i<arrayList_size(ext_pub_list);i++){
+						pubsub_endpoint_pt pubEP = (pubsub_endpoint_pt)arrayList_get(ext_pub_list,i);
+						if(pubEP->endpoint !=NULL){
+							status += pubsub_topicSubscriptionConnectPublisher(subscription,pubEP->endpoint);
+						}
+					}
+				}
+
+				pubsub_topicSubscriptionAddSubscriber(subscription,subEP);
+
+				status += pubsub_topicSubscriptionStart(subscription);
+
+			}
+
+			if(status==CELIX_SUCCESS){
+				celixThreadMutex_lock(&admin->subscriptionsLock);
+				hashMap_put(admin->subscriptions,strdup(scope_topic),subscription);
+				celixThreadMutex_unlock(&admin->subscriptionsLock);
+			}
+		}
+
+		if (status == CELIX_SUCCESS){
+			pubsub_topicIncreaseNrSubscribers(subscription);
+		}
+	}
+
+    free(scope_topic);
+	celixThreadMutex_unlock(&admin->externalPublicationsLock);
+	celixThreadMutex_unlock(&admin->localPublicationsLock);
+
+	return status;
+
+}
+
+celix_status_t pubsubAdmin_removeSubscription(pubsub_admin_pt admin,pubsub_endpoint_pt subEP){
+	celix_status_t status = CELIX_SUCCESS;
+
+	printf("PSA: Removing subscription [FWUUID=%s bundleID=%ld topic=%s]\n",subEP->frameworkUUID,subEP->serviceID,subEP->topic);
+
+	celixThreadMutex_lock(&admin->subscriptionsLock);
+
+	topic_subscription_pt sub = (topic_subscription_pt)hashMap_get(admin->subscriptions,subEP->topic);
+
+	if(sub!=NULL){
+		pubsub_topicDecreaseNrSubscribers(sub);
+		if(pubsub_topicGetNrSubscribers(sub) == 0) {
+			status = pubsub_topicSubscriptionRemoveSubscriber(sub,subEP);
+		}
+	}
+	else{
+		status = CELIX_ILLEGAL_STATE;
+	}
+
+	celixThreadMutex_unlock(&admin->subscriptionsLock);
+
+	return status;
+
+}
+
+celix_status_t pubsubAdmin_addPublication(pubsub_admin_pt admin, pubsub_endpoint_pt pubEP) {
+    celix_status_t status = CELIX_SUCCESS;
+
+    printf("PSA: Received publication [FWUUID=%s bundleID=%ld scope=%s, topic=%s]\n", pubEP->frameworkUUID, pubEP->serviceID, pubEP->scope, pubEP->topic);
+
+    const char* fwUUID = NULL;
+
+    char *scope_topic = createScopeTopicKey(pubEP->scope, pubEP->topic);
+    bundleContext_getProperty(admin->bundle_context, OSGI_FRAMEWORK_FRAMEWORK_UUID, &fwUUID);
+    if (fwUUID == NULL) {
+        printf("PSA: Cannot retrieve fwUUID.\n");
+        return CELIX_INVALID_BUNDLE_CONTEXT;
+    }
+
+    if ((strcmp(pubEP->frameworkUUID, fwUUID) == 0) && (pubEP->endpoint == NULL)) {
+
+        celixThreadMutex_lock(&admin->localPublicationsLock);
+
+        service_factory_pt factory = (service_factory_pt) hashMap_get(admin->localPublications, scope_topic);
+
+        if (factory == NULL) {
+            topic_publication_pt pub = NULL;
+            status = pubsub_topicPublicationCreate(admin->bundle_context, pubEP, admin->ipAddress, admin->basePort, admin->maxPort, &pub);
+            if (status == CELIX_SUCCESS) {
+                status = pubsub_topicPublicationStart(admin->bundle_context, pub, &factory);
+                if (status == CELIX_SUCCESS && factory != NULL) {
+                    hashMap_put(admin->localPublications, strdup(scope_topic), factory);
+                }
+            } else {
+                printf("PSA: Cannot create a topicPublication for scope=%s, topic=%s (bundle %ld).\n", pubEP->scope, pubEP->topic, pubEP->serviceID);
+            }
+        } else {
+            //just add the new EP to the list
+            topic_publication_pt pub = (topic_publication_pt) factory->handle;
+            pubsub_topicPublicationAddPublisherEP(pub, pubEP);
+        }
+
+        celixThreadMutex_unlock(&admin->localPublicationsLock);
+    } else {
+
+        celixThreadMutex_lock(&admin->externalPublicationsLock);
+        array_list_pt ext_pub_list = (array_list_pt) hashMap_get(admin->externalPublications, scope_topic);
+        if (ext_pub_list == NULL) {
+            arrayList_create(&ext_pub_list);
+            hashMap_put(admin->externalPublications, strdup(scope_topic), ext_pub_list);
+        }
+
+        arrayList_add(ext_pub_list, pubEP);
+
+        celixThreadMutex_unlock(&admin->externalPublicationsLock);
+    }
+
+    /* Re-evaluate the pending subscriptions */
+    celixThreadMutex_lock(&admin->pendingSubscriptionsLock);
+
+    hash_map_entry_pt pendingSub = hashMap_getEntry(admin->pendingSubscriptions, scope_topic);
+    if (pendingSub != NULL) { //There were pending subscription for the just published topic. Let's connect them.
+        char* topic = (char*) hashMapEntry_getKey(pendingSub);
+        array_list_pt pendingSubList = (array_list_pt) hashMapEntry_getValue(pendingSub);
+        int i;
+        for (i = 0; i < arrayList_size(pendingSubList); i++) {
+            pubsub_endpoint_pt subEP = (pubsub_endpoint_pt) arrayList_get(pendingSubList, i);
+            pubsubAdmin_addSubscription(admin, subEP);
+        }
+        hashMap_remove(admin->pendingSubscriptions, scope_topic);
+        arrayList_clear(pendingSubList);
+        arrayList_destroy(pendingSubList);
+        free(topic);
+    }
+
+    celixThreadMutex_unlock(&admin->pendingSubscriptionsLock);
+
+    /* Connect the new publisher to the subscription for his topic, if there is any */
+    celixThreadMutex_lock(&admin->subscriptionsLock);
+
+    topic_subscription_pt sub = (topic_subscription_pt) hashMap_get(admin->subscriptions, scope_topic);
+    if (sub != NULL && pubEP->endpoint != NULL) {
+        pubsub_topicSubscriptionAddConnectPublisherToPendingList(sub, pubEP->endpoint);
+    }
+
+    /* And check also for ANY subscription */
+    topic_subscription_pt any_sub = (topic_subscription_pt) hashMap_get(admin->subscriptions, PUBSUB_ANY_SUB_TOPIC);
+    if (any_sub != NULL && pubEP->endpoint != NULL) {
+        pubsub_topicSubscriptionAddConnectPublisherToPendingList(sub, pubEP->endpoint);
+    }
+    free(scope_topic);
+
+    celixThreadMutex_unlock(&admin->subscriptionsLock);
+
+    return status;
+
+}
+
+celix_status_t pubsubAdmin_removePublication(pubsub_admin_pt admin,pubsub_endpoint_pt pubEP){
+	celix_status_t status = CELIX_SUCCESS;
+        int count = 0;
+
+	printf("PSA: Removing publication [FWUUID=%s bundleID=%ld topic=%s]\n",pubEP->frameworkUUID,pubEP->serviceID,pubEP->topic);
+
+	const char* fwUUID = NULL;
+
+	bundleContext_getProperty(admin->bundle_context,OSGI_FRAMEWORK_FRAMEWORK_UUID,&fwUUID);
+	if(fwUUID==NULL){
+		printf("PSA: Cannot retrieve fwUUID.\n");
+		return CELIX_INVALID_BUNDLE_CONTEXT;
+	}
+	char *scope_topic = createScopeTopicKey(pubEP->scope, pubEP->topic);
+	if(strcmp(pubEP->frameworkUUID,fwUUID)==0){
+
+		celixThreadMutex_lock(&admin->localPublicationsLock);
+
+		service_factory_pt factory = (service_factory_pt)hashMap_get(admin->localPublications,scope_topic);
+		if(factory!=NULL){
+			topic_publication_pt pub = (topic_publication_pt)factory->handle;
+			pubsub_topicPublicationRemovePublisherEP(pub,pubEP);
+		}
+		else{
+			status = CELIX_ILLEGAL_STATE;
+		}
+
+		celixThreadMutex_unlock(&admin->localPublicationsLock);
+	}
+	else{
+
+		celixThreadMutex_lock(&admin->externalPublicationsLock);
+		array_list_pt ext_pub_list = (array_list_pt)hashMap_get(admin->externalPublications,scope_topic);
+		if(ext_pub_list!=NULL){
+			int i;
+			bool found = false;
+			for(i=0;!found && i<arrayList_size(ext_pub_list);i++){
+				pubsub_endpoint_pt p  = (pubsub_endpoint_pt)arrayList_get(ext_pub_list,i);
+				found = pubsubEndpoint_equals(pubEP,p);
+				if (found){
+				        found = true;
+					arrayList_remove(ext_pub_list,i);
+				}
+			}
+			// Check if there are more publsihers on the same endpoint (happens when 1 celix-instance with multiple bundles publish in same topic)
+                        for(i=0; i<arrayList_size(ext_pub_list);i++) {
+                            pubsub_endpoint_pt p  = (pubsub_endpoint_pt)arrayList_get(ext_pub_list,i);
+                            if (strcmp(pubEP->endpoint,p->endpoint) == 0) {
+                                count++;
+                            }
+                        }
+
+		}
+		if(arrayList_size(ext_pub_list)==0){
+			hash_map_entry_pt entry = hashMap_getEntry(admin->externalPublications,scope_topic);
+			char* topic = (char*)hashMapEntry_getKey(entry);
+			array_list_pt list = (array_list_pt)hashMapEntry_getValue(entry);
+			hashMap_remove(admin->externalPublications,topic);
+			arrayList_destroy(list);
+			free(topic);
+		}
+
+		celixThreadMutex_unlock(&admin->externalPublicationsLock);
+	}
+
+	/* Check if this publisher was connected to one of our subscribers*/
+	celixThreadMutex_lock(&admin->subscriptionsLock);
+
+	topic_subscription_pt sub = (topic_subscription_pt)hashMap_get(admin->subscriptions,scope_topic);
+	if(sub!=NULL && pubEP->endpoint!=NULL && count == 0){
+		pubsub_topicSubscriptionAddDisconnectPublisherToPendingList(sub,pubEP->endpoint);
+	}
+
+	/* And check also for ANY subscription */
+	topic_subscription_pt any_sub = (topic_subscription_pt)hashMap_get(admin->subscriptions,PUBSUB_ANY_SUB_TOPIC);
+	if(any_sub!=NULL && pubEP->endpoint!=NULL && count == 0){
+		pubsub_topicSubscriptionAddDisconnectPublisherToPendingList(sub,pubEP->endpoint);
+	}
+	free(scope_topic);
+	celixThreadMutex_unlock(&admin->subscriptionsLock);
+
+	return status;
+
+}
+
+celix_status_t pubsubAdmin_closeAllPublications(pubsub_admin_pt admin, char *scope, char* topic){
+	celix_status_t status = CELIX_SUCCESS;
+
+	printf("PSA: Closing all publications\n");
+
+	celixThreadMutex_lock(&admin->localPublicationsLock);
+	char *scope_topic = createScopeTopicKey(scope, topic);
+	hash_map_entry_pt pubsvc_entry = (hash_map_entry_pt)hashMap_getEntry(admin->localPublications,scope_topic);
+	if(pubsvc_entry!=NULL){
+		char* topic = (char*)hashMapEntry_getKey(pubsvc_entry);
+		service_factory_pt factory= (service_factory_pt)hashMapEntry_getValue(pubsvc_entry);
+		topic_publication_pt pub = (topic_publication_pt)factory->handle;
+		status += pubsub_topicPublicationStop(pub);
+		status += pubsub_topicPublicationDestroy(pub);
+
+		hashMap_remove(admin->localPublications,scope_topic);
+		free(topic);
+		free(factory);
+	}
+	free(scope_topic);
+	celixThreadMutex_unlock(&admin->localPublicationsLock);
+
+	return status;
+
+}
+
+celix_status_t pubsubAdmin_closeAllSubscriptions(pubsub_admin_pt admin,char* scope,char* topic){
+	celix_status_t status = CELIX_SUCCESS;
+
+	printf("PSA: Closing all subscriptions\n");
+
+	celixThreadMutex_lock(&admin->subscriptionsLock);
+	char *scope_topic = createScopeTopicKey(scope, topic);
+	hash_map_entry_pt sub_entry = (hash_map_entry_pt)hashMap_getEntry(admin->subscriptions,scope_topic);
+	if(sub_entry!=NULL){
+		char* topic = (char*)hashMapEntry_getKey(sub_entry);
+
+		topic_subscription_pt ts = (topic_subscription_pt)hashMapEntry_getValue(sub_entry);
+		status += pubsub_topicSubscriptionStop(ts);
+		status += pubsub_topicSubscriptionDestroy(ts);
+
+		hashMap_remove(admin->subscriptions,scope_topic);
+		free(topic);
+
+	}
+	free(scope_topic);
+	celixThreadMutex_unlock(&admin->subscriptionsLock);
+
+	return status;
+
+}
+
+
+#ifndef ANDROID
+static celix_status_t pubsubAdmin_getIpAdress(const char* interface, char** ip) {
+	celix_status_t status = CELIX_BUNDLE_EXCEPTION;
+
+	struct ifaddrs *ifaddr, *ifa;
+	char host[NI_MAXHOST];
+
+	if (getifaddrs(&ifaddr) != -1)
+	{
+		for (ifa = ifaddr; ifa != NULL && status != CELIX_SUCCESS; ifa = ifa->ifa_next)
+		{
+			if (ifa->ifa_addr == NULL)
+				continue;
+
+			if ((getnameinfo(ifa->ifa_addr,sizeof(struct sockaddr_in), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) == 0) && (ifa->ifa_addr->sa_family == AF_INET)) {
+				if (interface == NULL) {
+					*ip = strdup(host);
+					status = CELIX_SUCCESS;
+				}
+				else if (strcmp(ifa->ifa_name, interface) == 0) {
+					*ip = strdup(host);
+					status = CELIX_SUCCESS;
+				}
+			}
+		}
+
+		freeifaddrs(ifaddr);
+	}
+
+	return status;
+}
+#endif
+
+static celix_status_t pubsubAdmin_addSubscriptionToPendingList(pubsub_admin_pt admin,pubsub_endpoint_pt subEP){
+	celix_status_t status = CELIX_SUCCESS;
+	char* scope_topic = createScopeTopicKey(subEP->scope, subEP->topic);
+	array_list_pt pendingListPerTopic = hashMap_get(admin->pendingSubscriptions,scope_topic);
+	if(pendingListPerTopic==NULL){
+		arrayList_create(&pendingListPerTopic);
+		hashMap_put(admin->pendingSubscriptions,strdup(scope_topic),pendingListPerTopic);
+	}
+	arrayList_add(pendingListPerTopic,subEP);
+	free(scope_topic);
+	return status;
+}

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_admin_zmq/private/src/topic_publication.c
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_admin_zmq/private/src/topic_publication.c b/celix-pubsub/pubsub/pubsub_admin_zmq/private/src/topic_publication.c
new file mode 100644
index 0000000..4943884
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_admin_zmq/private/src/topic_publication.c
@@ -0,0 +1,605 @@
+/**
+ *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.
+ */
+/*
+ * topic_publication.c
+ *
+ *  \date       Sep 24, 2015
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#include "pubsub_publish_service_private.h"
+#include <czmq.h>
+/* The following undefs prevent the collision between:
+ * - sys/syslog.h (which is included within czmq)
+ * - celix/dfi/dfi_log_util.h
+ */
+#undef LOG_DEBUG
+#undef LOG_WARNING
+#undef LOG_INFO
+#undef LOG_WARNING
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "array_list.h"
+#include "celixbool.h"
+#include "service_registration.h"
+#include "utils.h"
+#include "service_factory.h"
+#include "version.h"
+
+#include "pubsub_common.h"
+#include "dyn_msg_utils.h"
+#include "pubsub_utils.h"
+#include "publisher.h"
+
+#include "pubsub_serializer.h"
+
+#ifdef USE_ZMQ_SECURITY
+	#include "zmq_crypto.h"
+
+	#define MAX_CERT_PATH_LENGTH 512
+#endif
+
+#define EP_ADDRESS_LEN		32
+#define ZMQ_BIND_MAX_RETRY	5
+
+#define FIRST_SEND_DELAY	2
+
+struct topic_publication {
+	zsock_t* zmq_socket;
+	zcert_t * zmq_cert;
+	char* endpoint;
+	service_registration_pt svcFactoryReg;
+	array_list_pt pub_ep_list; //List<pubsub_endpoint>
+	hash_map_pt boundServices; //<bundle_pt,bound_service>
+	celix_thread_mutex_t tp_lock;
+};
+
+typedef struct publish_bundle_bound_service {
+	topic_publication_pt parent;
+	pubsub_publisher_pt service;
+	bundle_pt bundle;
+	char *topic;
+	hash_map_pt msgTypes;
+	unsigned short getCount;
+	celix_thread_mutex_t mp_lock;
+	bool mp_send_in_progress;
+	array_list_pt mp_parts;
+}* publish_bundle_bound_service_pt;
+
+typedef struct pubsub_msg{
+	pubsub_msg_header_pt header;
+	char* payload;
+	int payloadSize;
+}* pubsub_msg_pt;
+
+static unsigned int rand_range(unsigned int min, unsigned int max);
+
+static celix_status_t pubsub_topicPublicationGetService(void* handle, bundle_pt bundle, service_registration_pt registration, void **service);
+static celix_status_t pubsub_topicPublicationUngetService(void* handle, bundle_pt bundle, service_registration_pt registration, void **service);
+
+static publish_bundle_bound_service_pt pubsub_createPublishBundleBoundService(topic_publication_pt tp,bundle_pt bundle);
+static void pubsub_destroyPublishBundleBoundService(publish_bundle_bound_service_pt boundSvc);
+
+static int pubsub_topicPublicationSend(void* handle,unsigned int msgTypeId, void *msg);
+static int pubsub_topicPublicationSendMultipart(void *handle, unsigned int msgTypeId, void *msg, int flags);
+static int pubsub_localMsgTypeIdForUUID(void* handle, const char* msgType, unsigned int* msgTypeId);
+
+static void delay_first_send_for_late_joiners(void);
+
+celix_status_t pubsub_topicPublicationCreate(bundle_context_pt bundle_context, pubsub_endpoint_pt pubEP,char* bindIP, unsigned int basePort, unsigned int maxPort, topic_publication_pt *out){
+	celix_status_t status = CELIX_SUCCESS;
+
+#ifdef USE_ZMQ_SECURITY
+	char* keys_bundle_dir = pubsub_getKeysBundleDir(bundle_context);
+	if (keys_bundle_dir == NULL){
+		return CELIX_SERVICE_EXCEPTION;
+	}
+
+	const char* keys_file_path = NULL;
+	const char* keys_file_name = NULL;
+	bundleContext_getProperty(bundle_context, PROPERTY_KEYS_FILE_PATH, &keys_file_path);
+	bundleContext_getProperty(bundle_context, PROPERTY_KEYS_FILE_NAME, &keys_file_name);
+
+	char cert_path[MAX_CERT_PATH_LENGTH];
+
+	//certificate path ".cache/bundle{id}/version0.0/./META-INF/keys/publisher/private/pub_{topic}.key"
+	snprintf(cert_path, MAX_CERT_PATH_LENGTH, "%s/META-INF/keys/publisher/private/pub_%s.key.enc", keys_bundle_dir, pubEP->topic);
+	free(keys_bundle_dir);
+	printf("PSA: Loading key '%s'\n", cert_path);
+
+	zcert_t* pub_cert = get_zcert_from_encoded_file((char *) keys_file_path, (char *) keys_file_name, cert_path);
+	if (pub_cert == NULL){
+		printf("PSA: Cannot load key '%s'\n", cert_path);
+		return CELIX_SERVICE_EXCEPTION;
+	}
+#endif
+
+	zsock_t* socket = zsock_new (ZMQ_PUB);
+	if(socket==NULL){
+		#ifdef USE_ZMQ_SECURITY
+			zcert_destroy(&pub_cert);
+		#endif
+
+        perror("Error for zmq_socket");
+		return CELIX_SERVICE_EXCEPTION;
+	}
+#ifdef USE_ZMQ_SECURITY
+	zcert_apply (pub_cert, socket); // apply certificate to socket
+	zsock_set_curve_server (socket, true); // setup the publisher's socket to use the curve functions
+#endif
+
+	int rv = -1, retry=0;
+	char* ep = malloc(EP_ADDRESS_LEN);
+    char bindAddress[EP_ADDRESS_LEN];
+
+	while(rv==-1 && retry<ZMQ_BIND_MAX_RETRY){
+		/* Randomized part due to same bundle publishing on different topics */
+		unsigned int port = rand_range(basePort,maxPort);
+		memset(ep,0,EP_ADDRESS_LEN);
+        memset(bindAddress, 0, EP_ADDRESS_LEN);
+
+		snprintf(ep,EP_ADDRESS_LEN,"tcp://%s:%u",bindIP,port);
+        snprintf(bindAddress, EP_ADDRESS_LEN, "tcp://0.0.0.0:%u", port); //NOTE using a different bind addres than endpoint address
+		rv = zsock_bind (socket, bindAddress);
+        if (rv == -1) {
+            perror("Error for zmq_bind");
+        }
+		retry++;
+	}
+
+	if(rv == -1){
+		free(ep);
+		return CELIX_SERVICE_EXCEPTION;
+	}
+
+	/* ZMQ stuffs are all fine at this point. Let's create and initialize the structure */
+
+	topic_publication_pt pub = calloc(1,sizeof(*pub));
+
+	arrayList_create(&(pub->pub_ep_list));
+	pub->boundServices = hashMap_create(NULL,NULL,NULL,NULL);
+	celixThreadMutex_create(&(pub->tp_lock),NULL);
+
+	pub->endpoint = ep;
+	pub->zmq_socket = socket;
+
+	#ifdef USE_ZMQ_SECURITY
+	pub->zmq_cert = pub_cert;
+	#endif
+
+	pubsub_topicPublicationAddPublisherEP(pub,pubEP);
+
+	*out = pub;
+
+	return status;
+}
+
+celix_status_t pubsub_topicPublicationDestroy(topic_publication_pt pub){
+	celix_status_t status = CELIX_SUCCESS;
+
+	celixThreadMutex_lock(&(pub->tp_lock));
+
+	free(pub->endpoint);
+	arrayList_destroy(pub->pub_ep_list);
+
+	hash_map_iterator_pt iter = hashMapIterator_create(pub->boundServices);
+	while(hashMapIterator_hasNext(iter)){
+		publish_bundle_bound_service_pt bound = hashMapIterator_nextValue(iter);
+		pubsub_destroyPublishBundleBoundService(bound);
+	}
+	hashMapIterator_destroy(iter);
+	hashMap_destroy(pub->boundServices,false,false);
+
+	pub->svcFactoryReg = NULL;
+	zsock_destroy(&(pub->zmq_socket));
+	#ifdef USE_ZMQ_SECURITY
+	zcert_destroy(&(pub->zmq_cert));
+	#endif
+
+	celixThreadMutex_unlock(&(pub->tp_lock));
+
+	celixThreadMutex_destroy(&(pub->tp_lock));
+
+	free(pub);
+
+	return status;
+}
+
+celix_status_t pubsub_topicPublicationStart(bundle_context_pt bundle_context,topic_publication_pt pub,service_factory_pt* svcFactory){
+	celix_status_t status = CELIX_SUCCESS;
+
+	/* Let's register the new service */
+	//celixThreadMutex_lock(&(pub->tp_lock));
+
+	pubsub_endpoint_pt pubEP = (pubsub_endpoint_pt)arrayList_get(pub->pub_ep_list,0);
+
+	if(pubEP!=NULL){
+		service_factory_pt factory = calloc(1, sizeof(*factory));
+		factory->handle = pub;
+		factory->getService = pubsub_topicPublicationGetService;
+		factory->ungetService = pubsub_topicPublicationUngetService;
+
+		properties_pt props = properties_create();
+		properties_set(props,PUBSUB_PUBLISHER_TOPIC,pubEP->topic);
+		properties_set(props,PUBSUB_PUBLISHER_SCOPE,pubEP->scope);
+		properties_set(props,"service.version", PUBSUB_PUBLISHER_SERVICE_VERSION);
+
+		status = bundleContext_registerServiceFactory(bundle_context,PUBSUB_PUBLISHER_SERVICE_NAME,factory,props,&(pub->svcFactoryReg));
+
+		if(status != CELIX_SUCCESS){
+			properties_destroy(props);
+			printf("PSA: Cannot register ServiceFactory for topic %s (bundle %ld).\n",pubEP->topic,pubEP->serviceID);
+		}
+		else{
+			*svcFactory = factory;
+		}
+	}
+	else{
+		printf("PSA: Cannot find pubsub_endpoint after adding it...Should never happen!\n");
+		status = CELIX_SERVICE_EXCEPTION;
+	}
+
+	//celixThreadMutex_unlock(&(pub->tp_lock));
+
+	return status;
+}
+
+celix_status_t pubsub_topicPublicationStop(topic_publication_pt pub){
+	celix_status_t status = CELIX_SUCCESS;
+
+	//celixThreadMutex_lock(&(pub->tp_lock));
+
+	status = serviceRegistration_unregister(pub->svcFactoryReg);
+
+	//celixThreadMutex_unlock(&(pub->tp_lock));
+
+	return status;
+}
+
+celix_status_t pubsub_topicPublicationAddPublisherEP(topic_publication_pt pub,pubsub_endpoint_pt ep){
+
+	celixThreadMutex_lock(&(pub->tp_lock));
+	ep->endpoint = strdup(pub->endpoint);
+	arrayList_add(pub->pub_ep_list,ep);
+	celixThreadMutex_unlock(&(pub->tp_lock));
+
+	return CELIX_SUCCESS;
+}
+
+celix_status_t pubsub_topicPublicationRemovePublisherEP(topic_publication_pt pub,pubsub_endpoint_pt ep){
+
+	celixThreadMutex_lock(&(pub->tp_lock));
+	for (int i = 0; i < arrayList_size(pub->pub_ep_list); i++) {
+	        pubsub_endpoint_pt e = arrayList_get(pub->pub_ep_list, i);
+	        if(pubsubEndpoint_equals(ep, e)) {
+	            arrayList_removeElement(pub->pub_ep_list,ep);
+	            break;
+	        }
+	}
+	celixThreadMutex_unlock(&(pub->tp_lock));
+
+	return CELIX_SUCCESS;
+}
+
+array_list_pt pubsub_topicPublicationGetPublisherList(topic_publication_pt pub){
+	return pub->pub_ep_list;
+}
+
+
+static celix_status_t pubsub_topicPublicationGetService(void* handle, bundle_pt bundle, service_registration_pt registration, void **service) {
+	celix_status_t  status = CELIX_SUCCESS;
+
+	topic_publication_pt publish = (topic_publication_pt)handle;
+
+	celixThreadMutex_lock(&(publish->tp_lock));
+
+	publish_bundle_bound_service_pt bound = (publish_bundle_bound_service_pt)hashMap_get(publish->boundServices,bundle);
+	if(bound==NULL){
+		bound = pubsub_createPublishBundleBoundService(publish,bundle);
+		if(bound!=NULL){
+			hashMap_put(publish->boundServices,bundle,bound);
+		}
+	}
+	else{
+		bound->getCount++;
+	}
+
+	*service = bound->service;
+
+	celixThreadMutex_unlock(&(publish->tp_lock));
+
+	return status;
+}
+
+static celix_status_t pubsub_topicPublicationUngetService(void* handle, bundle_pt bundle, service_registration_pt registration, void **service)  {
+
+	topic_publication_pt publish = (topic_publication_pt)handle;
+
+	celixThreadMutex_lock(&(publish->tp_lock));
+
+	publish_bundle_bound_service_pt bound = (publish_bundle_bound_service_pt)hashMap_get(publish->boundServices,bundle);
+	if(bound!=NULL){
+
+		bound->getCount--;
+		if(bound->getCount==0){
+			pubsub_destroyPublishBundleBoundService(bound);
+			hashMap_remove(publish->boundServices,bundle);
+		}
+
+	}
+	else{
+		long bundleId = -1;
+		bundle_getBundleId(bundle,&bundleId);
+		printf("TP: Unexpected ungetService call for bundle %ld.\n", bundleId);
+	}
+
+	/* service should be never used for unget, so let's set the pointer to NULL */
+	*service = NULL;
+
+	celixThreadMutex_unlock(&(publish->tp_lock));
+
+	return CELIX_SUCCESS;
+}
+
+static bool send_pubsub_msg(zsock_t* zmq_socket, pubsub_msg_pt msg, bool last){
+
+	bool ret = true;
+
+	zframe_t* headerMsg = zframe_new(msg->header, sizeof(struct pubsub_msg_header));
+	if (headerMsg == NULL) ret=false;
+	zframe_t* payloadMsg = zframe_new(msg->payload, msg->payloadSize);
+	if (payloadMsg == NULL) ret=false;
+
+	delay_first_send_for_late_joiners();
+
+	if( zframe_send(&headerMsg,zmq_socket, ZFRAME_MORE) == -1) ret=false;
+
+	if(!last){
+		if( zframe_send(&payloadMsg,zmq_socket, ZFRAME_MORE) == -1) ret=false;
+	}
+	else{
+		if( zframe_send(&payloadMsg,zmq_socket, 0) == -1) ret=false;
+	}
+
+	if (!ret){
+		zframe_destroy(&headerMsg);
+		zframe_destroy(&payloadMsg);
+	}
+
+	free(msg->header);
+	free(msg->payload);
+	free(msg);
+
+	return ret;
+
+}
+
+static bool send_pubsub_mp_msg(zsock_t* zmq_socket, array_list_pt mp_msg_parts){
+
+	bool ret = true;
+
+	unsigned int i = 0;
+	unsigned int mp_num = arrayList_size(mp_msg_parts);
+	for(;i<mp_num;i++){
+		ret = ret && send_pubsub_msg(zmq_socket, (pubsub_msg_pt)arrayList_get(mp_msg_parts,i), (i==mp_num-1));
+	}
+	arrayList_clear(mp_msg_parts);
+
+	return ret;
+
+}
+
+static int pubsub_topicPublicationSend(void* handle, unsigned int msgTypeId, void *msg) {
+
+	return pubsub_topicPublicationSendMultipart(handle,msgTypeId,msg, PUBSUB_PUBLISHER_FIRST_MSG | PUBSUB_PUBLISHER_LAST_MSG);
+
+}
+
+static int pubsub_topicPublicationSendMultipart(void *handle, unsigned int msgTypeId, void *msg, int flags){
+
+	int status = 0;
+
+	publish_bundle_bound_service_pt bound = (publish_bundle_bound_service_pt) handle;
+
+	celixThreadMutex_lock(&(bound->mp_lock));
+	if( (flags & PUBSUB_PUBLISHER_FIRST_MSG) && !(flags & PUBSUB_PUBLISHER_LAST_MSG) && bound->mp_send_in_progress){ //means a real mp_msg
+		printf("TP: Multipart send already in progress. Cannot process a new one.\n");
+		celixThreadMutex_unlock(&(bound->mp_lock));
+		return -3;
+	}
+
+	pubsub_message_type *msgType = hashMap_get(bound->msgTypes, &msgTypeId);
+
+	int major=0, minor=0;
+
+	if (msgType != NULL) {
+
+		version_pt msgVersion = pubsubSerializer_getVersion(msgType);
+
+		pubsub_msg_header_pt msg_hdr = calloc(1,sizeof(struct pubsub_msg_header));
+
+		strncpy(msg_hdr->topic,bound->topic,MAX_TOPIC_LEN-1);
+
+		msg_hdr->type = msgTypeId;
+		if (msgVersion != NULL){
+			version_getMajor(msgVersion, &major);
+			version_getMinor(msgVersion, &minor);
+			msg_hdr->major = major;
+			msg_hdr->minor = minor;
+		}
+
+		void* serializedOutput = NULL;
+		int serializedOutputLen = 0;
+		pubsubSerializer_serialize(msgType, msg, &serializedOutput, &serializedOutputLen);
+
+		pubsub_msg_pt msg = calloc(1,sizeof(struct pubsub_msg));
+		msg->header = msg_hdr;
+		msg->payload = (char *) serializedOutput;
+		msg->payloadSize = serializedOutputLen;
+
+		bool snd = true;
+
+		switch(flags){
+		case PUBSUB_PUBLISHER_FIRST_MSG:
+			bound->mp_send_in_progress = true;
+			arrayList_add(bound->mp_parts,msg);
+			break;
+		case PUBSUB_PUBLISHER_PART_MSG:
+			if(!bound->mp_send_in_progress){
+				printf("TP: ERROR: received msg part without the first part.\n");
+				status = -4;
+			}
+			else{
+				arrayList_add(bound->mp_parts,msg);
+			}
+			break;
+		case PUBSUB_PUBLISHER_LAST_MSG:
+			if(!bound->mp_send_in_progress){
+				printf("TP: ERROR: received end msg without the first part.\n");
+				status = -4;
+			}
+			else{
+				arrayList_add(bound->mp_parts,msg);
+				celixThreadMutex_lock(&(bound->parent->tp_lock));
+				snd = send_pubsub_mp_msg(bound->parent->zmq_socket,bound->mp_parts);
+				bound->mp_send_in_progress = false;
+				celixThreadMutex_unlock(&(bound->parent->tp_lock));
+			}
+			break;
+		case PUBSUB_PUBLISHER_FIRST_MSG | PUBSUB_PUBLISHER_LAST_MSG:	//Normal send case
+			celixThreadMutex_lock(&(bound->parent->tp_lock));
+			snd = send_pubsub_msg(bound->parent->zmq_socket,msg,true);
+			celixThreadMutex_unlock(&(bound->parent->tp_lock));
+			break;
+		default:
+			printf("TP: ERROR: Invalid MP flags combination\n");
+			status = -4;
+			break;
+		}
+
+		if(!snd){
+			printf("TP: Failed to send %s message %u.\n",flags == (PUBSUB_PUBLISHER_FIRST_MSG | PUBSUB_PUBLISHER_LAST_MSG) ? "single" : "multipart", msgTypeId);
+		}
+
+	} else {
+		printf("TP: Message %u not supported.",msgTypeId);
+		status=-1;
+	}
+
+	celixThreadMutex_unlock(&(bound->mp_lock));
+
+	return status;
+
+}
+
+static int pubsub_localMsgTypeIdForUUID(void* handle, const char* msgType, unsigned int* msgTypeId){
+	*msgTypeId = pubsubSerializer_hashCode(msgType);
+	return 0;
+}
+
+static unsigned int rand_range(unsigned int min, unsigned int max){
+
+	double scaled = (double)(((double)rand())/((double)RAND_MAX));
+	return (max-min+1)*scaled + min;
+
+}
+
+static publish_bundle_bound_service_pt pubsub_createPublishBundleBoundService(topic_publication_pt tp,bundle_pt bundle){
+
+	publish_bundle_bound_service_pt bound = calloc(1, sizeof(*bound));
+
+	if (bound != NULL) {
+		bound->service = calloc(1, sizeof(*bound->service));
+	}
+
+	if (bound != NULL && bound->service != NULL) {
+
+		bound->parent = tp;
+		bound->bundle = bundle;
+		bound->getCount = 1;
+		bound->mp_send_in_progress = false;
+		celixThreadMutex_create(&bound->mp_lock,NULL);
+		bound->msgTypes = hashMap_create(uintHash, NULL, uintEquals, NULL); //<int* (msgId),pubsub_message_type>
+		arrayList_create(&bound->mp_parts);
+
+		pubsub_endpoint_pt pubEP = (pubsub_endpoint_pt)arrayList_get(bound->parent->pub_ep_list,0);
+		bound->topic=strdup(pubEP->topic);
+
+		bound->service->handle = bound;
+		bound->service->localMsgTypeIdForMsgType = pubsub_localMsgTypeIdForUUID;
+		bound->service->send = pubsub_topicPublicationSend;
+		bound->service->sendMultipart = pubsub_topicPublicationSendMultipart;
+
+		pubsubSerializer_fillMsgTypesMap(bound->msgTypes,bound->bundle);
+
+	}
+	else
+	{
+		if (bound != NULL) {
+			free(bound->service);
+		}
+		free(bound);
+		return NULL;
+	}
+
+	return bound;
+}
+
+static void pubsub_destroyPublishBundleBoundService(publish_bundle_bound_service_pt boundSvc){
+
+	celixThreadMutex_lock(&boundSvc->mp_lock);
+
+	if(boundSvc->service != NULL){
+		free(boundSvc->service);
+	}
+
+	if(boundSvc->msgTypes != NULL){
+		pubsubSerializer_emptyMsgTypesMap(boundSvc->msgTypes);
+		hashMap_destroy(boundSvc->msgTypes,false,false);
+	}
+
+	if(boundSvc->mp_parts!=NULL){
+		arrayList_destroy(boundSvc->mp_parts);
+	}
+
+	if(boundSvc->topic!=NULL){
+		free(boundSvc->topic);
+	}
+
+	celixThreadMutex_unlock(&boundSvc->mp_lock);
+	celixThreadMutex_destroy(&boundSvc->mp_lock);
+
+	free(boundSvc);
+
+}
+
+static void delay_first_send_for_late_joiners(){
+
+	static bool firstSend = true;
+
+	if(firstSend){
+		printf("TP: Delaying first send for late joiners...\n");
+		sleep(FIRST_SEND_DELAY);
+		firstSend = false;
+	}
+}

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_admin_zmq/private/src/topic_subscription.c
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_admin_zmq/private/src/topic_subscription.c b/celix-pubsub/pubsub/pubsub_admin_zmq/private/src/topic_subscription.c
new file mode 100644
index 0000000..9e1a47d
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_admin_zmq/private/src/topic_subscription.c
@@ -0,0 +1,741 @@
+/**
+ *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.
+ */
+/*
+ * topic_subscription.c
+ *
+ *  \date       Oct 2, 2015
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#include "topic_subscription.h"
+#include <czmq.h>
+/* The following undefs prevent the collision between:
+ * - sys/syslog.h (which is included within czmq)
+ * - celix/dfi/dfi_log_util.h
+ */
+#undef LOG_DEBUG
+#undef LOG_WARNING
+#undef LOG_INFO
+#undef LOG_WARNING
+
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+
+#include "utils.h"
+#include "celix_errno.h"
+#include "constants.h"
+#include "version.h"
+
+#include "subscriber.h"
+#include "publisher.h"
+#include "dyn_msg_utils.h"
+#include "pubsub_utils.h"
+
+#include "pubsub_serializer.h"
+
+#ifdef USE_ZMQ_SECURITY
+	#include "zmq_crypto.h"
+
+	#define MAX_CERT_PATH_LENGTH 512
+#endif
+
+#define POLL_TIMEOUT  	250
+#define ZMQ_POLL_TIMEOUT_MS_ENV 	"ZMQ_POLL_TIMEOUT_MS"
+
+struct topic_subscription{
+
+	zsock_t* zmq_socket;
+	zcert_t * zmq_cert;
+	zcert_t * zmq_pub_cert;
+	pthread_mutex_t socket_lock;
+	service_tracker_pt tracker;
+	array_list_pt sub_ep_list;
+	celix_thread_t recv_thread;
+	bool running;
+	celix_thread_mutex_t ts_lock;
+	bundle_context_pt context;
+
+	hash_map_pt servicesMap; // key = service, value = msg types map
+	array_list_pt pendingConnections;
+	array_list_pt pendingDisconnections;
+
+	celix_thread_mutex_t pendingConnections_lock;
+	celix_thread_mutex_t pendingDisconnections_lock;
+	unsigned int nrSubscribers;
+};
+
+typedef struct complete_zmq_msg{
+	zframe_t* header;
+	zframe_t* payload;
+}* complete_zmq_msg_pt;
+
+typedef struct mp_handle{
+	hash_map_pt svc_msg_db;
+	hash_map_pt rcv_msg_map;
+}* mp_handle_pt;
+
+typedef struct msg_map_entry{
+	bool retain;
+	void* msgInst;
+}* msg_map_entry_pt;
+
+static celix_status_t topicsub_subscriberTracked(void * handle, service_reference_pt reference, void * service);
+static celix_status_t topicsub_subscriberUntracked(void * handle, service_reference_pt reference, void * service);
+static void* zmq_recv_thread_func(void* arg);
+static bool checkVersion(version_pt msgVersion,pubsub_msg_header_pt hdr);
+static void sigusr1_sighandler(int signo);
+static int pubsub_localMsgTypeIdForMsgType(void* handle, const char* msgType, unsigned int* msgTypeId);
+static int pubsub_getMultipart(void *handle, unsigned int msgTypeId, bool retain, void **part);
+static mp_handle_pt create_mp_handle(hash_map_pt svc_msg_db,array_list_pt rcv_msg_list);
+static void destroy_mp_handle(mp_handle_pt mp_handle);
+static void connectPendingPublishers(topic_subscription_pt sub);
+static void disconnectPendingPublishers(topic_subscription_pt sub);
+
+celix_status_t pubsub_topicSubscriptionCreate(bundle_context_pt bundle_context, char* scope, char* topic,topic_subscription_pt* out){
+	celix_status_t status = CELIX_SUCCESS;
+
+#ifdef USE_ZMQ_SECURITY
+	char* keys_bundle_dir = pubsub_getKeysBundleDir(bundle_context);
+	if (keys_bundle_dir == NULL){
+		return CELIX_SERVICE_EXCEPTION;
+	}
+
+	const char* keys_file_path = NULL;
+	const char* keys_file_name = NULL;
+	bundleContext_getProperty(bundle_context, PROPERTY_KEYS_FILE_PATH, &keys_file_path);
+	bundleContext_getProperty(bundle_context, PROPERTY_KEYS_FILE_NAME, &keys_file_name);
+
+	char sub_cert_path[MAX_CERT_PATH_LENGTH];
+	char pub_cert_path[MAX_CERT_PATH_LENGTH];
+
+	//certificate path ".cache/bundle{id}/version0.0/./META-INF/keys/subscriber/private/sub_{topic}.key.enc"
+	snprintf(sub_cert_path, MAX_CERT_PATH_LENGTH, "%s/META-INF/keys/subscriber/private/sub_%s.key.enc", keys_bundle_dir, topic);
+	snprintf(pub_cert_path, MAX_CERT_PATH_LENGTH, "%s/META-INF/keys/publisher/public/pub_%s.pub", keys_bundle_dir, topic);
+	free(keys_bundle_dir);
+
+	printf("PSA: Loading subscriber key '%s'\n", sub_cert_path);
+	printf("PSA: Loading publisher key '%s'\n", pub_cert_path);
+
+	zcert_t* sub_cert = get_zcert_from_encoded_file((char *) keys_file_path, (char *) keys_file_name, sub_cert_path);
+	if (sub_cert == NULL){
+		printf("PSA: Cannot load key '%s'\n", sub_cert_path);
+		return CELIX_SERVICE_EXCEPTION;
+	}
+
+	zcert_t* pub_cert = zcert_load(pub_cert_path);
+	if (pub_cert == NULL){
+		zcert_destroy(&sub_cert);
+		printf("PSA: Cannot load key '%s'\n", pub_cert_path);
+		return CELIX_SERVICE_EXCEPTION;
+	}
+
+	const char* pub_key = zcert_public_txt(pub_cert);
+#endif
+
+	zsock_t* zmq_s = zsock_new (ZMQ_SUB);
+	if(zmq_s==NULL){
+		#ifdef USE_ZMQ_SECURITY
+		zcert_destroy(&sub_cert);
+		zcert_destroy(&pub_cert);
+		#endif
+
+		return CELIX_SERVICE_EXCEPTION;
+	}
+
+	#ifdef USE_ZMQ_SECURITY
+	zcert_apply (sub_cert, zmq_s);
+	zsock_set_curve_serverkey (zmq_s, pub_key); //apply key of publisher to socket of subscriber
+	#endif
+
+	if(strcmp(topic,PUBSUB_ANY_SUB_TOPIC)==0){
+		zsock_set_subscribe (zmq_s, "");
+	}
+	else{
+		zsock_set_subscribe (zmq_s, topic);
+	}
+
+	topic_subscription_pt ts = (topic_subscription_pt) calloc(1,sizeof(*ts));
+	ts->context = bundle_context;
+	ts->zmq_socket = zmq_s;
+	ts->running = false;
+	ts->nrSubscribers = 0;
+
+	#ifdef USE_ZMQ_SECURITY
+	ts->zmq_cert = sub_cert;
+	ts->zmq_pub_cert = pub_cert;
+	#endif
+
+	celixThreadMutex_create(&ts->socket_lock, NULL);
+	celixThreadMutex_create(&ts->ts_lock,NULL);
+	arrayList_create(&ts->sub_ep_list);
+	ts->servicesMap = hashMap_create(NULL, NULL, NULL, NULL);
+	arrayList_create(&ts->pendingConnections);
+	arrayList_create(&ts->pendingDisconnections);
+	celixThreadMutex_create(&ts->pendingConnections_lock, NULL);
+	celixThreadMutex_create(&ts->pendingDisconnections_lock, NULL);
+
+	char filter[128];
+	memset(filter,0,128);
+	if(strncmp(PUBSUB_SUBSCRIBER_SCOPE_DEFAULT,scope,strlen(PUBSUB_SUBSCRIBER_SCOPE_DEFAULT)) == 0) {
+	        // default scope, means that subscriber has not defined a scope property
+	        snprintf(filter, 128, "(&(%s=%s)(%s=%s))",
+	                (char*) OSGI_FRAMEWORK_OBJECTCLASS, PUBSUB_SUBSCRIBER_SERVICE_NAME,
+	                PUBSUB_SUBSCRIBER_TOPIC,topic);
+
+	} else {
+        snprintf(filter, 128, "(&(%s=%s)(%s=%s)(%s=%s))",
+                (char*) OSGI_FRAMEWORK_OBJECTCLASS, PUBSUB_SUBSCRIBER_SERVICE_NAME,
+                PUBSUB_SUBSCRIBER_TOPIC,topic,
+                PUBSUB_SUBSCRIBER_SCOPE,scope);
+    }
+	service_tracker_customizer_pt customizer = NULL;
+	status += serviceTrackerCustomizer_create(ts,NULL,topicsub_subscriberTracked,NULL,topicsub_subscriberUntracked,&customizer);
+	status += serviceTracker_createWithFilter(bundle_context, filter, customizer, &ts->tracker);
+
+	struct sigaction actions;
+	memset(&actions, 0, sizeof(actions));
+	sigemptyset(&actions.sa_mask);
+	actions.sa_flags = 0;
+	actions.sa_handler = sigusr1_sighandler;
+
+	sigaction(SIGUSR1,&actions,NULL);
+
+	*out=ts;
+
+	return status;
+}
+
+celix_status_t pubsub_topicSubscriptionDestroy(topic_subscription_pt ts){
+	celix_status_t status = CELIX_SUCCESS;
+
+	celixThreadMutex_lock(&ts->ts_lock);
+
+	ts->running = false;
+	serviceTracker_destroy(ts->tracker);
+	arrayList_clear(ts->sub_ep_list);
+	arrayList_destroy(ts->sub_ep_list);
+	hashMap_destroy(ts->servicesMap,false,false);
+
+	celixThreadMutex_lock(&ts->pendingConnections_lock);
+	arrayList_destroy(ts->pendingConnections);
+	celixThreadMutex_unlock(&ts->pendingConnections_lock);
+	celixThreadMutex_destroy(&ts->pendingConnections_lock);
+
+	celixThreadMutex_lock(&ts->pendingDisconnections_lock);
+	arrayList_destroy(ts->pendingDisconnections);
+	celixThreadMutex_unlock(&ts->pendingDisconnections_lock);
+	celixThreadMutex_destroy(&ts->pendingDisconnections_lock);
+
+	celixThreadMutex_lock(&ts->socket_lock);
+	zsock_destroy(&(ts->zmq_socket));
+	#ifdef USE_ZMQ_SECURITY
+	zcert_destroy(&(ts->zmq_cert));
+	zcert_destroy(&(ts->zmq_pub_cert));
+	#endif
+	celixThreadMutex_unlock(&ts->socket_lock);
+	celixThreadMutex_destroy(&ts->socket_lock);
+
+	celixThreadMutex_unlock(&ts->ts_lock);
+
+
+	free(ts);
+
+	return status;
+}
+
+celix_status_t pubsub_topicSubscriptionStart(topic_subscription_pt ts){
+	celix_status_t status = CELIX_SUCCESS;
+
+	//celixThreadMutex_lock(&ts->ts_lock);
+
+	status = serviceTracker_open(ts->tracker);
+
+	ts->running = true;
+
+	if(status==CELIX_SUCCESS){
+		status=celixThread_create(&ts->recv_thread,NULL,zmq_recv_thread_func,ts);
+	}
+
+	//celixThreadMutex_unlock(&ts->ts_lock);
+
+	return status;
+}
+
+celix_status_t pubsub_topicSubscriptionStop(topic_subscription_pt ts){
+	celix_status_t status = CELIX_SUCCESS;
+
+	//celixThreadMutex_lock(&ts->ts_lock);
+
+	ts->running = false;
+
+	pthread_kill(ts->recv_thread.thread,SIGUSR1);
+
+	celixThread_join(ts->recv_thread,NULL);
+
+	status = serviceTracker_close(ts->tracker);
+
+	//celixThreadMutex_unlock(&ts->ts_lock);
+
+	return status;
+}
+
+celix_status_t pubsub_topicSubscriptionConnectPublisher(topic_subscription_pt ts, char* pubURL){
+	celix_status_t status = CELIX_SUCCESS;
+	celixThreadMutex_lock(&ts->socket_lock);
+	if(!zsock_is(ts->zmq_socket) || zsock_connect(ts->zmq_socket,pubURL) != 0){
+		status = CELIX_SERVICE_EXCEPTION;
+	}
+	celixThreadMutex_unlock(&ts->socket_lock);
+
+	return status;
+}
+
+celix_status_t pubsub_topicSubscriptionAddConnectPublisherToPendingList(topic_subscription_pt ts, char* pubURL) {
+    celix_status_t status = CELIX_SUCCESS;
+    char *url = strdup(pubURL);
+    celixThreadMutex_lock(&ts->pendingConnections_lock);
+    arrayList_add(ts->pendingConnections, url);
+    celixThreadMutex_unlock(&ts->pendingConnections_lock);
+    return status;
+}
+
+celix_status_t pubsub_topicSubscriptionAddDisconnectPublisherToPendingList(topic_subscription_pt ts, char* pubURL) {
+     celix_status_t status = CELIX_SUCCESS;
+    char *url = strdup(pubURL);
+    celixThreadMutex_lock(&ts->pendingDisconnections_lock);
+    arrayList_add(ts->pendingDisconnections, url);
+    celixThreadMutex_unlock(&ts->pendingDisconnections_lock);
+    return status;
+}
+
+celix_status_t pubsub_topicSubscriptionDisconnectPublisher(topic_subscription_pt ts, char* pubURL){
+	celix_status_t status = CELIX_SUCCESS;
+
+	celixThreadMutex_lock(&ts->socket_lock);
+	if(!zsock_is(ts->zmq_socket) || zsock_disconnect(ts->zmq_socket,pubURL) != 0){
+		status = CELIX_SERVICE_EXCEPTION;
+	}
+	celixThreadMutex_unlock(&ts->socket_lock);
+
+	return status;
+}
+
+celix_status_t pubsub_topicSubscriptionAddSubscriber(topic_subscription_pt ts, pubsub_endpoint_pt subEP){
+	celix_status_t status = CELIX_SUCCESS;
+
+	celixThreadMutex_lock(&ts->ts_lock);
+
+	arrayList_add(ts->sub_ep_list,subEP);
+
+	celixThreadMutex_unlock(&ts->ts_lock);
+
+	return status;
+
+}
+
+celix_status_t pubsub_topicIncreaseNrSubscribers(topic_subscription_pt ts) {
+	celix_status_t status = CELIX_SUCCESS;
+
+	celixThreadMutex_lock(&ts->ts_lock);
+
+	ts->nrSubscribers++;
+
+	celixThreadMutex_unlock(&ts->ts_lock);
+
+	return status;
+}
+
+celix_status_t pubsub_topicSubscriptionRemoveSubscriber(topic_subscription_pt ts, pubsub_endpoint_pt subEP){
+	celix_status_t status = CELIX_SUCCESS;
+
+	celixThreadMutex_lock(&ts->ts_lock);
+
+	arrayList_removeElement(ts->sub_ep_list,subEP);
+
+	celixThreadMutex_unlock(&ts->ts_lock);
+
+	return status;
+
+}
+
+celix_status_t pubsub_topicDecreaseNrSubscribers(topic_subscription_pt ts) {
+	celix_status_t status = CELIX_SUCCESS;
+
+	celixThreadMutex_lock(&ts->ts_lock);
+
+	ts->nrSubscribers--;
+
+	celixThreadMutex_unlock(&ts->ts_lock);
+
+	return status;
+}
+
+unsigned int pubsub_topicGetNrSubscribers(topic_subscription_pt ts) {
+	return ts->nrSubscribers;
+}
+
+static celix_status_t topicsub_subscriberTracked(void * handle, service_reference_pt reference, void * service){
+	celix_status_t status = CELIX_SUCCESS;
+	topic_subscription_pt ts = handle;
+
+	celixThreadMutex_lock(&ts->ts_lock);
+	if (!hashMap_containsKey(ts->servicesMap, service)) {
+		hash_map_pt msgTypes = hashMap_create(uintHash, NULL, uintEquals, NULL); //key = msgId, value = pubsub_message_type
+
+		bundle_pt bundle = NULL;
+		serviceReference_getBundle(reference, &bundle);
+		pubsubSerializer_fillMsgTypesMap(msgTypes,bundle);
+
+		if(hashMap_size(msgTypes)==0){ //If the msgTypes hashMap is not filled, the service is an unsupported subscriber
+			hashMap_destroy(msgTypes,false,false);
+			printf("TS: Unsupported subscriber!\n");
+		}
+		else{
+			hashMap_put(ts->servicesMap, service, msgTypes);
+		}
+
+	}
+	celixThreadMutex_unlock(&ts->ts_lock);
+	printf("TS: New subscriber registered.\n");
+	return status;
+
+}
+
+static celix_status_t topicsub_subscriberUntracked(void * handle, service_reference_pt reference, void * service){
+	celix_status_t status = CELIX_SUCCESS;
+	topic_subscription_pt ts = handle;
+
+	celixThreadMutex_lock(&ts->ts_lock);
+	if (hashMap_containsKey(ts->servicesMap, service)) {
+		hash_map_pt msgTypes = hashMap_remove(ts->servicesMap, service);
+		if(msgTypes!=NULL){
+			pubsubSerializer_emptyMsgTypesMap(msgTypes);
+			hashMap_destroy(msgTypes,false,false);
+		}
+	}
+	celixThreadMutex_unlock(&ts->ts_lock);
+
+	printf("TS: Subscriber unregistered.\n");
+	return status;
+}
+
+
+static void process_msg(topic_subscription_pt sub,array_list_pt msg_list){
+
+	pubsub_msg_header_pt first_msg_hdr = (pubsub_msg_header_pt)zframe_data(((complete_zmq_msg_pt)arrayList_get(msg_list,0))->header);
+
+	hash_map_iterator_pt iter = hashMapIterator_create(sub->servicesMap);
+	while (hashMapIterator_hasNext(iter)) {
+		hash_map_entry_pt entry = hashMapIterator_nextEntry(iter);
+		pubsub_subscriber_pt subsvc = hashMapEntry_getKey(entry);
+		hash_map_pt msgTypes = hashMapEntry_getValue(entry);
+
+		pubsub_message_type *msgType = hashMap_get(msgTypes,&(first_msg_hdr->type));
+		if (msgType == NULL) {
+			printf("TS: Primary message %d not supported. NOT sending any part of the whole message.\n",first_msg_hdr->type);
+		}
+		else{
+			void *msgInst = NULL;
+			char *name = pubsubSerializer_getName(msgType);
+			version_pt msgVersion = pubsubSerializer_getVersion(msgType);
+
+			bool validVersion = checkVersion(msgVersion,first_msg_hdr);
+
+			if(validVersion){
+
+				int rc = pubsubSerializer_deserialize(msgType, (const void *) zframe_data(((complete_zmq_msg_pt)arrayList_get(msg_list,0))->payload), &msgInst);
+
+				if (rc != -1) {
+					bool release = true;
+
+					mp_handle_pt mp_handle = create_mp_handle(msgTypes,msg_list);
+					pubsub_multipart_callbacks_t mp_callbacks;
+					mp_callbacks.handle = mp_handle;
+					mp_callbacks.localMsgTypeIdForMsgType = pubsub_localMsgTypeIdForMsgType;
+					mp_callbacks.getMultipart = pubsub_getMultipart;
+					subsvc->receive(subsvc->handle, name, first_msg_hdr->type, msgInst, &mp_callbacks, &release);
+
+					if(release){
+						pubsubSerializer_freeMsg(msgType, msgInst);
+					}
+					if(mp_handle!=NULL){
+						destroy_mp_handle(mp_handle);
+					}
+				}
+				else{
+					printf("TS: Cannot deserialize msgType %s.\n",name);
+				}
+
+			}
+			else{
+				int major=0,minor=0;
+				version_getMajor(msgVersion,&major);
+				version_getMinor(msgVersion,&minor);
+				printf("TS: Version mismatch for primary message '%s' (have %d.%d, received %u.%u). NOT sending any part of the whole message.\n",name,major,minor,first_msg_hdr->major,first_msg_hdr->minor);
+			}
+
+		}
+	}
+	hashMapIterator_destroy(iter);
+
+	int i = 0;
+	for(;i<arrayList_size(msg_list);i++){
+		complete_zmq_msg_pt c_msg = arrayList_get(msg_list,i);
+		zframe_destroy(&(c_msg->header));
+		zframe_destroy(&(c_msg->payload));
+		free(c_msg);
+	}
+
+	arrayList_destroy(msg_list);
+
+}
+
+static void* zmq_recv_thread_func(void * arg) {
+    topic_subscription_pt sub = (topic_subscription_pt) arg;
+
+    while (sub->running) {
+
+        celixThreadMutex_lock(&sub->socket_lock);
+
+        zframe_t* headerMsg = zframe_recv(sub->zmq_socket);
+        if (headerMsg == NULL) {
+            if (errno == EINTR) {
+                //It means we got a signal and we have to exit...
+                printf("TS: header_recv thread for topic got a signal and will exit.\n");
+            } else {
+                perror("TS: header_recv thread");
+            }
+        } else {
+
+			pubsub_msg_header_pt hdr = (pubsub_msg_header_pt) zframe_data(headerMsg);
+
+			if (zframe_more(headerMsg)) {
+
+				zframe_t* payloadMsg = zframe_recv(sub->zmq_socket);
+				if (payloadMsg == NULL) {
+					if (errno == EINTR) {
+						//It means we got a signal and we have to exit...
+						printf("TS: payload_recv thread for topic got a signal and will exit.\n");
+					} else {
+						perror("TS: payload_recv");
+					}
+					zframe_destroy(&headerMsg);
+				} else {
+
+					celixThreadMutex_lock(&sub->ts_lock);
+
+					//Let's fetch all the messages from the socket
+					array_list_pt msg_list = NULL;
+					arrayList_create(&msg_list);
+					complete_zmq_msg_pt firstMsg = calloc(1, sizeof(struct complete_zmq_msg));
+					firstMsg->header = headerMsg;
+					firstMsg->payload = payloadMsg;
+					arrayList_add(msg_list, firstMsg);
+
+					bool more = zframe_more(payloadMsg);
+					while (more) {
+
+						zframe_t* h_msg = zframe_recv(sub->zmq_socket);
+						if (h_msg == NULL) {
+							if (errno == EINTR) {
+								//It means we got a signal and we have to exit...
+								printf("TS: h_recv thread for topic got a signal and will exit.\n");
+							} else {
+								perror("TS: h_recv");
+							}
+							break;
+						}
+
+						zframe_t* p_msg = zframe_recv(sub->zmq_socket);
+						if (p_msg == NULL) {
+							if (errno == EINTR) {
+								//It means we got a signal and we have to exit...
+								printf("TS: p_recv thread for topic got a signal and will exit.\n");
+							} else {
+								perror("TS: p_recv");
+							}
+							zframe_destroy(&h_msg);
+							break;
+						}
+
+						complete_zmq_msg_pt c_msg = calloc(1, sizeof(struct complete_zmq_msg));
+						c_msg->header = h_msg;
+						c_msg->payload = p_msg;
+						arrayList_add(msg_list, c_msg);
+
+						if (!zframe_more(p_msg)) {
+							more = false;
+						}
+					}
+
+					process_msg(sub, msg_list);
+
+					celixThreadMutex_unlock(&sub->ts_lock);
+
+				}
+
+			} //zframe_more(headerMsg)
+			else {
+				free(headerMsg);
+				printf("TS: received message %u for topic %s without payload!\n", hdr->type, hdr->topic);
+			}
+
+        } // headerMsg != NULL
+        celixThreadMutex_unlock(&sub->socket_lock);
+        connectPendingPublishers(sub);
+        disconnectPendingPublishers(sub);
+    } // while
+
+    return NULL;
+}
+
+static void connectPendingPublishers(topic_subscription_pt sub) {
+	celixThreadMutex_lock(&sub->pendingConnections_lock);
+	while(!arrayList_isEmpty(sub->pendingConnections)) {
+		char * pubEP = arrayList_remove(sub->pendingConnections, 0);
+		pubsub_topicSubscriptionConnectPublisher(sub, pubEP);
+		free(pubEP);
+	}
+	celixThreadMutex_unlock(&sub->pendingConnections_lock);
+}
+
+static void disconnectPendingPublishers(topic_subscription_pt sub) {
+	celixThreadMutex_lock(&sub->pendingDisconnections_lock);
+	while(!arrayList_isEmpty(sub->pendingDisconnections)) {
+		char * pubEP = arrayList_remove(sub->pendingDisconnections, 0);
+		pubsub_topicSubscriptionDisconnectPublisher(sub, pubEP);
+		free(pubEP);
+	}
+	celixThreadMutex_unlock(&sub->pendingDisconnections_lock);
+}
+
+static void sigusr1_sighandler(int signo){
+	printf("TS: Topic subscription being shut down...\n");
+	return;
+}
+
+static bool checkVersion(version_pt msgVersion,pubsub_msg_header_pt hdr){
+	bool check=false;
+	int major=0,minor=0;
+
+	if(msgVersion!=NULL){
+		version_getMajor(msgVersion,&major);
+		version_getMinor(msgVersion,&minor);
+		if(hdr->major==((unsigned char)major)){ /* Different major means incompatible */
+			check = (hdr->minor>=((unsigned char)minor)); /* Compatible only if the provider has a minor equals or greater (means compatible update) */
+		}
+	}
+
+	return check;
+}
+
+static int pubsub_localMsgTypeIdForMsgType(void* handle, const char* msgType, unsigned int* msgTypeId){
+	*msgTypeId = pubsubSerializer_hashCode(msgType);
+	return 0;
+}
+
+static int pubsub_getMultipart(void *handle, unsigned int msgTypeId, bool retain, void **part){
+
+	if(handle==NULL){
+		*part = NULL;
+		return -1;
+	}
+
+	mp_handle_pt mp_handle = (mp_handle_pt)handle;
+	msg_map_entry_pt entry = hashMap_get(mp_handle->rcv_msg_map,&msgTypeId);
+	if(entry!=NULL){
+		entry->retain = retain;
+		*part = entry->msgInst;
+	}
+	else{
+		printf("TP: getMultipart cannot find msg '%u'\n",msgTypeId);
+		*part=NULL;
+		return -2;
+	}
+
+	return 0;
+
+}
+
+static mp_handle_pt create_mp_handle(hash_map_pt svc_msg_db,array_list_pt rcv_msg_list){
+
+	if(arrayList_size(rcv_msg_list)==1){ //Means it's not a multipart message
+		return NULL;
+	}
+
+	mp_handle_pt mp_handle = calloc(1,sizeof(struct mp_handle));
+	mp_handle->svc_msg_db = svc_msg_db;
+	mp_handle->rcv_msg_map = hashMap_create(uintHash, NULL, uintEquals, NULL);
+
+	int i=1; //We skip the first message, it will be handle differently
+	for(;i<arrayList_size(rcv_msg_list);i++){
+		complete_zmq_msg_pt c_msg = (complete_zmq_msg_pt)arrayList_get(rcv_msg_list,i);
+
+		pubsub_msg_header_pt header = (pubsub_msg_header_pt)zframe_data(c_msg->header);
+
+		pubsub_message_type *msgType = hashMap_get(svc_msg_db,&(header->type));
+		if (msgType != NULL) {
+			void *msgInst = NULL;
+			version_pt msgVersion = pubsubSerializer_getVersion(msgType);
+
+			bool validVersion = checkVersion(msgVersion,header);
+
+			if(validVersion){
+				int rc = pubsubSerializer_deserialize(msgType, (const void *) zframe_data(c_msg->payload), &msgInst);
+
+				if(rc != -1){
+					unsigned int* msgId = calloc(1,sizeof(unsigned int));
+					*msgId = header->type;
+					msg_map_entry_pt entry = calloc(1,sizeof(struct msg_map_entry));
+					entry->msgInst = msgInst;
+					hashMap_put(mp_handle->rcv_msg_map,msgId,entry);
+				}
+			}
+		}
+
+	}
+
+	return mp_handle;
+
+}
+
+static void destroy_mp_handle(mp_handle_pt mp_handle){
+
+	hash_map_iterator_pt iter = hashMapIterator_create(mp_handle->rcv_msg_map);
+	while(hashMapIterator_hasNext(iter)){
+		hash_map_entry_pt entry = hashMapIterator_nextEntry(iter);
+		unsigned int* msgId = (unsigned int*)hashMapEntry_getKey(entry);
+		msg_map_entry_pt msgEntry = hashMapEntry_getValue(entry);
+		pubsub_message_type* msgType = hashMap_get(mp_handle->svc_msg_db,msgId);
+		if(msgType!=NULL){
+			if(!msgEntry->retain){
+				free(msgEntry->msgInst);
+			}
+		}
+		else{
+			printf("TS: ERROR: Cannot find pubsub_message_type for msg %u, so cannot destroy it!\n",*msgId);
+		}
+	}
+	hashMapIterator_destroy(iter);
+
+	hashMap_destroy(mp_handle->rcv_msg_map,true,true);
+	free(mp_handle);
+}

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_admin_zmq/private/src/zmq_crypto.c
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_admin_zmq/private/src/zmq_crypto.c b/celix-pubsub/pubsub/pubsub_admin_zmq/private/src/zmq_crypto.c
new file mode 100644
index 0000000..fe444bd
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_admin_zmq/private/src/zmq_crypto.c
@@ -0,0 +1,281 @@
+/**
+ *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.
+ */
+/*
+ * zmq_crypto.c
+ *
+ *  \date       Dec 2, 2016
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#include "zmq_crypto.h"
+
+#include <zmq.h>
+#include <openssl/conf.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+
+#include <string.h>
+
+#define MAX_FILE_PATH_LENGTH 512
+#define ZMQ_KEY_LENGTH 40
+#define AES_KEY_LENGTH 32
+#define AES_IV_LENGTH 16
+
+#define KEY_TO_GET "aes_key"
+#define IV_TO_GET "aes_iv"
+
+static char* read_file_content(char* filePath, char* fileName);
+static void parse_key_lines(char *keysBuffer, char **key, char **iv);
+static void parse_key_line(char *line, char **key, char **iv);
+static void extract_keys_from_buffer(unsigned char *input, int inputlen, char **publicKey, char **secretKey);
+
+/**
+ * Return a valid zcert_t from an encoded file
+ * Caller is responsible for freeing by calling zcert_destroy(zcert** cert);
+ */
+zcert_t* get_zcert_from_encoded_file(char* keysFilePath, char* keysFileName, char* file_path)
+{
+
+	if (keysFilePath == NULL){
+		keysFilePath = DEFAULT_KEYS_FILE_PATH;
+	}
+
+	if (keysFileName == NULL){
+		keysFileName = DEFAULT_KEYS_FILE_NAME;
+	}
+
+	char* keys_data = read_file_content(keysFilePath, keysFileName);
+	if (keys_data == NULL){
+		return NULL;
+	}
+
+	char *key = NULL;
+	char *iv = NULL;
+	parse_key_lines(keys_data, &key, &iv);
+	free(keys_data);
+
+	if (key == NULL || iv == NULL){
+		free(key);
+		free(iv);
+
+		printf("CRYPTO: Loading AES key and/or AES iv failed!\n");
+		return NULL;
+	}
+
+	//At this point, we know an aes key and iv are stored and loaded
+
+	// generate sha256 hashes
+	unsigned char key_digest[EVP_MAX_MD_SIZE];
+	unsigned char iv_digest[EVP_MAX_MD_SIZE];
+	generate_sha256_hash((char*) key, key_digest);
+	generate_sha256_hash((char*) iv, iv_digest);
+
+	zchunk_t* encoded_secret = zchunk_slurp (file_path, 0);
+	if (encoded_secret == NULL){
+		free(key);
+		free(iv);
+
+		return NULL;
+	}
+
+	int encoded_secret_size = (int) zchunk_size (encoded_secret);
+	char* encoded_secret_data = zchunk_strdup(encoded_secret);
+	zchunk_destroy (&encoded_secret);
+
+	// Decryption of data
+	int decryptedtext_len;
+	unsigned char decryptedtext[encoded_secret_size];
+	decryptedtext_len = decrypt((unsigned char *) encoded_secret_data, encoded_secret_size, key_digest, iv_digest, decryptedtext);
+	decryptedtext[decryptedtext_len] = '\0';
+
+	EVP_cleanup();
+
+	free(encoded_secret_data);
+	free(key);
+	free(iv);
+
+	// The public and private keys are retrieved
+	char* public_text = NULL;
+	char* secret_text = NULL;
+
+	extract_keys_from_buffer(decryptedtext, decryptedtext_len, &public_text, &secret_text);
+
+	byte public_key [32] = { 0 };
+	byte secret_key [32] = { 0 };
+
+	zmq_z85_decode (public_key, public_text);
+	zmq_z85_decode (secret_key, secret_text);
+
+	zcert_t* cert_loaded = zcert_new_from(public_key, secret_key);
+
+	free(public_text);
+	free(secret_text);
+
+	return cert_loaded;
+}
+
+int generate_sha256_hash(char* text, unsigned char* digest)
+{
+	unsigned int digest_len;
+
+	EVP_MD_CTX * mdctx = EVP_MD_CTX_new();
+	EVP_DigestInit_ex(mdctx, EVP_sha256(), NULL);
+	EVP_DigestUpdate(mdctx, text, strlen(text));
+	EVP_DigestFinal_ex(mdctx, digest, &digest_len);
+	EVP_MD_CTX_free(mdctx);
+
+	return digest_len;
+}
+
+int decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key, unsigned char *iv, unsigned char *plaintext)
+{
+	int len;
+	int plaintext_len;
+
+	EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
+
+	EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv);
+	EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len);
+	plaintext_len = len;
+	EVP_DecryptFinal_ex(ctx, plaintext + len, &len);
+	plaintext_len += len;
+
+	EVP_CIPHER_CTX_free(ctx);
+
+	return plaintext_len;
+}
+
+/**
+ * Caller is responsible for freeing the returned value
+ */
+static char* read_file_content(char* filePath, char* fileName){
+
+	char fileNameWithPath[MAX_FILE_PATH_LENGTH];
+	snprintf(fileNameWithPath, MAX_FILE_PATH_LENGTH, "%s/%s", filePath, fileName);
+	int rc = 0;
+
+	if (!zsys_file_exists(fileNameWithPath)){
+		printf("CRYPTO: Keys file '%s' doesn't exist!\n", fileNameWithPath);
+		return NULL;
+	}
+
+	zfile_t* keys_file = zfile_new (filePath, fileName);
+	rc = zfile_input (keys_file);
+	if (rc != 0){
+		zfile_destroy(&keys_file);
+		printf("CRYPTO: Keys file '%s' not readable!\n", fileNameWithPath);
+		return NULL;
+	}
+
+	ssize_t keys_file_size = zsys_file_size (fileNameWithPath);
+	zchunk_t* keys_chunk = zfile_read (keys_file, keys_file_size, 0);
+	if (keys_chunk == NULL){
+		zfile_close(keys_file);
+		zfile_destroy(&keys_file);
+		printf("CRYPTO: Can't read file '%s'!\n", fileNameWithPath);
+		return NULL;
+	}
+
+	char* keys_data = zchunk_strdup(keys_chunk);
+	zchunk_destroy(&keys_chunk);
+	zfile_close(keys_file);
+	zfile_destroy (&keys_file);
+
+	return keys_data;
+}
+
+static void parse_key_lines(char *keysBuffer, char **key, char **iv){
+	char *line = NULL, *saveLinePointer = NULL;
+
+	bool firstTime = true;
+	do {
+		if (firstTime){
+			line = strtok_r(keysBuffer, "\n", &saveLinePointer);
+			firstTime = false;
+		}else {
+			line = strtok_r(NULL, "\n", &saveLinePointer);
+		}
+
+		if (line == NULL){
+			break;
+		}
+
+		parse_key_line(line, key, iv);
+
+	} while((*key == NULL || *iv == NULL) && line != NULL);
+
+}
+
+static void parse_key_line(char *line, char **key, char **iv){
+	char *detectedKey = NULL, *detectedValue= NULL;
+
+	char* sep_at = strchr(line, ':');
+	if (sep_at == NULL){
+		return;
+	}
+
+	*sep_at = '\0'; // overwrite first separator, creating two strings.
+	detectedKey = line;
+	detectedValue = sep_at + 1;
+
+	if (detectedKey == NULL || detectedValue == NULL){
+		return;
+	}
+	if (detectedKey[0] == '\0' || detectedValue[0] == '\0'){
+		return;
+	}
+
+	if (*key == NULL && strcmp(detectedKey, KEY_TO_GET) == 0){
+		*key = strndup(detectedValue, AES_KEY_LENGTH);
+	} else if (*iv == NULL && strcmp(detectedKey, IV_TO_GET) == 0){
+		*iv = strndup(detectedValue, AES_IV_LENGTH);
+	}
+}
+
+static void extract_keys_from_buffer(unsigned char *input, int inputlen, char **publicKey, char **secretKey) {
+	// Load decrypted text buffer
+	zchunk_t* secret_decrypted = zchunk_new(input, inputlen);
+	if (secret_decrypted == NULL){
+		printf("CRYPTO: Failed to create zchunk\n");
+		return;
+	}
+
+	zconfig_t* secret_config = zconfig_chunk_load (secret_decrypted);
+	zchunk_destroy (&secret_decrypted);
+	if (secret_config == NULL){
+		printf("CRYPTO: Failed to create zconfig\n");
+		return;
+	}
+
+	// Extract public and secret key from text buffer
+	char* public_text = zconfig_get (secret_config, "/curve/public-key", NULL);
+	char* secret_text = zconfig_get (secret_config, "/curve/secret-key", NULL);
+
+	if (public_text == NULL || secret_text == NULL){
+		zconfig_destroy(&secret_config);
+		printf("CRYPTO: Loading public / secret key from text-buffer failed!\n");
+		return;
+	}
+
+	*publicKey = strndup(public_text, ZMQ_KEY_LENGTH + 1);
+	*secretKey = strndup(secret_text, ZMQ_KEY_LENGTH + 1);
+
+	zconfig_destroy(&secret_config);
+}

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_common/public/include/dyn_msg_utils.h
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_common/public/include/dyn_msg_utils.h b/celix-pubsub/pubsub/pubsub_common/public/include/dyn_msg_utils.h
new file mode 100644
index 0000000..71085ab
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_common/public/include/dyn_msg_utils.h
@@ -0,0 +1,39 @@
+/**
+ *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.
+ */
+/*
+ * dyn_msg_utils.h
+ *
+ *  \date       Nov 11, 2015
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#ifndef DYN_MSG_UTILS_H_
+#define DYN_MSG_UTILS_H_
+
+#include "bundle.h"
+#include "hash_map.h"
+
+unsigned int uintHash(const void * uintNum);
+int uintEquals(const void * uintNum, const void * toCompare);
+
+void fillMsgTypesMap(hash_map_pt msgTypesMap,bundle_pt bundle);
+void emptyMsgTypesMap(hash_map_pt msgTypesMap);
+
+#endif /* DYN_MSG_UTILS_H_ */

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_common/public/include/etcd.h
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_common/public/include/etcd.h b/celix-pubsub/pubsub/pubsub_common/public/include/etcd.h
new file mode 100644
index 0000000..a502df4
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_common/public/include/etcd.h
@@ -0,0 +1,39 @@
+/**
+ *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.
+ */
+
+#ifndef ETCD_H_
+#define ETCD_H_
+
+#include <stdbool.h>
+
+typedef void (*etcd_key_value_callback) (const char *key, const char *value, void* arg);
+
+int etcd_init(const char* server, int port);
+
+int etcd_get(const char* key, char** value, int* modifiedIndex);
+int etcd_get_directory(const char* directory, etcd_key_value_callback callback, void *arg, long long* modifiedIndex);
+
+int etcd_set(const char* key, const char* value, int ttl, bool prevExist);
+int etcd_set_with_check(const char* key, const char* value, int ttl, bool always_write);
+
+int etcd_del(const char* key);
+
+int etcd_watch(const char* key, long long index, char** action, char** prevValue, char** value, char** rkey, long long* modifiedIndex);
+
+#endif /* ETCD_H_ */

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_common/public/include/publisher_endpoint_announce.h
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_common/public/include/publisher_endpoint_announce.h b/celix-pubsub/pubsub/pubsub_common/public/include/publisher_endpoint_announce.h
new file mode 100644
index 0000000..bd39fc0
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_common/public/include/publisher_endpoint_announce.h
@@ -0,0 +1,36 @@
+/**
+ *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.
+ */
+
+#ifndef PUBLISHER_ENDPOINT_ANNOUNCE_H_
+#define PUBLISHER_ENDPOINT_ANNOUNCE_H_
+
+#include "pubsub_endpoint.h"
+
+struct publisher_endpoint_announce {
+	void *handle;
+	celix_status_t (*announcePublisher)(void *handle, pubsub_endpoint_pt pubEP);
+	celix_status_t (*removePublisher)(void *handle, pubsub_endpoint_pt pubEP);
+	celix_status_t (*interestedInTopic)(void* handle, const char *scope, const char *topic);
+	celix_status_t (*uninterestedInTopic)(void* handle, const char *scope, const char *topic);
+};
+
+typedef struct publisher_endpoint_announce *publisher_endpoint_announce_pt;
+
+
+#endif /* PUBLISHER_ENDPOINT_ANNOUNCE_H_ */

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_common/public/include/pubsub_admin.h
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_common/public/include/pubsub_admin.h b/celix-pubsub/pubsub/pubsub_common/public/include/pubsub_admin.h
new file mode 100644
index 0000000..1670942
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_common/public/include/pubsub_admin.h
@@ -0,0 +1,56 @@
+/**
+ *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.
+ */
+/*
+ * pubsub_admin.h
+ *
+ *  \date       Sep 30, 2011
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#ifndef PUBSUB_ADMIN_H_
+#define PUBSUB_ADMIN_H_
+
+#include "service_reference.h"
+
+#include "pubsub_common.h"
+#include "pubsub_endpoint.h"
+
+#define PSA_IP 	"PSA_IP"
+#define PSA_ITF	"PSA_INTERFACE"
+#define PSA_MULTICAST_IP_PREFIX "PSA_MC_PREFIX"
+
+typedef struct pubsub_admin *pubsub_admin_pt;
+
+struct pubsub_admin_service {
+	pubsub_admin_pt admin;
+
+	celix_status_t (*addSubscription)(pubsub_admin_pt admin,pubsub_endpoint_pt subEP);
+	celix_status_t (*removeSubscription)(pubsub_admin_pt admin,pubsub_endpoint_pt subEP);
+
+	celix_status_t (*addPublication)(pubsub_admin_pt admin,pubsub_endpoint_pt subEP);
+	celix_status_t (*removePublication)(pubsub_admin_pt admin,pubsub_endpoint_pt subEP);
+
+	celix_status_t (*closeAllPublications)(pubsub_admin_pt admin,char* scope, char* topic);
+	celix_status_t (*closeAllSubscriptions)(pubsub_admin_pt admin,char* scope, char* topic);
+};
+
+typedef struct pubsub_admin_service *pubsub_admin_service_pt;
+
+#endif /* PUBSUB_ADMIN_H_ */

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_common/public/include/pubsub_common.h
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_common/public/include/pubsub_common.h b/celix-pubsub/pubsub/pubsub_common/public/include/pubsub_common.h
new file mode 100644
index 0000000..d9c6f1d
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_common/public/include/pubsub_common.h
@@ -0,0 +1,51 @@
+/**
+ *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.
+ */
+/*
+ * pubsub_common.h
+ *
+ *  \date       Sep 17, 2015
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#ifndef PUBSUB_COMMON_H_
+#define PUBSUB_COMMON_H_
+
+#define PUBSUB_ADMIN_SERVICE 			"pubsub_admin"
+#define PUBSUB_DISCOVERY_SERVICE		"pubsub_discovery"
+#define PUBSUB_TM_ANNOUNCE_PUBLISHER_SERVICE    "pubsub_tm_announce_publisher"
+
+#define PUBSUB_ANY_SUB_TOPIC			"any"
+
+#define PUBSUB_BUNDLE_ID				"bundle.id"
+
+#define MAX_SCOPE_LEN					1024
+#define MAX_TOPIC_LEN					1024
+
+struct pubsub_msg_header{
+	char topic[MAX_TOPIC_LEN];
+	unsigned int type;
+	unsigned char major;
+	unsigned char minor;
+};
+
+typedef struct pubsub_msg_header* pubsub_msg_header_pt;
+
+
+#endif /* PUBSUB_COMMON_H_ */

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_common/public/include/pubsub_endpoint.h
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_common/public/include/pubsub_endpoint.h b/celix-pubsub/pubsub/pubsub_common/public/include/pubsub_endpoint.h
new file mode 100644
index 0000000..ae6bcf8
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_common/public/include/pubsub_endpoint.h
@@ -0,0 +1,49 @@
+/**
+ *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.
+ */
+/*
+ * pubsub_endpoint.h
+ *
+ *  \date       Sep 21, 2015
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#ifndef PUBSUB_ENDPOINT_H_
+#define PUBSUB_ENDPOINT_H_
+
+#include "service_reference.h"
+
+struct pubsub_endpoint {
+    char *frameworkUUID;
+    char *scope;
+    char *topic;
+    long serviceID;
+    char* endpoint;
+};
+
+typedef struct pubsub_endpoint *pubsub_endpoint_pt;
+
+celix_status_t pubsubEndpoint_create(const char* fwUUID, const char* scope, const char* topic, long serviceId,const char* endpoint,pubsub_endpoint_pt* psEp);
+celix_status_t pubsubEndpoint_createFromServiceReference(service_reference_pt reference,pubsub_endpoint_pt* psEp);
+celix_status_t pubsubEndpoint_destroy(pubsub_endpoint_pt psEp);
+bool pubsubEndpoint_equals(pubsub_endpoint_pt psEp1,pubsub_endpoint_pt psEp2);
+
+char *createScopeTopicKey(const char* scope, const char* topic);
+
+#endif /* PUBSUB_ENDPOINT_H_ */


[4/6] celix git commit: CELIX-389: Adds Celix Publish Subscribe donation.

Posted by pn...@apache.org.
http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_admin_udp_mc/private/src/pubsub_admin_impl.c
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_admin_udp_mc/private/src/pubsub_admin_impl.c b/celix-pubsub/pubsub/pubsub_admin_udp_mc/private/src/pubsub_admin_impl.c
new file mode 100644
index 0000000..722a7a4
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_admin_udp_mc/private/src/pubsub_admin_impl.c
@@ -0,0 +1,670 @@
+/**
+ *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.
+ */
+/*
+ * pubsub_admin_impl.c
+ *
+ *  \date       Sep 30, 2011
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifndef ANDROID
+#include <ifaddrs.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include "constants.h"
+#include "utils.h"
+#include "hash_map.h"
+#include "array_list.h"
+#include "bundle_context.h"
+#include "bundle.h"
+#include "service_reference.h"
+#include "service_registration.h"
+#include "log_helper.h"
+#include "log_service.h"
+#include "celix_threads.h"
+#include "service_factory.h"
+
+#include "pubsub_admin_impl.h"
+#include "topic_subscription.h"
+#include "pubsub_publish_service_private.h"
+#include "pubsub_endpoint.h"
+#include "subscriber.h"
+
+static const char *DEFAULT_MC_IP = "224.100.1.1";
+static char *DEFAULT_MC_PREFIX = "224.100";
+
+static celix_status_t pubsubAdmin_getIpAddress(const char* interface, char** ip);
+static celix_status_t pubsubAdmin_addSubscriptionToPendingList(pubsub_admin_pt admin,pubsub_endpoint_pt subEP);
+static celix_status_t pubsubAdmin_addAnySubscription(pubsub_admin_pt admin,pubsub_endpoint_pt subEP);
+
+
+celix_status_t pubsubAdmin_create(bundle_context_pt context, pubsub_admin_pt *admin) {
+	celix_status_t status = CELIX_SUCCESS;
+
+	*admin = calloc(1, sizeof(**admin));
+
+	if (!*admin) {
+		status = CELIX_ENOMEM;
+	}
+	else{
+
+		char *mc_ip = NULL;
+		char *if_ip = NULL;
+		(*admin)->bundle_context= context;
+		(*admin)->localPublications = hashMap_create(utils_stringHash, NULL, utils_stringEquals, NULL);
+		(*admin)->subscriptions = hashMap_create(utils_stringHash, NULL, utils_stringEquals, NULL);
+		(*admin)->pendingSubscriptions = hashMap_create(utils_stringHash, NULL, utils_stringEquals, NULL);
+		(*admin)->externalPublications = hashMap_create(utils_stringHash, NULL, utils_stringEquals, NULL);
+
+		celixThreadMutex_create(&(*admin)->localPublicationsLock, NULL);
+		celixThreadMutex_create(&(*admin)->subscriptionsLock, NULL);
+		celixThreadMutex_create(&(*admin)->pendingSubscriptionsLock, NULL);
+		celixThreadMutex_create(&(*admin)->externalPublicationsLock, NULL);
+
+		if (logHelper_create(context, &(*admin)->loghelper) == CELIX_SUCCESS) {
+			logHelper_start((*admin)->loghelper);
+		}
+		const char *mc_ip_prop = NULL;
+		bundleContext_getProperty(context,PSA_IP , &mc_ip_prop);
+		if(mc_ip_prop) {
+		    mc_ip = strdup(mc_ip_prop);
+		}
+#ifndef ANDROID
+		if (mc_ip == NULL) {
+		    const char *mc_prefix = NULL;
+            const char *interface = NULL;
+            int b0, b1, b2, b3;
+            bundleContext_getProperty(context,PSA_MULTICAST_IP_PREFIX , &mc_prefix);
+            if(mc_prefix == NULL) {
+                mc_prefix = DEFAULT_MC_PREFIX;
+            }
+
+			bundleContext_getProperty(context, PSA_ITF, &interface);
+			if (pubsubAdmin_getIpAddress(interface, &if_ip) != CELIX_SUCCESS) {
+				logHelper_log((*admin)->loghelper, OSGI_LOGSERVICE_WARNING, "PSA: Could not retrieve IP address for interface %s", interface);
+			}
+
+			printf("IP Detected : %s\n", if_ip);
+			if(if_ip && sscanf(if_ip, "%i.%i.%i.%i", &b0, &b1, &b2, &b3) != 4) {
+			    logHelper_log((*admin)->loghelper, OSGI_LOGSERVICE_WARNING, "PSA: Could not parse IP address %s", if_ip);
+			    b2 = 1;
+			    b3 = 1;
+			}
+
+            asprintf(&mc_ip, "%s.%d.%d",mc_prefix, b2, b3);
+
+	        int sendSocket = socket(AF_INET, SOCK_DGRAM, 0);
+	        if(sendSocket == -1) {
+	            perror("pubsubAdmin_create:socket");
+	            return CELIX_SERVICE_EXCEPTION;
+	        }
+	        char loop = 1;
+	        if(setsockopt(sendSocket, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) != 0) {
+	            perror("pubsubAdmin_create:setsockopt(IP_MULTICAST_LOOP)");
+	            return CELIX_SERVICE_EXCEPTION;
+	        }
+
+	        struct in_addr multicast_interface;
+	        inet_aton(if_ip, &multicast_interface);
+	        if(setsockopt(sendSocket,  IPPROTO_IP, IP_MULTICAST_IF, &multicast_interface, sizeof(multicast_interface)) != 0) {
+	            perror("pubsubAdmin_create:setsockopt(IP_MULTICAST_IF)");
+	            return CELIX_SERVICE_EXCEPTION;
+	        }
+
+	        (*admin)->sendSocket = sendSocket;
+
+		}
+#endif
+        if (if_ip != NULL) {
+            logHelper_log((*admin)->loghelper, OSGI_LOGSERVICE_INFO, "PSA: Using %s as interface for multicast communication", if_ip);
+            (*admin)->ifIpAddress = if_ip;
+        } else {
+            (*admin)->ifIpAddress = strdup("127.0.0.1");
+        }
+
+		if (mc_ip != NULL) {
+			logHelper_log((*admin)->loghelper, OSGI_LOGSERVICE_INFO, "PSA: Using %s for service annunciation", mc_ip);
+			(*admin)->mcIpAddress = mc_ip;
+		}
+		else {
+			logHelper_log((*admin)->loghelper, OSGI_LOGSERVICE_WARNING, "PSA: No IP address for service annunciation set. Using %s", DEFAULT_MC_IP);
+			(*admin)->mcIpAddress = strdup(DEFAULT_MC_IP);
+		}
+
+	}
+
+	return status;
+}
+
+
+celix_status_t pubsubAdmin_destroy(pubsub_admin_pt admin)
+{
+	celix_status_t status = CELIX_SUCCESS;
+
+	free(admin->mcIpAddress);
+    free(admin->ifIpAddress);
+
+	celixThreadMutex_lock(&admin->pendingSubscriptionsLock);
+	hash_map_iterator_pt iter = hashMapIterator_create(admin->pendingSubscriptions);
+	while(hashMapIterator_hasNext(iter)){
+		hash_map_entry_pt entry = hashMapIterator_nextEntry(iter);
+		free((char*)hashMapEntry_getKey(entry));
+		arrayList_destroy((array_list_pt)hashMapEntry_getValue(entry));
+	}
+	hashMapIterator_destroy(iter);
+	hashMap_destroy(admin->pendingSubscriptions,false,false);
+	celixThreadMutex_unlock(&admin->pendingSubscriptionsLock);
+
+	celixThreadMutex_lock(&admin->subscriptionsLock);
+	hashMap_destroy(admin->subscriptions,false,false);
+	celixThreadMutex_unlock(&admin->subscriptionsLock);
+
+	celixThreadMutex_lock(&admin->localPublicationsLock);
+	hashMap_destroy(admin->localPublications,true,false);
+	celixThreadMutex_unlock(&admin->localPublicationsLock);
+
+	celixThreadMutex_lock(&admin->externalPublicationsLock);
+	iter = hashMapIterator_create(admin->externalPublications);
+	while(hashMapIterator_hasNext(iter)){
+		hash_map_entry_pt entry = hashMapIterator_nextEntry(iter);
+		free((char*)hashMapEntry_getKey(entry));
+		arrayList_destroy((array_list_pt)hashMapEntry_getValue(entry));
+	}
+	hashMapIterator_destroy(iter);
+	hashMap_destroy(admin->externalPublications,false,false);
+	celixThreadMutex_unlock(&admin->externalPublicationsLock);
+
+	celixThreadMutex_destroy(&admin->pendingSubscriptionsLock);
+	celixThreadMutex_destroy(&admin->subscriptionsLock);
+	celixThreadMutex_destroy(&admin->localPublicationsLock);
+	celixThreadMutex_destroy(&admin->externalPublicationsLock);
+
+	logHelper_stop(admin->loghelper);
+
+	logHelper_destroy(&admin->loghelper);
+
+	free(admin);
+
+	return status;
+}
+
+celix_status_t pubsubAdmin_stop(pubsub_admin_pt admin) {
+	celix_status_t status = CELIX_SUCCESS;
+
+	return status;
+}
+
+static celix_status_t pubsubAdmin_addAnySubscription(pubsub_admin_pt admin,pubsub_endpoint_pt subEP){
+	celix_status_t status = CELIX_SUCCESS;
+
+	celixThreadMutex_lock(&admin->subscriptionsLock);
+
+	topic_subscription_pt any_sub = hashMap_get(admin->subscriptions,PUBSUB_ANY_SUB_TOPIC);
+
+	if(any_sub==NULL){
+
+		int i;
+
+		status += pubsub_topicSubscriptionCreate(admin->ifIpAddress, admin->bundle_context, PUBSUB_SUBSCRIBER_SCOPE_DEFAULT, PUBSUB_ANY_SUB_TOPIC,&any_sub);
+
+		/* Connect all internal publishers */
+		celixThreadMutex_lock(&admin->localPublicationsLock);
+		hash_map_iterator_pt lp_iter =hashMapIterator_create(admin->localPublications);
+		while(hashMapIterator_hasNext(lp_iter)){
+			service_factory_pt factory = (service_factory_pt)hashMapIterator_nextValue(lp_iter);
+			topic_publication_pt topic_pubs = (topic_publication_pt)factory->handle;
+			array_list_pt topic_publishers = pubsub_topicPublicationGetPublisherList(topic_pubs);
+
+			if(topic_publishers!=NULL){
+				for(i=0;i<arrayList_size(topic_publishers);i++){
+					pubsub_endpoint_pt pubEP = (pubsub_endpoint_pt)arrayList_get(topic_publishers,i);
+					if(pubEP->endpoint !=NULL){
+						status += pubsub_topicSubscriptionConnectPublisher(any_sub,pubEP->endpoint);
+					}
+				}
+			}
+		}
+		hashMapIterator_destroy(lp_iter);
+		celixThreadMutex_unlock(&admin->localPublicationsLock);
+
+		/* Connect also all external publishers */
+		celixThreadMutex_lock(&admin->externalPublicationsLock);
+		hash_map_iterator_pt extp_iter =hashMapIterator_create(admin->externalPublications);
+		while(hashMapIterator_hasNext(extp_iter)){
+			array_list_pt ext_pub_list = (array_list_pt)hashMapIterator_nextValue(extp_iter);
+			if(ext_pub_list!=NULL){
+				for(i=0;i<arrayList_size(ext_pub_list);i++){
+					pubsub_endpoint_pt pubEP = (pubsub_endpoint_pt)arrayList_get(ext_pub_list,i);
+					if(pubEP->endpoint !=NULL){
+						status += pubsub_topicSubscriptionConnectPublisher(any_sub,pubEP->endpoint);
+					}
+				}
+			}
+		}
+		hashMapIterator_destroy(extp_iter);
+		celixThreadMutex_unlock(&admin->externalPublicationsLock);
+
+
+		pubsub_topicSubscriptionAddSubscriber(any_sub,subEP);
+
+		status += pubsub_topicSubscriptionStart(any_sub);
+
+		hashMap_put(admin->subscriptions,strdup(PUBSUB_ANY_SUB_TOPIC),any_sub);
+
+	}
+
+	celixThreadMutex_unlock(&admin->subscriptionsLock);
+
+	return status;
+}
+
+celix_status_t pubsubAdmin_addSubscription(pubsub_admin_pt admin,pubsub_endpoint_pt subEP){
+	celix_status_t status = CELIX_SUCCESS;
+
+	printf("PSA: Received subscription [FWUUID=%s bundleID=%ld scope=%s, topic=%s]\n",subEP->frameworkUUID,subEP->serviceID,subEP->scope,subEP->topic);
+
+	if(strcmp(subEP->topic,PUBSUB_ANY_SUB_TOPIC)==0){
+		return pubsubAdmin_addAnySubscription(admin,subEP);
+	}
+
+	/* Check if we already know some publisher about this topic, otherwise let's put the subscription in the pending hashmap */
+	celixThreadMutex_lock(&admin->localPublicationsLock);
+	celixThreadMutex_lock(&admin->externalPublicationsLock);
+	char* scope_topic = createScopeTopicKey(subEP->scope,subEP->topic);
+
+	service_factory_pt factory = (service_factory_pt)hashMap_get(admin->localPublications,scope_topic);
+	array_list_pt ext_pub_list = (array_list_pt)hashMap_get(admin->externalPublications,scope_topic);
+
+	if(factory==NULL && ext_pub_list==NULL){ //No (local or external) publishers yet for this topic
+		celixThreadMutex_lock(&admin->pendingSubscriptionsLock);
+		pubsubAdmin_addSubscriptionToPendingList(admin,subEP);
+		celixThreadMutex_unlock(&admin->pendingSubscriptionsLock);
+	}
+	else{
+		int i;
+
+		topic_subscription_pt subscription = hashMap_get(admin->subscriptions, scope_topic);
+
+		if(subscription == NULL) {
+
+			status += pubsub_topicSubscriptionCreate(admin->ifIpAddress, admin->bundle_context, subEP->scope, subEP->topic,&subscription);
+
+			/* Try to connect internal publishers */
+			if(factory!=NULL){
+				topic_publication_pt topic_pubs = (topic_publication_pt)factory->handle;
+				array_list_pt topic_publishers = pubsub_topicPublicationGetPublisherList(topic_pubs);
+
+				if(topic_publishers!=NULL){
+					for(i=0;i<arrayList_size(topic_publishers);i++){
+						pubsub_endpoint_pt pubEP = (pubsub_endpoint_pt)arrayList_get(topic_publishers,i);
+						if(pubEP->endpoint !=NULL){
+							status += pubsub_topicSubscriptionConnectPublisher(subscription,pubEP->endpoint);
+						}
+					}
+				}
+
+			}
+
+			/* Look also for external publishers */
+			if(ext_pub_list!=NULL){
+				for(i=0;i<arrayList_size(ext_pub_list);i++){
+					pubsub_endpoint_pt pubEP = (pubsub_endpoint_pt)arrayList_get(ext_pub_list,i);
+					if(pubEP->endpoint !=NULL){
+						status += pubsub_topicSubscriptionConnectPublisher(subscription,pubEP->endpoint);
+					}
+				}
+			}
+
+			pubsub_topicSubscriptionAddSubscriber(subscription,subEP);
+
+			status += pubsub_topicSubscriptionStart(subscription);
+
+			if(status==CELIX_SUCCESS){
+				celixThreadMutex_lock(&admin->subscriptionsLock);
+				hashMap_put(admin->subscriptions,strdup(scope_topic),subscription);
+				celixThreadMutex_unlock(&admin->subscriptionsLock);
+			}
+		}
+		pubsub_topicIncreaseNrSubscribers(subscription);
+
+	}
+	free(scope_topic);
+	celixThreadMutex_unlock(&admin->externalPublicationsLock);
+	celixThreadMutex_unlock(&admin->localPublicationsLock);
+
+	return status;
+
+}
+
+celix_status_t pubsubAdmin_removeSubscription(pubsub_admin_pt admin,pubsub_endpoint_pt subEP){
+	celix_status_t status = CELIX_SUCCESS;
+
+	printf("PSA: Removing subscription [FWUUID=%s bundleID=%ld scope=%s, topic=%s]\n",subEP->frameworkUUID,subEP->serviceID,subEP->scope, subEP->topic);
+
+	celixThreadMutex_lock(&admin->subscriptionsLock);
+	char* scope_topic = createScopeTopicKey(subEP->scope, subEP->topic);
+	topic_subscription_pt sub = (topic_subscription_pt)hashMap_get(admin->subscriptions,scope_topic);
+	free(scope_topic);
+	if(sub!=NULL){
+		pubsub_topicDecreaseNrSubscribers(sub);
+		if(pubsub_topicGetNrSubscribers(sub) == 0) {
+			status = pubsub_topicSubscriptionRemoveSubscriber(sub,subEP);
+		}
+	}
+	else{
+		status = CELIX_ILLEGAL_STATE;
+	}
+
+	celixThreadMutex_unlock(&admin->subscriptionsLock);
+
+	return status;
+
+}
+
+celix_status_t pubsubAdmin_addPublication(pubsub_admin_pt admin,pubsub_endpoint_pt pubEP){
+	celix_status_t status = CELIX_SUCCESS;
+
+	printf("PSA: Received publication [FWUUID=%s bundleID=%ld scope=%s, topic=%s]\n",pubEP->frameworkUUID,pubEP->serviceID,pubEP->scope, pubEP->topic);
+
+	const char* fwUUID = NULL;
+
+	bundleContext_getProperty(admin->bundle_context,OSGI_FRAMEWORK_FRAMEWORK_UUID,&fwUUID);
+	if(fwUUID==NULL){
+		printf("PSA: Cannot retrieve fwUUID.\n");
+		return CELIX_INVALID_BUNDLE_CONTEXT;
+	}
+	char* scope_topic = createScopeTopicKey(pubEP->scope, pubEP->topic);
+
+	if((strcmp(pubEP->frameworkUUID,fwUUID)==0) && (pubEP->endpoint==NULL)){
+
+		celixThreadMutex_lock(&admin->localPublicationsLock);
+
+
+		service_factory_pt factory = (service_factory_pt)hashMap_get(admin->localPublications,scope_topic);
+
+		if (factory == NULL) {
+			topic_publication_pt pub = NULL;
+			status = pubsub_topicPublicationCreate(admin->sendSocket, pubEP,admin->mcIpAddress,&pub);
+			if(status == CELIX_SUCCESS){
+				status = pubsub_topicPublicationStart(admin->bundle_context,pub,&factory);
+				if(status==CELIX_SUCCESS && factory !=NULL){
+					hashMap_put(admin->localPublications,strdup(scope_topic),factory);
+				}
+			}
+			else{
+				printf("PSA: Cannot create a topicPublication for topic %s (bundle %ld).\n",pubEP->topic,pubEP->serviceID);
+			}
+		}
+		else{
+			//just add the new EP to the list
+			topic_publication_pt pub = (topic_publication_pt)factory->handle;
+			pubsub_topicPublicationAddPublisherEP(pub,pubEP);
+		}
+
+
+		celixThreadMutex_unlock(&admin->localPublicationsLock);
+	}
+	else{
+		celixThreadMutex_lock(&admin->externalPublicationsLock);
+		array_list_pt ext_pub_list = (array_list_pt)hashMap_get(admin->externalPublications,scope_topic);
+		if(ext_pub_list==NULL){
+			arrayList_create(&ext_pub_list);
+			hashMap_put(admin->externalPublications,strdup(scope_topic),ext_pub_list);
+		}
+
+		arrayList_add(ext_pub_list,pubEP);
+
+		celixThreadMutex_unlock(&admin->externalPublicationsLock);
+	}
+
+    /* Connect the new publisher to the subscription for his topic, if there is any */
+    celixThreadMutex_lock(&admin->subscriptionsLock);
+
+    topic_subscription_pt sub = (topic_subscription_pt)hashMap_get(admin->subscriptions,scope_topic);
+    if(sub!=NULL && pubEP->endpoint!=NULL){
+        pubsub_topicSubscriptionConnectPublisher(sub,pubEP->endpoint);
+    }
+
+    /* And check also for ANY subscription */
+    topic_subscription_pt any_sub = (topic_subscription_pt)hashMap_get(admin->subscriptions,PUBSUB_ANY_SUB_TOPIC);
+    if(any_sub!=NULL && pubEP->endpoint!=NULL){
+        pubsub_topicSubscriptionConnectPublisher(any_sub,pubEP->endpoint);
+    }
+
+    celixThreadMutex_unlock(&admin->subscriptionsLock);
+
+	/* Re-evaluate the pending subscriptions */
+	celixThreadMutex_lock(&admin->pendingSubscriptionsLock);
+
+	hash_map_entry_pt pendingSub = hashMap_getEntry(admin->pendingSubscriptions,scope_topic);
+	if(pendingSub!=NULL){ //There were pending subscription for the just published topic. Let's connect them.
+		char* key = (char*)hashMapEntry_getKey(pendingSub);
+		array_list_pt pendingSubList = (array_list_pt)hashMapEntry_getValue(pendingSub);
+		int i;
+		for(i=0;i<arrayList_size(pendingSubList);i++){
+			pubsub_endpoint_pt subEP = (pubsub_endpoint_pt)arrayList_get(pendingSubList,i);
+			pubsubAdmin_addSubscription(admin,subEP);
+		}
+		hashMap_remove(admin->pendingSubscriptions,key);
+		arrayList_clear(pendingSubList);
+		arrayList_destroy(pendingSubList);
+		free(key);
+	}
+    free(scope_topic);
+
+    celixThreadMutex_unlock(&admin->pendingSubscriptionsLock);
+
+	return status;
+
+}
+
+celix_status_t pubsubAdmin_removePublication(pubsub_admin_pt admin,pubsub_endpoint_pt pubEP){
+	celix_status_t status = CELIX_SUCCESS;
+
+	printf("PSA: Removing publication [FWUUID=%s bundleID=%ld scope=%s, topic=%s]\n",pubEP->frameworkUUID,pubEP->serviceID,pubEP->scope, pubEP->topic);
+
+	const char* fwUUID = NULL;
+
+	bundleContext_getProperty(admin->bundle_context,OSGI_FRAMEWORK_FRAMEWORK_UUID,&fwUUID);
+	if(fwUUID==NULL){
+		printf("PSA: Cannot retrieve fwUUID.\n");
+		return CELIX_INVALID_BUNDLE_CONTEXT;
+	}
+	char *scope_topic = createScopeTopicKey(pubEP->scope, pubEP->topic);
+
+	if(strcmp(pubEP->frameworkUUID,fwUUID)==0){
+
+		celixThreadMutex_lock(&admin->localPublicationsLock);
+
+		service_factory_pt factory = (service_factory_pt)hashMap_get(admin->localPublications,scope_topic);
+		if(factory!=NULL){
+			topic_publication_pt pub = (topic_publication_pt)factory->handle;
+			pubsub_topicPublicationRemovePublisherEP(pub,pubEP);
+		}
+		else{
+			status = CELIX_ILLEGAL_STATE;
+		}
+
+		celixThreadMutex_unlock(&admin->localPublicationsLock);
+	}
+	else{
+
+		celixThreadMutex_lock(&admin->externalPublicationsLock);
+		array_list_pt ext_pub_list = (array_list_pt)hashMap_get(admin->externalPublications,scope_topic);
+		if(ext_pub_list!=NULL){
+			int i;
+			bool found = false;
+			for(i=0;!found && i<arrayList_size(ext_pub_list);i++){
+				pubsub_endpoint_pt p  = (pubsub_endpoint_pt)arrayList_get(ext_pub_list,i);
+				found = pubsubEndpoint_equals(pubEP,p);
+				if(found){
+					arrayList_remove(ext_pub_list,i);
+				}
+			}
+            if(arrayList_size(ext_pub_list)==0){
+                hash_map_entry_pt entry = hashMap_getEntry(admin->externalPublications,scope_topic);
+                char* topic = (char*)hashMapEntry_getKey(entry);
+                array_list_pt list = (array_list_pt)hashMapEntry_getValue(entry);
+                hashMap_remove(admin->externalPublications,scope_topic);
+                arrayList_destroy(list);
+                free(topic);
+            }
+		}
+
+		celixThreadMutex_unlock(&admin->externalPublicationsLock);
+	}
+
+	/* Check if this publisher was connected to one of our subscribers*/
+	celixThreadMutex_lock(&admin->subscriptionsLock);
+
+	topic_subscription_pt sub = (topic_subscription_pt)hashMap_get(admin->subscriptions,scope_topic);
+	if(sub!=NULL && pubEP->endpoint!=NULL){
+		pubsub_topicSubscriptionDisconnectPublisher(sub,pubEP->endpoint);
+	}
+
+	/* And check also for ANY subscription */
+	topic_subscription_pt any_sub = (topic_subscription_pt)hashMap_get(admin->subscriptions,PUBSUB_ANY_SUB_TOPIC);
+	if(any_sub!=NULL && pubEP->endpoint!=NULL){
+		pubsub_topicSubscriptionDisconnectPublisher(any_sub,pubEP->endpoint);
+	}
+	free(scope_topic);
+	celixThreadMutex_unlock(&admin->subscriptionsLock);
+
+	return status;
+
+}
+
+celix_status_t pubsubAdmin_closeAllPublications(pubsub_admin_pt admin,char *scope, char* topic){
+	celix_status_t status = CELIX_SUCCESS;
+
+	printf("PSA: Closing all publications for scope=%s,topic=%s\n", scope, topic);
+
+	celixThreadMutex_lock(&admin->localPublicationsLock);
+	char* scope_topic =createScopeTopicKey(scope, topic);
+	hash_map_entry_pt pubsvc_entry = (hash_map_entry_pt)hashMap_getEntry(admin->localPublications,scope_topic);
+	if(pubsvc_entry!=NULL){
+		char* key = (char*)hashMapEntry_getKey(pubsvc_entry);
+		service_factory_pt factory= (service_factory_pt)hashMapEntry_getValue(pubsvc_entry);
+		topic_publication_pt pub = (topic_publication_pt)factory->handle;
+		status += pubsub_topicPublicationStop(pub);
+		status += pubsub_topicPublicationDestroy(pub);
+
+		hashMap_remove(admin->localPublications,scope_topic);
+		free(key);
+		free(factory);
+	}
+	free(scope_topic);
+	celixThreadMutex_unlock(&admin->localPublicationsLock);
+
+	return status;
+
+}
+
+celix_status_t pubsubAdmin_closeAllSubscriptions(pubsub_admin_pt admin,char *scope, char* topic){
+	celix_status_t status = CELIX_SUCCESS;
+
+	printf("PSA: Closing all subscriptions\n");
+
+	celixThreadMutex_lock(&admin->subscriptionsLock);
+	char* scope_topic =createScopeTopicKey(scope, topic);
+	hash_map_entry_pt sub_entry = (hash_map_entry_pt)hashMap_getEntry(admin->subscriptions,scope_topic);
+	if(sub_entry!=NULL){
+		char* topic = (char*)hashMapEntry_getKey(sub_entry);
+
+		topic_subscription_pt ts = (topic_subscription_pt)hashMapEntry_getValue(sub_entry);
+		status += pubsub_topicSubscriptionStop(ts);
+		status += pubsub_topicSubscriptionDestroy(ts);
+
+		hashMap_remove(admin->subscriptions,topic);
+		free(topic);
+
+	}
+	free(scope_topic);
+	celixThreadMutex_unlock(&admin->subscriptionsLock);
+
+	return status;
+
+}
+
+
+#ifndef ANDROID
+static celix_status_t pubsubAdmin_getIpAddress(const char* interface, char** ip) {
+	celix_status_t status = CELIX_BUNDLE_EXCEPTION;
+
+	struct ifaddrs *ifaddr, *ifa;
+	char host[NI_MAXHOST];
+
+	if (getifaddrs(&ifaddr) != -1)
+	{
+		for (ifa = ifaddr; ifa != NULL && status != CELIX_SUCCESS; ifa = ifa->ifa_next)
+		{
+			if (ifa->ifa_addr == NULL)
+				continue;
+
+			if ((getnameinfo(ifa->ifa_addr,sizeof(struct sockaddr_in), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) == 0) && (ifa->ifa_addr->sa_family == AF_INET)) {
+				if (interface == NULL) {
+					*ip = strdup(host);
+					status = CELIX_SUCCESS;
+				}
+				else if (strcmp(ifa->ifa_name, interface) == 0) {
+					*ip = strdup(host);
+					status = CELIX_SUCCESS;
+				}
+			}
+		}
+
+		freeifaddrs(ifaddr);
+	}
+	if(status == CELIX_SUCCESS) {
+
+	}
+	return status;
+}
+#endif
+
+static celix_status_t pubsubAdmin_addSubscriptionToPendingList(pubsub_admin_pt admin,pubsub_endpoint_pt subEP){
+	celix_status_t status = CELIX_SUCCESS;
+
+	char* scope_topic =createScopeTopicKey(subEP->scope, subEP->topic);
+	array_list_pt pendingListPerTopic = hashMap_get(admin->pendingSubscriptions,scope_topic);
+	if(pendingListPerTopic==NULL){
+		arrayList_create(&pendingListPerTopic);
+		hashMap_put(admin->pendingSubscriptions,scope_topic,pendingListPerTopic);
+	} else {
+	    free(scope_topic);
+	}
+	arrayList_add(pendingListPerTopic,subEP);
+
+	return status;
+}

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_admin_udp_mc/private/src/topic_publication.c
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_admin_udp_mc/private/src/topic_publication.c b/celix-pubsub/pubsub/pubsub_admin_udp_mc/private/src/topic_publication.c
new file mode 100644
index 0000000..9a9fa55
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_admin_udp_mc/private/src/topic_publication.c
@@ -0,0 +1,470 @@
+/**
+ *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.
+ */
+/*
+ * topic_publication.c
+ *
+ *  \date       Sep 24, 2015
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "array_list.h"
+#include "celixbool.h"
+#include "service_registration.h"
+#include "dyn_msg_utils.h"
+#include "utils.h"
+#include "service_factory.h"
+#include "version.h"
+
+#include "pubsub_publish_service_private.h"
+#include "pubsub_common.h"
+#include "publisher.h"
+#include "large_udp.h"
+
+#include "pubsub_serializer.h"
+
+#define EP_ADDRESS_LEN		32
+
+#define FIRST_SEND_DELAY	2
+
+struct topic_publication {
+	int sendSocket;
+	char* endpoint;
+	service_registration_pt svcFactoryReg;
+	array_list_pt pub_ep_list; //List<pubsub_endpoint>
+	hash_map_pt boundServices; //<bundle_pt,bound_service>
+	celix_thread_mutex_t tp_lock;
+	struct sockaddr_in destAddr;
+};
+
+typedef struct publish_bundle_bound_service {
+	topic_publication_pt parent;
+	pubsub_publisher_pt service;
+	bundle_pt bundle;
+    char *scope;
+	char *topic;
+	hash_map_pt msgTypes;
+	unsigned short getCount;
+	celix_thread_mutex_t mp_lock;
+	bool mp_send_in_progress;
+	array_list_pt mp_parts;
+	largeUdp_pt largeUdpHandle;
+}* publish_bundle_bound_service_pt;
+
+typedef struct pubsub_msg{
+	pubsub_msg_header_pt header;
+	char* payload;
+	int payloadSize;
+}* pubsub_msg_pt;
+
+static unsigned int rand_range(unsigned int min, unsigned int max);
+
+static celix_status_t pubsub_topicPublicationGetService(void* handle, bundle_pt bundle, service_registration_pt registration, void **service);
+static celix_status_t pubsub_topicPublicationUngetService(void* handle, bundle_pt bundle, service_registration_pt registration, void **service);
+
+static publish_bundle_bound_service_pt pubsub_createPublishBundleBoundService(topic_publication_pt tp,bundle_pt bundle);
+static void pubsub_destroyPublishBundleBoundService(publish_bundle_bound_service_pt boundSvc);
+
+static int pubsub_topicPublicationSend(void* handle,unsigned int msgTypeId, void *msg);
+
+static int pubsub_localMsgTypeIdForUUID(void* handle, const char* msgType, unsigned int* msgTypeId);
+
+
+static void delay_first_send_for_late_joiners(void);
+
+
+celix_status_t pubsub_topicPublicationCreate(int sendSocket, pubsub_endpoint_pt pubEP,char* bindIP, topic_publication_pt *out){
+
+    char* ep = malloc(EP_ADDRESS_LEN);
+    memset(ep,0,EP_ADDRESS_LEN);
+    unsigned int port = pubEP->serviceID + rand_range(UDP_BASE_PORT+pubEP->serviceID+3, UDP_MAX_PORT);
+    snprintf(ep,EP_ADDRESS_LEN,"udp://%s:%u",bindIP,port);
+
+
+	topic_publication_pt pub = calloc(1,sizeof(*pub));
+
+	arrayList_create(&(pub->pub_ep_list));
+	pub->boundServices = hashMap_create(NULL,NULL,NULL,NULL);
+	celixThreadMutex_create(&(pub->tp_lock),NULL);
+
+	pub->endpoint = ep;
+	pub->sendSocket = sendSocket;
+	pub->destAddr.sin_family = AF_INET;
+	pub->destAddr.sin_addr.s_addr = inet_addr(bindIP);
+	pub->destAddr.sin_port = htons(port);
+
+	pubsub_topicPublicationAddPublisherEP(pub,pubEP);
+
+	*out = pub;
+
+	return CELIX_SUCCESS;
+}
+
+celix_status_t pubsub_topicPublicationDestroy(topic_publication_pt pub){
+	celix_status_t status = CELIX_SUCCESS;
+
+	celixThreadMutex_lock(&(pub->tp_lock));
+
+	free(pub->endpoint);
+	arrayList_destroy(pub->pub_ep_list);
+
+	hash_map_iterator_pt iter = hashMapIterator_create(pub->boundServices);
+	while(hashMapIterator_hasNext(iter)){
+		publish_bundle_bound_service_pt bound = hashMapIterator_nextValue(iter);
+		pubsub_destroyPublishBundleBoundService(bound);
+	}
+	hashMapIterator_destroy(iter);
+	hashMap_destroy(pub->boundServices,false,false);
+
+	pub->svcFactoryReg = NULL;
+	status = close(pub->sendSocket);
+
+	celixThreadMutex_unlock(&(pub->tp_lock));
+
+	celixThreadMutex_destroy(&(pub->tp_lock));
+
+	free(pub);
+
+	return status;
+}
+
+celix_status_t pubsub_topicPublicationStart(bundle_context_pt bundle_context,topic_publication_pt pub,service_factory_pt* svcFactory){
+	celix_status_t status = CELIX_SUCCESS;
+
+	/* Let's register the new service */
+	//celixThreadMutex_lock(&(pub->tp_lock));
+
+	pubsub_endpoint_pt pubEP = (pubsub_endpoint_pt)arrayList_get(pub->pub_ep_list,0);
+
+	if(pubEP!=NULL){
+		service_factory_pt factory = calloc(1, sizeof(*factory));
+		factory->handle = pub;
+		factory->getService = pubsub_topicPublicationGetService;
+		factory->ungetService = pubsub_topicPublicationUngetService;
+
+		properties_pt props = properties_create();
+        properties_set(props,PUBSUB_PUBLISHER_SCOPE,pubEP->scope);
+		properties_set(props,PUBSUB_PUBLISHER_TOPIC,pubEP->topic);
+
+		status = bundleContext_registerServiceFactory(bundle_context,PUBSUB_PUBLISHER_SERVICE_NAME,factory,props,&(pub->svcFactoryReg));
+
+		if(status != CELIX_SUCCESS){
+			properties_destroy(props);
+			printf("PSA: Cannot register ServiceFactory for topic %s, topic %s (bundle %ld).\n",pubEP->scope, pubEP->topic,pubEP->serviceID);
+		}
+		else{
+			*svcFactory = factory;
+		}
+	}
+	else{
+		printf("PSA: Cannot find pubsub_endpoint after adding it...Should never happen!\n");
+		status = CELIX_SERVICE_EXCEPTION;
+	}
+
+	//celixThreadMutex_unlock(&(pub->tp_lock));
+
+	return status;
+}
+
+celix_status_t pubsub_topicPublicationStop(topic_publication_pt pub){
+	celix_status_t status = CELIX_SUCCESS;
+
+	//celixThreadMutex_lock(&(pub->tp_lock));
+
+	status = serviceRegistration_unregister(pub->svcFactoryReg);
+
+	//celixThreadMutex_unlock(&(pub->tp_lock));
+
+	return status;
+}
+
+celix_status_t pubsub_topicPublicationAddPublisherEP(topic_publication_pt pub,pubsub_endpoint_pt ep){
+
+	celixThreadMutex_lock(&(pub->tp_lock));
+	ep->endpoint = strdup(pub->endpoint);
+	arrayList_add(pub->pub_ep_list,ep);
+	celixThreadMutex_unlock(&(pub->tp_lock));
+
+	return CELIX_SUCCESS;
+}
+
+celix_status_t pubsub_topicPublicationRemovePublisherEP(topic_publication_pt pub,pubsub_endpoint_pt ep){
+
+	celixThreadMutex_lock(&(pub->tp_lock));
+	arrayList_removeElement(pub->pub_ep_list,ep);
+	celixThreadMutex_unlock(&(pub->tp_lock));
+
+	return CELIX_SUCCESS;
+}
+
+array_list_pt pubsub_topicPublicationGetPublisherList(topic_publication_pt pub){
+	return pub->pub_ep_list;
+}
+
+
+static celix_status_t pubsub_topicPublicationGetService(void* handle, bundle_pt bundle, service_registration_pt registration, void **service) {
+	celix_status_t  status = CELIX_SUCCESS;
+
+	topic_publication_pt publish = (topic_publication_pt)handle;
+
+	celixThreadMutex_lock(&(publish->tp_lock));
+
+	publish_bundle_bound_service_pt bound = (publish_bundle_bound_service_pt)hashMap_get(publish->boundServices,bundle);
+	if(bound==NULL){
+		bound = pubsub_createPublishBundleBoundService(publish,bundle);
+		if(bound!=NULL){
+			hashMap_put(publish->boundServices,bundle,bound);
+		}
+	}
+	else{
+		bound->getCount++;
+	}
+
+	*service = bound->service;
+
+	celixThreadMutex_unlock(&(publish->tp_lock));
+
+	return status;
+}
+
+static celix_status_t pubsub_topicPublicationUngetService(void* handle, bundle_pt bundle, service_registration_pt registration, void **service)  {
+
+	topic_publication_pt publish = (topic_publication_pt)handle;
+
+	celixThreadMutex_lock(&(publish->tp_lock));
+
+	publish_bundle_bound_service_pt bound = (publish_bundle_bound_service_pt)hashMap_get(publish->boundServices,bundle);
+	if(bound!=NULL){
+
+		bound->getCount--;
+		if(bound->getCount==0){
+			pubsub_destroyPublishBundleBoundService(bound);
+			hashMap_remove(publish->boundServices,bundle);
+		}
+
+	}
+	else{
+		long bundleId = -1;
+		bundle_getBundleId(bundle,&bundleId);
+		printf("TP: Unexpected ungetService call for bundle %ld.\n", bundleId);
+	}
+
+	/* service should be never used for unget, so let's set the pointer to NULL */
+	*service = NULL;
+
+	celixThreadMutex_unlock(&(publish->tp_lock));
+
+	return CELIX_SUCCESS;
+}
+
+static bool send_pubsub_msg(publish_bundle_bound_service_pt bound, pubsub_msg_pt msg, bool last, pubsub_release_callback_t *releaseCallback){
+	const int iovec_len = 3; // header + size + payload
+	bool ret = true;
+	pubsub_udp_msg_pt udpMsg;
+
+	int compiledMsgSize = sizeof(*udpMsg) + msg->payloadSize;
+
+	struct iovec msg_iovec[iovec_len];
+	msg_iovec[0].iov_base = msg->header;
+	msg_iovec[0].iov_len = sizeof(*msg->header);
+	msg_iovec[1].iov_base = &msg->payloadSize;
+	msg_iovec[1].iov_len = sizeof(msg->payloadSize);
+	msg_iovec[2].iov_base = msg->payload;
+	msg_iovec[2].iov_len = msg->payloadSize;
+
+	delay_first_send_for_late_joiners();
+
+	if(largeUdp_sendmsg(bound->largeUdpHandle, bound->parent->sendSocket, msg_iovec, iovec_len, 0, &bound->parent->destAddr, sizeof(bound->parent->destAddr)) == -1) {
+	    fprintf(stderr, "Socket: %d, size: %i",bound->parent->sendSocket, compiledMsgSize);
+	    perror("send_pubsub_msg:sendSocket");
+	    ret = false;
+	}
+
+	//free(udpMsg);
+	if(releaseCallback) {
+	    releaseCallback->release(msg->payload, bound);
+	}
+	return ret;
+
+}
+
+
+static int pubsub_topicPublicationSend(void* handle, unsigned int msgTypeId, void *msg) {
+    int status = 0;
+    publish_bundle_bound_service_pt bound = (publish_bundle_bound_service_pt) handle;
+
+    celixThreadMutex_lock(&(bound->mp_lock));
+
+    pubsub_message_type *msgType = hashMap_get(bound->msgTypes, &msgTypeId);
+
+    int major=0, minor=0;
+
+    if (msgType != NULL) {
+
+    	version_pt msgVersion = pubsubSerializer_getVersion(msgType);
+
+		pubsub_msg_header_pt msg_hdr = calloc(1,sizeof(struct pubsub_msg_header));
+
+		strncpy(msg_hdr->topic,bound->topic,MAX_TOPIC_LEN-1);
+
+		msg_hdr->type = msgTypeId;
+		if (msgVersion != NULL){
+			version_getMajor(msgVersion, &major);
+			version_getMinor(msgVersion, &minor);
+			msg_hdr->major = major;
+			msg_hdr->minor = minor;
+		}
+
+		void* serializedOutput = NULL;
+		int serializedOutputLen = 0;
+		pubsubSerializer_serialize(msgType, msg, &serializedOutput, &serializedOutputLen);
+
+		pubsub_msg_pt msg = calloc(1,sizeof(struct pubsub_msg));
+		msg->header = msg_hdr;
+		msg->payload = (char *) serializedOutput;
+		msg->payloadSize = serializedOutputLen;
+
+		celixThreadMutex_lock(&(bound->parent->tp_lock));
+		if(send_pubsub_msg(bound, msg,true, NULL) == false) {
+			status = -1;
+		}
+		free(msg_hdr);
+		free(msg);
+		free(serializedOutput);
+		celixThreadMutex_unlock(&(bound->parent->tp_lock));
+
+    } else {
+        printf("TP: Message %u not supported.",msgTypeId);
+        status=-1;
+    }
+
+    celixThreadMutex_unlock(&(bound->mp_lock));
+
+    return status;
+}
+
+static int pubsub_localMsgTypeIdForUUID(void* handle, const char* msgType, unsigned int* msgTypeId){
+	*msgTypeId = pubsubSerializer_hashCode(msgType);
+	return 0;
+}
+
+
+static unsigned int rand_range(unsigned int min, unsigned int max){
+
+	double scaled = (double)(((double)rand())/((double)RAND_MAX));
+	return (max-min+1)*scaled + min;
+
+}
+
+static publish_bundle_bound_service_pt pubsub_createPublishBundleBoundService(topic_publication_pt tp,bundle_pt bundle){
+
+	publish_bundle_bound_service_pt bound = calloc(1, sizeof(*bound));
+
+	if (bound != NULL) {
+		bound->service = calloc(1, sizeof(*bound->service));
+	}
+
+	if (bound != NULL && bound->service != NULL) {
+
+		bound->parent = tp;
+		bound->bundle = bundle;
+		bound->getCount = 1;
+		bound->mp_send_in_progress = false;
+		celixThreadMutex_create(&bound->mp_lock,NULL);
+		bound->msgTypes = hashMap_create(uintHash, NULL, uintEquals, NULL); //<int* (msgId),pubsub_message_type>
+		arrayList_create(&bound->mp_parts);
+
+		pubsub_endpoint_pt pubEP = (pubsub_endpoint_pt)arrayList_get(bound->parent->pub_ep_list,0);
+		bound->scope=strdup(pubEP->scope);
+		bound->topic=strdup(pubEP->topic);
+		bound->largeUdpHandle = largeUdp_create(1);
+		bound->service->handle = bound;
+		bound->service->localMsgTypeIdForMsgType = pubsub_localMsgTypeIdForUUID;
+		bound->service->send = pubsub_topicPublicationSend;
+		bound->service->sendMultipart = NULL;  //Multipart not supported (jet) for UDP
+
+		pubsubSerializer_fillMsgTypesMap(bound->msgTypes,bound->bundle);
+
+	}
+	else
+	{
+		if (bound != NULL) {
+			free(bound->service);
+		}
+		free(bound);
+		return NULL;
+	}
+
+	return bound;
+}
+
+static void pubsub_destroyPublishBundleBoundService(publish_bundle_bound_service_pt boundSvc){
+
+	celixThreadMutex_lock(&boundSvc->mp_lock);
+
+	if(boundSvc->service != NULL){
+		free(boundSvc->service);
+	}
+
+	if(boundSvc->msgTypes != NULL){
+		pubsubSerializer_emptyMsgTypesMap(boundSvc->msgTypes);
+		hashMap_destroy(boundSvc->msgTypes,false,false);
+	}
+
+	if(boundSvc->mp_parts!=NULL){
+		arrayList_destroy(boundSvc->mp_parts);
+	}
+
+    if(boundSvc->scope!=NULL){
+        free(boundSvc->scope);
+    }
+
+    if(boundSvc->topic!=NULL){
+		free(boundSvc->topic);
+	}
+
+	largeUdp_destroy(boundSvc->largeUdpHandle);
+
+	celixThreadMutex_unlock(&boundSvc->mp_lock);
+	celixThreadMutex_destroy(&boundSvc->mp_lock);
+
+	free(boundSvc);
+
+}
+
+static void delay_first_send_for_late_joiners(){
+
+	static bool firstSend = true;
+
+	if(firstSend){
+		printf("TP: Delaying first send for late joiners...\n");
+		sleep(FIRST_SEND_DELAY);
+		firstSend = false;
+	}
+}

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_admin_udp_mc/private/src/topic_subscription.c
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_admin_udp_mc/private/src/topic_subscription.c b/celix-pubsub/pubsub/pubsub_admin_udp_mc/private/src/topic_subscription.c
new file mode 100644
index 0000000..12ec56d
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_admin_udp_mc/private/src/topic_subscription.c
@@ -0,0 +1,497 @@
+/**
+ *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.
+ */
+/*
+ * topic_subscription.c
+ *
+ *  \date       Oct 2, 2015
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/epoll.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "utils.h"
+#include "celix_errno.h"
+#include "constants.h"
+#include "version.h"
+
+#include "topic_subscription.h"
+#include "subscriber.h"
+#include "publisher.h"
+#include "dyn_msg_utils.h"
+#include "pubsub_publish_service_private.h"
+#include "large_udp.h"
+
+#include "pubsub_serializer.h"
+
+#define MAX_EPOLL_EVENTS        10
+#define RECV_THREAD_TIMEOUT     5
+#define UDP_BUFFER_SIZE         65535
+#define MAX_UDP_SESSIONS        16
+
+struct topic_subscription{
+
+	char* ifIpAddress;
+	service_tracker_pt tracker;
+	array_list_pt sub_ep_list;
+	celix_thread_t recv_thread;
+	bool running;
+	celix_thread_mutex_t ts_lock;
+	bundle_context_pt context;
+	int topicEpollFd; // EPOLL filedescriptor where the sockets are registered.
+	hash_map_pt servicesMap; // key = service, value = msg types map
+	hash_map_pt socketMap; // key = URL, value = listen-socket
+	unsigned int nrSubscribers;
+	largeUdp_pt largeUdpHandle;
+};
+
+typedef struct mp_handle{
+	hash_map_pt svc_msg_db;
+	hash_map_pt rcv_msg_map;
+}* mp_handle_pt;
+
+typedef struct msg_map_entry{
+	bool retain;
+	void* msgInst;
+}* msg_map_entry_pt;
+
+static celix_status_t topicsub_subscriberTracked(void * handle, service_reference_pt reference, void * service);
+static celix_status_t topicsub_subscriberUntracked(void * handle, service_reference_pt reference, void * service);
+static void* udp_recv_thread_func(void* arg);
+static bool checkVersion(version_pt msgVersion,pubsub_msg_header_pt hdr);
+static void sigusr1_sighandler(int signo);
+static int pubsub_localMsgTypeIdForMsgType(void* handle, const char* msgType, unsigned int* msgTypeId);
+
+
+celix_status_t pubsub_topicSubscriptionCreate(char* ifIp,bundle_context_pt bundle_context, char* scope, char* topic,topic_subscription_pt* out){
+	celix_status_t status = CELIX_SUCCESS;
+
+	topic_subscription_pt ts = (topic_subscription_pt) calloc(1,sizeof(*ts));
+	ts->context = bundle_context;
+	ts->ifIpAddress = strdup(ifIp);
+	ts->topicEpollFd = epoll_create1(0);
+	if(ts->topicEpollFd == -1) {
+	    status += CELIX_SERVICE_EXCEPTION;
+	}
+
+	ts->running = false;
+	ts->nrSubscribers = 0;
+
+	celixThreadMutex_create(&ts->ts_lock,NULL);
+	arrayList_create(&ts->sub_ep_list);
+	ts->servicesMap = hashMap_create(NULL, NULL, NULL, NULL);
+	ts->socketMap =  hashMap_create(utils_stringHash, NULL, utils_stringEquals, NULL);
+
+	ts->largeUdpHandle = largeUdp_create(MAX_UDP_SESSIONS);
+
+	char filter[128];
+	memset(filter,0,128);
+	if(strncmp(PUBSUB_SUBSCRIBER_SCOPE_DEFAULT, scope, strlen(PUBSUB_SUBSCRIBER_SCOPE_DEFAULT)) == 0) {
+        // default scope, means that subscriber has not defined a scope property
+        snprintf(filter, 128, "(&(%s=%s)(%s=%s))",
+                (char*) OSGI_FRAMEWORK_OBJECTCLASS, PUBSUB_SUBSCRIBER_SERVICE_NAME,
+                PUBSUB_SUBSCRIBER_TOPIC,topic);
+
+    } else {
+        snprintf(filter, 128, "(&(%s=%s)(%s=%s)(%s=%s))",
+                (char*) OSGI_FRAMEWORK_OBJECTCLASS, PUBSUB_SUBSCRIBER_SERVICE_NAME,
+                PUBSUB_SUBSCRIBER_TOPIC,topic,
+                PUBSUB_SUBSCRIBER_SCOPE,scope);
+    }
+
+	service_tracker_customizer_pt customizer = NULL;
+	status += serviceTrackerCustomizer_create(ts,NULL,topicsub_subscriberTracked,NULL,topicsub_subscriberUntracked,&customizer);
+	status += serviceTracker_createWithFilter(bundle_context, filter, customizer, &ts->tracker);
+
+	struct sigaction actions;
+	memset(&actions, 0, sizeof(actions));
+	sigemptyset(&actions.sa_mask);
+	actions.sa_flags = 0;
+	actions.sa_handler = sigusr1_sighandler;
+
+	sigaction(SIGUSR1,&actions,NULL);
+
+	*out=ts;
+
+	return status;
+}
+
+celix_status_t pubsub_topicSubscriptionDestroy(topic_subscription_pt ts){
+	celix_status_t status = CELIX_SUCCESS;
+
+	celixThreadMutex_lock(&ts->ts_lock);
+	ts->running = false;
+	free(ts->ifIpAddress);
+	serviceTracker_destroy(ts->tracker);
+	arrayList_clear(ts->sub_ep_list);
+	arrayList_destroy(ts->sub_ep_list);
+	hashMap_destroy(ts->servicesMap,false,false);
+
+	hashMap_destroy(ts->socketMap,false,false);
+	largeUdp_destroy(ts->largeUdpHandle);
+	close(ts->topicEpollFd);
+
+	celixThreadMutex_unlock(&ts->ts_lock);
+
+	celixThreadMutex_destroy(&ts->ts_lock);
+
+	free(ts);
+
+	return status;
+}
+
+celix_status_t pubsub_topicSubscriptionStart(topic_subscription_pt ts){
+	celix_status_t status = CELIX_SUCCESS;
+
+	status = serviceTracker_open(ts->tracker);
+
+	ts->running = true;
+
+	if(status==CELIX_SUCCESS){
+		status=celixThread_create(&ts->recv_thread,NULL,udp_recv_thread_func,ts);
+	}
+
+	return status;
+}
+
+celix_status_t pubsub_topicSubscriptionStop(topic_subscription_pt ts){
+	celix_status_t status = CELIX_SUCCESS;
+
+	ts->running = false;
+
+	pthread_kill(ts->recv_thread.thread,SIGUSR1);
+
+	celixThread_join(ts->recv_thread,NULL);
+
+    status = serviceTracker_close(ts->tracker);
+
+    hash_map_iterator_pt it = hashMapIterator_create(ts->socketMap);
+    while(hashMapIterator_hasNext(it)) {
+        hash_map_entry_pt entry = hashMapIterator_nextEntry(it);
+        char *url = hashMapEntry_getKey(entry);
+        pubsub_topicSubscriptionDisconnectPublisher(ts, url);
+    }
+    hashMapIterator_destroy(it);
+
+
+	return status;
+}
+
+celix_status_t pubsub_topicSubscriptionConnectPublisher(topic_subscription_pt ts, char* pubURL) {
+
+    printf("pubsub_topicSubscriptionConnectPublisher : pubURL = %s\n", pubURL);
+
+    celix_status_t status = CELIX_SUCCESS;
+    celixThreadMutex_lock(&ts->ts_lock);
+    int *recvSocket = calloc(sizeof(int), 1);
+    *recvSocket = socket(AF_INET, SOCK_DGRAM, 0);
+    if (*recvSocket < 0) {
+        perror("pubsub_topicSubscriptionCreate:socket");
+        return CELIX_SERVICE_EXCEPTION;
+    }
+
+    int reuse = 1;
+    if (setsockopt(*recvSocket, SOL_SOCKET, SO_REUSEADDR, (char*) &reuse, sizeof(reuse)) != 0) {
+        perror("setsockopt() SO_REUSEADDR");
+        return CELIX_SERVICE_EXCEPTION;
+    }
+
+    // TODO Check if there is a better way to parse the URL to IP/Portnr
+    //replace ':' by spaces
+    char *url = strdup(pubURL);
+    char *pt = url;
+    while((pt=strchr(pt, ':')) != NULL) {
+        *pt = ' ';
+    }
+    char mcIp[100];
+    unsigned short mcPort;
+    sscanf(url, "udp //%s %hu", mcIp, &mcPort);
+    free (url);
+
+    printf("pubsub_topicSubscriptionConnectPublisher : IP = %s, Port = %hu\n", mcIp, mcPort);
+
+    struct ip_mreq mc_addr;
+    mc_addr.imr_multiaddr.s_addr = inet_addr(mcIp);
+    mc_addr.imr_interface.s_addr = inet_addr(ts->ifIpAddress);
+    printf("Adding MC %s at interface %s\n", mcIp, ts->ifIpAddress);
+    if (setsockopt(*recvSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*) &mc_addr, sizeof(mc_addr)) != 0) {
+        perror("setsockopt() IP_ADD_MEMBERSHIP");
+        return CELIX_SERVICE_EXCEPTION;
+    }
+
+    struct sockaddr_in mcListenAddr;
+    mcListenAddr.sin_family = AF_INET;
+    mcListenAddr.sin_addr.s_addr = INADDR_ANY;
+    mcListenAddr.sin_port = htons(mcPort);
+    if(bind(*recvSocket, (struct sockaddr*)&mcListenAddr, sizeof(mcListenAddr)) != 0) {
+        perror("bind()");
+        return CELIX_SERVICE_EXCEPTION;
+    }
+
+
+    struct epoll_event ev;
+    memset(&ev, 0, sizeof(ev));
+    ev.events = EPOLLIN;
+    ev.data.fd = *recvSocket;
+    if(epoll_ctl(ts->topicEpollFd, EPOLL_CTL_ADD, *recvSocket, &ev) == -1) {
+        perror("epoll_ctl() EPOLL_CTL_ADD");
+        return CELIX_SERVICE_EXCEPTION;
+    }
+    hashMap_put(ts->socketMap, pubURL, (void*)recvSocket);
+
+    celixThreadMutex_unlock(&ts->ts_lock);
+
+    return status;
+}
+
+celix_status_t pubsub_topicSubscriptionDisconnectPublisher(topic_subscription_pt ts, char* pubURL){
+    printf("pubsub_topicSubscriptionDisconnectPublisher : pubURL = %s\n", pubURL);
+    celix_status_t status = CELIX_SUCCESS;
+    struct epoll_event ev;
+    memset(&ev, 0, sizeof(ev));
+
+    celixThreadMutex_lock(&ts->ts_lock);
+
+    int *s = hashMap_remove(ts->socketMap, pubURL);
+    if(epoll_ctl(ts->topicEpollFd, EPOLL_CTL_DEL, *s, &ev) == -1) {
+        perror("epoll_ctl() EPOLL_CTL_DEL");
+        status = CELIX_SERVICE_EXCEPTION;
+    }
+    free(s);
+
+    celixThreadMutex_unlock(&ts->ts_lock);
+
+	return status;
+}
+
+celix_status_t pubsub_topicSubscriptionAddSubscriber(topic_subscription_pt ts, pubsub_endpoint_pt subEP){
+	celix_status_t status = CELIX_SUCCESS;
+
+	celixThreadMutex_lock(&ts->ts_lock);
+
+	arrayList_add(ts->sub_ep_list,subEP);
+
+	celixThreadMutex_unlock(&ts->ts_lock);
+
+	return status;
+
+}
+
+celix_status_t pubsub_topicIncreaseNrSubscribers(topic_subscription_pt ts) {
+	celix_status_t status = CELIX_SUCCESS;
+
+	celixThreadMutex_lock(&ts->ts_lock);
+
+	ts->nrSubscribers++;
+
+	celixThreadMutex_unlock(&ts->ts_lock);
+
+	return status;
+}
+
+celix_status_t pubsub_topicSubscriptionRemoveSubscriber(topic_subscription_pt ts, pubsub_endpoint_pt subEP){
+	celix_status_t status = CELIX_SUCCESS;
+
+	celixThreadMutex_lock(&ts->ts_lock);
+
+	arrayList_removeElement(ts->sub_ep_list,subEP);
+
+	celixThreadMutex_unlock(&ts->ts_lock);
+
+	return status;
+
+}
+
+celix_status_t pubsub_topicDecreaseNrSubscribers(topic_subscription_pt ts) {
+	celix_status_t status = CELIX_SUCCESS;
+
+	celixThreadMutex_lock(&ts->ts_lock);
+
+	ts->nrSubscribers--;
+
+	celixThreadMutex_unlock(&ts->ts_lock);
+
+	return status;
+}
+
+unsigned int pubsub_topicGetNrSubscribers(topic_subscription_pt ts) {
+	return ts->nrSubscribers;
+}
+
+static celix_status_t topicsub_subscriberTracked(void * handle, service_reference_pt reference, void * service){
+	celix_status_t status = CELIX_SUCCESS;
+	topic_subscription_pt ts = handle;
+
+	celixThreadMutex_lock(&ts->ts_lock);
+	if (!hashMap_containsKey(ts->servicesMap, service)) {
+		hash_map_pt msgTypes = hashMap_create(uintHash, NULL, uintEquals, NULL); //key = msgId, value = pubsub_message_type
+
+		bundle_pt bundle = NULL;
+		serviceReference_getBundle(reference, &bundle);
+		pubsubSerializer_fillMsgTypesMap(msgTypes,bundle);
+
+		if(hashMap_size(msgTypes)==0){ //If the msgTypes hashMap is not filled, the service is an unsupported subscriber
+			hashMap_destroy(msgTypes,false,false);
+			printf("TS: Unsupported subscriber!\n");
+		}
+		else{
+			hashMap_put(ts->servicesMap, service, msgTypes);
+		}
+
+	}
+	celixThreadMutex_unlock(&ts->ts_lock);
+	printf("TS: New subscriber registered.\n");
+	return status;
+
+}
+
+static celix_status_t topicsub_subscriberUntracked(void * handle, service_reference_pt reference, void * service){
+	celix_status_t status = CELIX_SUCCESS;
+	topic_subscription_pt ts = handle;
+
+	celixThreadMutex_lock(&ts->ts_lock);
+	if (hashMap_containsKey(ts->servicesMap, service)) {
+		hash_map_pt msgTypes = hashMap_remove(ts->servicesMap, service);
+		if(msgTypes!=NULL){
+			pubsubSerializer_emptyMsgTypesMap(msgTypes);
+			hashMap_destroy(msgTypes,false,false);
+		}
+	}
+	celixThreadMutex_unlock(&ts->ts_lock);
+
+	printf("TS: Subscriber unregistered.\n");
+	return status;
+}
+
+
+static void process_msg(topic_subscription_pt sub,pubsub_udp_msg_pt msg){
+
+	hash_map_iterator_pt iter = hashMapIterator_create(sub->servicesMap);
+	while (hashMapIterator_hasNext(iter)) {
+		hash_map_entry_pt entry = hashMapIterator_nextEntry(iter);
+		pubsub_subscriber_pt subsvc = hashMapEntry_getKey(entry);
+		hash_map_pt msgTypes = hashMapEntry_getValue(entry);
+
+		pubsub_message_type *msgType = hashMap_get(msgTypes,&(msg->header.type));
+		if (msgType == NULL) {
+			printf("TS: Primary message %d not supported. NOT sending any part of the whole message.\n",msg->header.type);
+		}
+		else{
+			void *msgInst = NULL;
+			char *name = pubsubSerializer_getName(msgType);
+			version_pt msgVersion = pubsubSerializer_getVersion(msgType);
+
+			bool validVersion = checkVersion(msgVersion,&msg->header);
+
+			if(validVersion){
+				int rc = pubsubSerializer_deserialize(msgType, (const void *) msg->payload, &msgInst);
+
+				if (rc != -1) {
+					bool release = true;
+					pubsub_multipart_callbacks_t mp_callbacks;
+					mp_callbacks.handle = sub;
+					mp_callbacks.localMsgTypeIdForMsgType = pubsub_localMsgTypeIdForMsgType;
+					mp_callbacks.getMultipart = NULL;
+
+					subsvc->receive(subsvc->handle, name, msg->header.type, msgInst, &mp_callbacks, &release);
+					if(release){
+						pubsubSerializer_freeMsg(msgType, msgInst);
+					}
+				}
+				else{
+					printf("TS: Cannot deserialize msgType %s.\n",name);
+				}
+
+			}
+			else{
+				int major=0,minor=0;
+				version_getMajor(msgVersion,&major);
+				version_getMinor(msgVersion,&minor);
+				printf("TS: Version mismatch for primary message '%s' (have %d.%d, received %u.%u). NOT sending any part of the whole message.\n",name,major,minor,msg->header.major,msg->header.minor);
+			}
+
+		}
+	}
+	hashMapIterator_destroy(iter);
+}
+
+static void* udp_recv_thread_func(void * arg) {
+    topic_subscription_pt sub = (topic_subscription_pt) arg;
+
+    struct epoll_event events[MAX_EPOLL_EVENTS];
+
+    while (sub->running) {
+        int nfds = epoll_wait(sub->topicEpollFd, events, MAX_EPOLL_EVENTS, RECV_THREAD_TIMEOUT * 1000);
+        int i;
+        for(i = 0; i < nfds; i++ ) {
+            unsigned int index;
+            unsigned int size;
+            if(largeUdp_dataAvailable(sub->largeUdpHandle, events[i].data.fd, &index, &size) == true) {
+                // Handle data
+                pubsub_udp_msg_pt udpMsg = NULL;
+                if(largeUdp_read(sub->largeUdpHandle, index, (void**)&udpMsg, size) != 0) {
+                	printf("TS: ERROR largeUdp_read with index %d\n", index);
+                	continue;
+                }
+
+                process_msg(sub, udpMsg);
+
+                free(udpMsg);
+            }
+        }
+    }
+
+    return NULL;
+}
+
+
+static void sigusr1_sighandler(int signo){
+	printf("TS: Topic subscription being shut down...\n");
+	return;
+}
+
+static bool checkVersion(version_pt msgVersion,pubsub_msg_header_pt hdr){
+	bool check=false;
+	int major=0,minor=0;
+
+	if(msgVersion!=NULL){
+		version_getMajor(msgVersion,&major);
+		version_getMinor(msgVersion,&minor);
+		if(hdr->major==((unsigned char)major)){ /* Different major means incompatible */
+			check = (hdr->minor>=((unsigned char)minor)); /* Compatible only if the provider has a minor equals or greater (means compatible update) */
+		}
+	}
+
+	return check;
+}
+
+static int pubsub_localMsgTypeIdForMsgType(void* handle, const char* msgType, unsigned int* msgTypeId){
+	*msgTypeId = pubsubSerializer_hashCode(msgType);
+	return 0;
+}
+

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_admin_zmq/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_admin_zmq/CMakeLists.txt b/celix-pubsub/pubsub/pubsub_admin_zmq/CMakeLists.txt
new file mode 100644
index 0000000..9ca4ddc
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_admin_zmq/CMakeLists.txt
@@ -0,0 +1,70 @@
+# 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.
+
+find_package(ZMQ REQUIRED)
+find_package(CZMQ REQUIRED)
+find_package(Jansson REQUIRED)
+
+include_directories("${ZMQ_INCLUDE_DIR}")
+include_directories("${CZMQ_INCLUDE_DIR}")
+include_directories("${JANSSON_INCLUDE_DIR}")
+include_directories("${PROJECT_SOURCE_DIR}/utils/public/include")
+include_directories("${PROJECT_SOURCE_DIR}/log_service/public/include")
+include_directories("${PROJECT_SOURCE_DIR}/dfi/public/include")
+include_directories("${PROJECT_SOURCE_DIR}/pubsub/pubsub_common/public/include")
+include_directories("${PROJECT_SOURCE_DIR}/pubsub/api/pubsub")
+include_directories("private/include")
+include_directories("public/include")
+if (SERIALIZER_PATH)
+	include_directories("${SERIALIZER_PATH}/include")
+endif()
+if (SERIALIZER_LIB_INCLUDE_DIR)
+	include_directories("${SERIALIZER_LIB_INCLUDE_DIR}")
+endif()
+if (SERIALIZER_LIB_DIR)
+	link_directories("${SERIALIZER_LIB_DIR}")
+endif()
+
+if (ENABLE_ZMQ_SECURITY)
+	add_definitions(-DUSE_ZMQ_SECURITY=1)
+
+	find_package(OpenSSL 1.1.0 REQUIRED)
+	include_directories("${OPENSSL_INCLUDE_DIR}")
+
+	set (ZMQ_CRYPTO_C "private/src/zmq_crypto.c")
+endif()
+
+add_bundle(org.apache.celix.pubsub_admin.PubSubAdmin
+    BUNDLE_SYMBOLICNAME "apache_celix_pubsub_admin"
+    VERSION "1.0.0"
+    SOURCES
+    	private/src/psa_activator.c
+    	private/src/pubsub_admin_impl.c
+    	private/src/topic_subscription.c
+    	private/src/topic_publication.c
+    	${ZMQ_CRYPTO_C}
+    	${PROJECT_SOURCE_DIR}/pubsub/pubsub_common/public/src/pubsub_endpoint.c
+    	${PROJECT_SOURCE_DIR}/pubsub/pubsub_common/public/src/log_helper.c
+    	${PROJECT_SOURCE_DIR}/pubsub/pubsub_common/public/src/dyn_msg_utils.c
+    	${PROJECT_SOURCE_DIR}/pubsub/pubsub_common/public/src/pubsub_utils.c
+    	${PUBSUB_SERIALIZER_SRC}
+)
+
+set_target_properties(org.apache.celix.pubsub_admin.PubSubAdmin PROPERTIES INSTALL_RPATH "$ORIGIN")
+target_link_libraries(org.apache.celix.pubsub_admin.PubSubAdmin ${CELIX_LIBRARIES} ${ZMQ_LIBRARIES} ${CZMQ_LIBRARIES} ${JANSSON_LIBRARIES} ${OPENSSL_CRYPTO_LIBRARY} ${SERIALIZER_LIBRARY})
+install_bundle(org.apache.celix.pubsub_admin.PubSubAdmin)
+

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_admin_zmq/private/include/pubsub_admin_impl.h
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_admin_zmq/private/include/pubsub_admin_impl.h b/celix-pubsub/pubsub/pubsub_admin_zmq/private/include/pubsub_admin_impl.h
new file mode 100644
index 0000000..cc28ccc
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_admin_zmq/private/include/pubsub_admin_impl.h
@@ -0,0 +1,86 @@
+/**
+ *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.
+ */
+/*
+ * pubsub_admin_impl.h
+ *
+ *  \date       Dec 5, 2013
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#ifndef PUBSUB_ADMIN_IMPL_H_
+#define PUBSUB_ADMIN_IMPL_H_
+
+#include <czmq.h>
+/* The following undefs prevent the collision between:
+ * - sys/syslog.h (which is included within czmq)
+ * - celix/dfi/dfi_log_util.h
+ */
+#undef LOG_DEBUG
+#undef LOG_WARNING
+#undef LOG_INFO
+#undef LOG_WARNING
+
+#include "pubsub_admin.h"
+#include "log_helper.h"
+
+#define PSA_ZMQ_BASE_PORT "PSA_ZMQ_BASE_PORT"
+#define PSA_ZMQ_MAX_PORT "PSA_ZMQ_MAX_PORT"
+
+#define PSA_ZMQ_DEFAULT_BASE_PORT 5501
+#define PSA_ZMQ_DEFAULT_MAX_PORT 6000
+
+struct pubsub_admin {
+
+	bundle_context_pt bundle_context;
+	log_helper_pt loghelper;
+
+	celix_thread_mutex_t localPublicationsLock;
+	hash_map_pt localPublications;//<topic(string),service_factory_pt>
+
+	celix_thread_mutex_t externalPublicationsLock;
+	hash_map_pt externalPublications;//<topic(string),List<pubsub_ep>>
+
+	celix_thread_mutex_t subscriptionsLock;
+	hash_map_pt subscriptions; //<topic(string),topic_subscription>
+
+	celix_thread_mutex_t pendingSubscriptionsLock;
+	hash_map_pt pendingSubscriptions; //<topic(string),List<pubsub_ep>>
+
+	char* ipAddress;
+
+	zactor_t* zmq_auth;
+
+    unsigned int basePort;
+    unsigned int maxPort;
+};
+
+celix_status_t pubsubAdmin_create(bundle_context_pt context, pubsub_admin_pt *admin);
+celix_status_t pubsubAdmin_destroy(pubsub_admin_pt admin);
+
+celix_status_t pubsubAdmin_addSubscription(pubsub_admin_pt admin,pubsub_endpoint_pt subEP);
+celix_status_t pubsubAdmin_removeSubscription(pubsub_admin_pt admin,pubsub_endpoint_pt subEP);
+
+celix_status_t pubsubAdmin_addPublication(pubsub_admin_pt admin,pubsub_endpoint_pt pubEP);
+celix_status_t pubsubAdmin_removePublication(pubsub_admin_pt admin,pubsub_endpoint_pt pubEP);
+
+celix_status_t pubsubAdmin_closeAllPublications(pubsub_admin_pt admin,char* scope, char* topic);
+celix_status_t pubsubAdmin_closeAllSubscriptions(pubsub_admin_pt admin,char* scope,char* topic);
+
+#endif /* PUBSUB_ADMIN_IMPL_H_ */

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_admin_zmq/private/include/pubsub_publish_service_private.h
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_admin_zmq/private/include/pubsub_publish_service_private.h b/celix-pubsub/pubsub/pubsub_admin_zmq/private/include/pubsub_publish_service_private.h
new file mode 100644
index 0000000..1c12eb8
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_admin_zmq/private/include/pubsub_publish_service_private.h
@@ -0,0 +1,47 @@
+/**
+ *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.
+ */
+/*
+ * pubsub_publish_service_private.h
+ *
+ *  \date       Sep 24, 2015
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#ifndef PUBSUB_PUBLISH_SERVICE_PRIVATE_H_
+#define PUBSUB_PUBLISH_SERVICE_PRIVATE_H_
+
+#include "publisher.h"
+#include "pubsub_endpoint.h"
+#include "pubsub_common.h"
+
+typedef struct topic_publication *topic_publication_pt;
+
+celix_status_t pubsub_topicPublicationCreate(bundle_context_pt bundle_context,pubsub_endpoint_pt pubEP,char* bindIP, unsigned int basePort, unsigned int maxPort, topic_publication_pt *out);
+celix_status_t pubsub_topicPublicationDestroy(topic_publication_pt pub);
+
+celix_status_t pubsub_topicPublicationAddPublisherEP(topic_publication_pt pub,pubsub_endpoint_pt ep);
+celix_status_t pubsub_topicPublicationRemovePublisherEP(topic_publication_pt pub,pubsub_endpoint_pt ep);
+
+celix_status_t pubsub_topicPublicationStart(bundle_context_pt bundle_context,topic_publication_pt pub,service_factory_pt* svcFactory);
+celix_status_t pubsub_topicPublicationStop(topic_publication_pt pub);
+
+array_list_pt pubsub_topicPublicationGetPublisherList(topic_publication_pt pub);
+
+#endif /* PUBSUB_PUBLISH_SERVICE_PRIVATE_H_ */

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_admin_zmq/private/include/topic_subscription.h
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_admin_zmq/private/include/topic_subscription.h b/celix-pubsub/pubsub/pubsub_admin_zmq/private/include/topic_subscription.h
new file mode 100644
index 0000000..d4c65bb
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_admin_zmq/private/include/topic_subscription.h
@@ -0,0 +1,57 @@
+/**
+ *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.
+ */
+/*
+ * topic_subscription.h
+ *
+ *  \date       Sep 22, 2015
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#ifndef TOPIC_SUBSCRIPTION_H_
+#define TOPIC_SUBSCRIPTION_H_
+
+#include "celix_threads.h"
+#include "array_list.h"
+#include "celixbool.h"
+#include "service_tracker.h"
+
+#include "pubsub_endpoint.h"
+#include "pubsub_common.h"
+
+typedef struct topic_subscription* topic_subscription_pt;
+
+celix_status_t pubsub_topicSubscriptionCreate(bundle_context_pt bundle_context,char* scope, char* topic,topic_subscription_pt* out);
+celix_status_t pubsub_topicSubscriptionDestroy(topic_subscription_pt ts);
+celix_status_t pubsub_topicSubscriptionStart(topic_subscription_pt ts);
+celix_status_t pubsub_topicSubscriptionStop(topic_subscription_pt ts);
+
+celix_status_t pubsub_topicSubscriptionAddConnectPublisherToPendingList(topic_subscription_pt ts, char* pubURL);
+celix_status_t pubsub_topicSubscriptionAddDisconnectPublisherToPendingList(topic_subscription_pt ts, char* pubURL);
+celix_status_t pubsub_topicSubscriptionConnectPublisher(topic_subscription_pt ts, char* pubURL);
+celix_status_t pubsub_topicSubscriptionDisconnectPublisher(topic_subscription_pt ts, char* pubURL);
+
+celix_status_t pubsub_topicSubscriptionAddSubscriber(topic_subscription_pt ts, pubsub_endpoint_pt subEP);
+celix_status_t pubsub_topicSubscriptionRemoveSubscriber(topic_subscription_pt ts, pubsub_endpoint_pt subEP);
+
+celix_status_t pubsub_topicIncreaseNrSubscribers(topic_subscription_pt subscription);
+celix_status_t pubsub_topicDecreaseNrSubscribers(topic_subscription_pt subscription);
+unsigned int pubsub_topicGetNrSubscribers(topic_subscription_pt subscription);
+
+#endif /*TOPIC_SUBSCRIPTION_H_ */

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_admin_zmq/private/include/zmq_crypto.h
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_admin_zmq/private/include/zmq_crypto.h b/celix-pubsub/pubsub/pubsub_admin_zmq/private/include/zmq_crypto.h
new file mode 100644
index 0000000..f1a990f
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_admin_zmq/private/include/zmq_crypto.h
@@ -0,0 +1,41 @@
+/**
+ *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.
+ */
+/*
+ * zmq_crypto.h
+ *
+ *  \date       Dec 2, 2016
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#ifndef ZMQ_CRYPTO_H_
+#define ZMQ_CRYPTO_H_
+
+#include <czmq.h>
+
+#define PROPERTY_KEYS_FILE_PATH "keys.file.path"
+#define PROPERTY_KEYS_FILE_NAME "keys.file.name"
+#define DEFAULT_KEYS_FILE_PATH "/etc/"
+#define DEFAULT_KEYS_FILE_NAME "pubsub.keys"
+
+zcert_t* get_zcert_from_encoded_file(char* keysFilePath, char* keysFileName, char* file_path);
+int generate_sha256_hash(char* text, unsigned char* digest);
+int decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key, unsigned char *iv, unsigned char *plaintext);
+
+#endif

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_admin_zmq/private/src/psa_activator.c
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_admin_zmq/private/src/psa_activator.c b/celix-pubsub/pubsub/pubsub_admin_zmq/private/src/psa_activator.c
new file mode 100644
index 0000000..50b28ec
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_admin_zmq/private/src/psa_activator.c
@@ -0,0 +1,112 @@
+/**
+ *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.
+ */
+/*
+ * psa_activator.c
+ *
+ *  \date       Sep 30, 2011
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#include <stdlib.h>
+
+#include "bundle_activator.h"
+#include "service_registration.h"
+
+#include "pubsub_admin_impl.h"
+
+
+struct activator {
+	pubsub_admin_pt admin;
+	pubsub_admin_service_pt adminService;
+	service_registration_pt registration;
+};
+
+celix_status_t bundleActivator_create(bundle_context_pt context, void **userData) {
+	celix_status_t status = CELIX_SUCCESS;
+	struct activator *activator;
+
+	activator = calloc(1, sizeof(*activator));
+	if (!activator) {
+		status = CELIX_ENOMEM;
+	}
+	else{
+		*userData = activator;
+		status = pubsubAdmin_create(context, &(activator->admin));
+	}
+
+	return status;
+}
+
+celix_status_t bundleActivator_start(void * userData, bundle_context_pt context) {
+	celix_status_t status = CELIX_SUCCESS;
+	struct activator *activator = userData;
+	pubsub_admin_service_pt pubsubAdminSvc = calloc(1, sizeof(*pubsubAdminSvc));
+
+	if (!pubsubAdminSvc) {
+		status = CELIX_ENOMEM;
+	}
+	else{
+		pubsubAdminSvc->admin = activator->admin;
+
+		pubsubAdminSvc->addPublication = pubsubAdmin_addPublication;
+		pubsubAdminSvc->removePublication = pubsubAdmin_removePublication;
+
+		pubsubAdminSvc->addSubscription = pubsubAdmin_addSubscription;
+		pubsubAdminSvc->removeSubscription = pubsubAdmin_removeSubscription;
+
+		pubsubAdminSvc->closeAllPublications = pubsubAdmin_closeAllPublications;
+		pubsubAdminSvc->closeAllSubscriptions = pubsubAdmin_closeAllSubscriptions;
+
+		activator->adminService = pubsubAdminSvc;
+
+		status = bundleContext_registerService(context, PUBSUB_ADMIN_SERVICE, pubsubAdminSvc, NULL, &activator->registration);
+
+	}
+
+
+	return status;
+}
+
+celix_status_t bundleActivator_stop(void * userData, bundle_context_pt context) {
+	celix_status_t status = CELIX_SUCCESS;
+	struct activator *activator = userData;
+
+	serviceRegistration_unregister(activator->registration);
+	activator->registration = NULL;
+
+	free(activator->adminService);
+	activator->adminService = NULL;
+
+	return status;
+}
+
+celix_status_t bundleActivator_destroy(void * userData, bundle_context_pt context) {
+	celix_status_t status = CELIX_SUCCESS;
+	struct activator *activator = userData;
+
+	pubsubAdmin_destroy(activator->admin);
+	activator->admin = NULL;
+
+	free(activator);
+
+	return status;
+}
+
+


[2/6] celix git commit: CELIX-389: Adds Celix Publish Subscribe donation.

Posted by pn...@apache.org.
http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_common/public/include/pubsub_serializer.h
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_common/public/include/pubsub_serializer.h b/celix-pubsub/pubsub/pubsub_common/public/include/pubsub_serializer.h
new file mode 100644
index 0000000..c1f9a4b
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_common/public/include/pubsub_serializer.h
@@ -0,0 +1,47 @@
+/**
+ *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.
+ */
+/*
+ * pubsub_serializer.h
+ *
+ *  \date       Dec 7, 2016
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#ifndef PUBSUB_SERIALIZER_H
+#define PUBSUB_SERIALIZER_H
+
+#include "bundle.h"
+#include "hash_map.h"
+
+typedef struct _pubsub_message_type pubsub_message_type;
+
+int pubsubSerializer_serialize(pubsub_message_type *msgType, const void *input, void **output, int *outputLen);
+int pubsubSerializer_deserialize(pubsub_message_type *msgType, const void *input, void **output);
+
+unsigned int pubsubSerializer_hashCode(const char *string);
+version_pt pubsubSerializer_getVersion(pubsub_message_type *msgType);
+char* pubsubSerializer_getName(pubsub_message_type *msgType);
+
+void pubsubSerializer_fillMsgTypesMap(hash_map_pt msgTypesMap,bundle_pt bundle);
+void pubsubSerializer_emptyMsgTypesMap(hash_map_pt msgTypesMap);
+
+void pubsubSerializer_freeMsg(pubsub_message_type *msgType, void *msg);
+
+#endif

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_common/public/include/pubsub_topic_info.descriptor
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_common/public/include/pubsub_topic_info.descriptor b/celix-pubsub/pubsub/pubsub_common/public/include/pubsub_topic_info.descriptor
new file mode 100644
index 0000000..c01a2fd
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_common/public/include/pubsub_topic_info.descriptor
@@ -0,0 +1,10 @@
+:header
+type=interface
+name=pubsub_topic_info
+version=1.0.0
+:annotations
+:types
+:methods
+getParticipantsNumber(t)i=getParticipantsNumber(#am=handle;Pt#am=pre;*i)N
+getSubscribersNumber(t)i=getSubscribersNumber(#am=handle;Pt#am=pre;*i)N
+getPublishersNumber(t)i=getPublishersNumber(#am=handle;Pt#am=pre;*i)N

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_common/public/include/pubsub_utils.h
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_common/public/include/pubsub_utils.h b/celix-pubsub/pubsub/pubsub_common/public/include/pubsub_utils.h
new file mode 100644
index 0000000..aff5c72
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_common/public/include/pubsub_utils.h
@@ -0,0 +1,39 @@
+/**
+ *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.
+ */
+/*
+ * pubsub_utils.h
+ *
+ *  \date       Sep 24, 2015
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#ifndef PUBSUB_UTILS_H_
+#define PUBSUB_UTILS_H_
+
+#include "bundle_context.h"
+#include "array_list.h"
+
+char* pubsub_getScopeFromFilter(char* bundle_filter);
+char* pubsub_getTopicFromFilter(char* bundle_filter);
+char* pubsub_getKeysBundleDir(bundle_context_pt ctx);
+array_list_pt pubsub_getTopicsFromString(char* string);
+
+
+#endif /* PUBSUB_UTILS_H_ */

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_common/public/src/dyn_msg_utils.c
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_common/public/src/dyn_msg_utils.c b/celix-pubsub/pubsub/pubsub_common/public/src/dyn_msg_utils.c
new file mode 100644
index 0000000..8309c11
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_common/public/src/dyn_msg_utils.c
@@ -0,0 +1,156 @@
+/**
+ *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.
+ */
+/*
+ * dyn_msg_utils.c
+ *
+ *  \date       Nov 11, 2015
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <dirent.h>
+
+#include "utils.h"
+#include "dyn_message.h"
+
+#include "dyn_msg_utils.h"
+
+#define SYSTEM_BUNDLE_ARCHIVE_PATH 		"CELIX_FRAMEWORK_EXTENDER_PATH"
+
+static char * getMsgDescriptionDir(bundle_pt bundle);
+static void addMsgDescriptorsFromBundle(const char *root, bundle_pt bundle, hash_map_pt msgTypesMap);
+
+
+unsigned int uintHash(const void * uintNum) {
+	return *((unsigned int*)uintNum);
+}
+
+int uintEquals(const void * uintNum, const void * toCompare) {
+	return ( (*((unsigned int*)uintNum)) == (*((unsigned int*)toCompare)) );
+}
+
+void fillMsgTypesMap(hash_map_pt msgTypesMap,bundle_pt bundle){
+
+	char *root = NULL;
+	char *metaInfPath = NULL;
+
+	root = getMsgDescriptionDir(bundle);
+	asprintf(&metaInfPath, "%s/META-INF/descriptors", root);
+
+	addMsgDescriptorsFromBundle(root, bundle, msgTypesMap);
+	addMsgDescriptorsFromBundle(metaInfPath, bundle, msgTypesMap);
+
+	free(metaInfPath);
+	if(root!=NULL){
+		free(root);
+	}
+}
+
+void emptyMsgTypesMap(hash_map_pt msgTypesMap)
+{
+	hash_map_iterator_pt iter = hashMapIterator_create(msgTypesMap);
+
+	while(hashMapIterator_hasNext(iter)){
+		hash_map_entry_pt entry = hashMapIterator_nextEntry(iter);
+		dynMessage_destroy( ((dyn_message_type *) hashMapEntry_getValue(entry)) );
+	}
+	hashMap_clear(msgTypesMap, true, false);
+	hashMapIterator_destroy(iter);
+}
+
+static char * getMsgDescriptionDir(bundle_pt bundle)
+{
+	char *root = NULL;
+
+	bool isSystemBundle = false;
+	bundle_isSystemBundle(bundle, &isSystemBundle);
+
+	if(isSystemBundle == true) {
+		bundle_context_pt context;
+		bundle_getContext(bundle, &context);
+
+		const char *prop = NULL;
+
+		bundleContext_getProperty(context, SYSTEM_BUNDLE_ARCHIVE_PATH, &prop);
+
+		if(prop != NULL) {
+			root = strdup(prop);
+		} else {
+			root = getcwd(NULL, 0);
+		}
+	} else {
+	    char *dir;
+		bundle_getEntry(bundle, ".", &dir);
+		root = dir;
+	}
+
+	return root;
+}
+
+
+static void addMsgDescriptorsFromBundle(const char *root, bundle_pt bundle, hash_map_pt msgTypesMap)
+{
+	char path[128];
+	struct dirent *entry = NULL;
+	DIR *dir = opendir(root);
+
+	if(dir) {
+		entry = readdir(dir);
+	}
+
+	while (entry != NULL) {
+
+		if (strstr(entry->d_name, ".descriptor") != NULL) {
+
+			printf("DMU: Parsing entry '%s'\n", entry->d_name);
+
+			memset(path,0,128);
+			snprintf(path, 128, "%s/%s", root, entry->d_name);
+			FILE *stream = fopen(path,"r");
+
+			dyn_message_type* msgType = NULL;
+
+			int rc = dynMessage_parse(stream, &msgType);
+			if (rc == 0 && msgType!=NULL) {
+
+				char* msgName = NULL;
+				dynMessage_getName(msgType,&msgName);
+
+				if(msgName!=NULL){
+					unsigned int* msgId = malloc(sizeof(unsigned int));
+					*msgId = utils_stringHash(msgName);
+					hashMap_put(msgTypesMap,msgId,msgType);
+				}
+
+			}
+			else{
+				printf("DMU: cannot parse message from descriptor %s\n.",path);
+			}
+			fclose(stream);
+		}
+		entry = readdir(dir);
+	}
+
+	if(dir) {
+		closedir(dir);
+	}
+}

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_common/public/src/etcd.c
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_common/public/src/etcd.c b/celix-pubsub/pubsub/pubsub_common/public/src/etcd.c
new file mode 100644
index 0000000..bbb17c3
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_common/public/src/etcd.c
@@ -0,0 +1,476 @@
+/**
+ *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 <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+#include <curl/curl.h>
+#include <jansson.h>
+#include "etcd.h"
+
+#define ETCD_JSON_NODE                  "node"
+#define ETCD_JSON_PREVNODE              "prevNode"
+#define ETCD_JSON_NODES                 "nodes"
+#define ETCD_JSON_ACTION                "action"
+#define ETCD_JSON_KEY                   "key"
+#define ETCD_JSON_VALUE                 "value"
+#define ETCD_JSON_DIR                   "dir"
+#define ETCD_JSON_MODIFIEDINDEX         "modifiedIndex"
+
+#define MAX_OVERHEAD_LENGTH           64
+#define DEFAULT_CURL_TIMEOUT          10
+#define DEFAULT_CURL_CONECTTIMEOUT    10
+
+typedef enum {
+	GET, PUT, DELETE
+} request_t;
+
+static const char* etcd_server;
+static int etcd_port = 0;
+
+struct MemoryStruct {
+	char *memory;
+	size_t size;
+};
+
+
+/**
+ * Static function declarations
+ */
+static int performRequest(char* url, request_t request, void* callback, void* reqData, void* repData);
+static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp);
+/**
+ * External function definition
+ */
+
+
+/**
+ * etcd_init
+ */
+int etcd_init(const char* server, int port) {
+        etcd_server = server;
+        etcd_port = port;
+
+        return curl_global_init(CURL_GLOBAL_ALL) != 0;
+}
+
+
+/**
+ * etcd_get
+ */
+int etcd_get(const char* key, char** value, int* modifiedIndex) {
+    json_t* js_root = NULL;
+    json_t* js_node = NULL;
+    json_t* js_value = NULL;
+    json_t* js_modifiedIndex = NULL;
+    json_error_t error;
+    int res = -1;
+    struct MemoryStruct reply;
+
+    reply.memory = malloc(1); /* will be grown as needed by the realloc above */
+    reply.size = 0; /* no data at this point */
+
+    int retVal = -1;
+    char *url;
+    asprintf(&url, "http://%s:%d/v2/keys/%s", etcd_server, etcd_port, key);
+    res = performRequest(url, GET, WriteMemoryCallback, NULL, (void*) &reply);
+    free(url);
+    if (res == CURLE_OK) {
+        js_root = json_loads(reply.memory, 0, &error);
+
+        if (js_root != NULL) {
+            js_node = json_object_get(js_root, ETCD_JSON_NODE);
+        }
+        if (js_node != NULL) {
+            js_value = json_object_get(js_node, ETCD_JSON_VALUE);
+            js_modifiedIndex = json_object_get(js_node,
+            ETCD_JSON_MODIFIEDINDEX);
+
+            if (js_modifiedIndex != NULL && js_value != NULL) {
+                if (modifiedIndex) {
+                    *modifiedIndex = json_integer_value(js_modifiedIndex);
+                }
+                *value = strdup(json_string_value(js_value));
+                retVal = 0;
+            }
+        }
+        if (js_root != NULL) {
+            json_decref(js_root);
+        }
+    }
+
+    if (reply.memory) {
+        free(reply.memory);
+    }
+    if(retVal != 0) {
+        value = NULL;
+    }
+    return retVal;
+}
+
+
+static int etcd_get_recursive_values(json_t* js_root, etcd_key_value_callback callback, void *arg, json_int_t *mod_index) {
+    json_t *js_nodes;
+    if ((js_nodes = json_object_get(js_root, ETCD_JSON_NODES)) != NULL) {
+        // subarray
+        if (json_is_array(js_nodes)) {
+            int len = json_array_size(js_nodes);
+            for (int i = 0; i < len; i++) {
+                json_t *js_object = json_array_get(js_nodes, i);
+                json_t *js_mod_index = json_object_get(js_object, ETCD_JSON_MODIFIEDINDEX);
+
+                if(js_mod_index != NULL) {
+                    json_int_t index = json_integer_value(js_mod_index);
+                    if(*mod_index < index) {
+                        *mod_index = index;
+                    }
+                } else {
+                    printf("[ETCDLIB] Error: No INDEX found for key!\n");
+                }
+
+                if (json_object_get(js_object, ETCD_JSON_NODES)) {
+                    // node contains nodes
+                    etcd_get_recursive_values(js_object, callback, arg, mod_index);
+                } else {
+                    json_t* js_key = json_object_get(js_object, ETCD_JSON_KEY);
+                    json_t* js_value = json_object_get(js_object, ETCD_JSON_VALUE);
+
+                    if (js_key && js_value) {
+                        if (!json_object_get(js_object, ETCD_JSON_DIR)) {
+                            callback(json_string_value(js_key), json_string_value(js_value), arg);
+                        }
+                    } //else empty etcd directory, not an error.
+
+                }
+            }
+        } else {
+            printf("[ETCDLIB] Error: misformatted JSON: nodes element is not an array !!\n");
+        }
+    } else {
+        printf("[ETCDLIB] Error: nodes element not found!!\n");
+    }
+
+    return (*index > 0 ? 0 : 1);
+}
+
+/**
+ * etcd_get_directory
+ */
+int etcd_get_directory(const char* directory, etcd_key_value_callback callback, void* arg, long long* modifiedIndex) {
+    json_t* js_root = NULL;
+    json_t* js_rootnode = NULL;
+
+    json_error_t error;
+    int res;
+    struct MemoryStruct reply;
+
+    reply.memory = malloc(1); /* will be grown as needed by the realloc above */
+    reply.size = 0; /* no data at this point */
+
+    int retVal = 0;
+    char *url;
+
+    asprintf(&url, "http://%s:%d/v2/keys/%s?recursive=true", etcd_server, etcd_port, directory);
+
+    res = performRequest(url, GET, WriteMemoryCallback, NULL, (void*) &reply);
+    free(url);
+
+    if (res == CURLE_OK) {
+        js_root = json_loads(reply.memory, 0, &error);
+        if (js_root != NULL) {
+            js_rootnode = json_object_get(js_root, ETCD_JSON_NODE);
+        } else {
+            retVal = -1;
+            printf("ERROR ETCD: %s in js_root not found", ETCD_JSON_NODE);
+        }
+        if (js_rootnode != NULL) {
+            *modifiedIndex = 0;
+            retVal = etcd_get_recursive_values(js_rootnode, callback, arg, (json_int_t*)modifiedIndex);
+        }
+        if (js_root != NULL) {
+            json_decref(js_root);
+        }
+    }
+
+    if (reply.memory) {
+        free(reply.memory);
+    }
+
+    return retVal;
+}
+
+/**
+ * etcd_set
+ */
+int etcd_set(const char* key, const char* value, int ttl, bool prevExist) {
+    json_error_t error;
+    json_t* js_root = NULL;
+    json_t* js_node = NULL;
+    json_t* js_value = NULL;
+    int retVal = -1;
+    char *url;
+    size_t req_len = strlen(value) + MAX_OVERHEAD_LENGTH;
+    char request[req_len];
+    char* requestPtr = request;
+    int res;
+    struct MemoryStruct reply;
+
+    /* Skip leading '/', etcd cannot handle this. */
+    while(*key == '/') {
+        key++;
+    }
+
+    reply.memory = calloc(1, 1); /* will be grown as needed by the realloc above */
+    reply.size = 0; /* no data at this point */
+
+    asprintf(&url, "http://%s:%d/v2/keys/%s", etcd_server, etcd_port, key);
+
+    requestPtr += snprintf(requestPtr, req_len, "value=%s", value);
+    if (ttl > 0) {
+        requestPtr += snprintf(requestPtr, req_len-(requestPtr-request), ";ttl=%d", ttl);
+    }
+
+    if (prevExist) {
+        requestPtr += snprintf(requestPtr, req_len-(requestPtr-request), ";prevExist=true");
+    }
+    res = performRequest(url, PUT, WriteMemoryCallback, request, (void*) &reply);
+    if(url) {
+        free(url);
+    }
+
+    if (res == CURLE_OK) {
+        js_root = json_loads(reply.memory, 0, &error);
+
+        if (js_root != NULL) {
+            js_node = json_object_get(js_root, ETCD_JSON_NODE);
+        }
+        if (js_node != NULL) {
+            js_value = json_object_get(js_node, ETCD_JSON_VALUE);
+        }
+        if (js_value != NULL && json_is_string(js_value)) {
+            if(strcmp(json_string_value(js_value), value) == 0) {
+                retVal = 0;
+            }
+        }
+        if (js_root != NULL) {
+            json_decref(js_root);
+        }
+    }
+
+    if (reply.memory) {
+        free(reply.memory);
+    }
+
+    return retVal;
+}
+
+
+/**
+ * etcd_set_with_check
+ */
+int etcd_set_with_check(const char* key, const char* value, int ttl, bool always_write) {
+    char *etcd_value;
+    int result = 0;
+    if (etcd_get(key, &etcd_value, NULL) == 0) {
+        if (strcmp(etcd_value, value) != 0) {
+            printf("[ETCDLIB} WARNING: value already exists and is different\n");
+            printf("   key       = %s\n", key);
+            printf("   old value = %s\n", etcd_value);
+            printf("   new value = %s\n", value);
+            result = -1;
+        }
+        if (etcd_value) {
+            free(etcd_value);
+        }
+    }
+    if(always_write || !result) {
+        result = etcd_set(key, value, ttl, false);
+    }
+    return result;
+}
+
+
+/**
+ * etcd_watch
+ */
+int etcd_watch(const char* key, long long index, char** action, char** prevValue, char** value, char** rkey, long long* modifiedIndex) {
+    json_error_t error;
+    json_t* js_root = NULL;
+    json_t* js_node = NULL;
+    json_t* js_prevNode = NULL;
+    json_t* js_action = NULL;
+    json_t* js_value = NULL;
+    json_t* js_rkey = NULL;
+    json_t* js_prevValue = NULL;
+    json_t* js_modIndex = NULL;
+    int retVal = -1;
+    char *url = NULL;
+    int res;
+    struct MemoryStruct reply;
+
+    reply.memory = malloc(1); /* will be grown as needed by the realloc above */
+    reply.size = 0; /* no data at this point */
+
+    if (index != 0)
+        asprintf(&url, "http://%s:%d/v2/keys/%s?wait=true&recursive=true&waitIndex=%lld", etcd_server, etcd_port, key, index);
+    else
+        asprintf(&url, "http://%s:%d/v2/keys/%s?wait=true&recursive=true", etcd_server, etcd_port, key);
+    res = performRequest(url, GET, WriteMemoryCallback, NULL, (void*) &reply);
+    if(url)
+        free(url);
+    if (res == CURLE_OK) {
+        js_root = json_loads(reply.memory, 0, &error);
+
+        if (js_root != NULL) {
+            js_action = json_object_get(js_root, ETCD_JSON_ACTION);
+            js_node = json_object_get(js_root, ETCD_JSON_NODE);
+            js_prevNode = json_object_get(js_root, ETCD_JSON_PREVNODE);
+            retVal = 0;
+        }
+        if (js_prevNode != NULL) {
+            js_prevValue = json_object_get(js_prevNode, ETCD_JSON_VALUE);
+        }
+        if (js_node != NULL) {
+            js_rkey = json_object_get(js_node, ETCD_JSON_KEY);
+            js_value = json_object_get(js_node, ETCD_JSON_VALUE);
+            js_modIndex = json_object_get(js_node, ETCD_JSON_MODIFIEDINDEX);
+        }
+        if (js_prevNode != NULL) {
+            js_prevValue = json_object_get(js_prevNode, ETCD_JSON_VALUE);
+        }
+        if ((prevValue != NULL) && (js_prevValue != NULL) && (json_is_string(js_prevValue))) {
+
+            *prevValue = strdup(json_string_value(js_prevValue));
+        }
+        if(modifiedIndex != NULL) {
+            if ((js_modIndex != NULL) && (json_is_integer(js_modIndex))) {
+                *modifiedIndex = json_integer_value(js_modIndex);
+            } else {
+                *modifiedIndex = index;
+            }
+        }
+        if ((rkey != NULL) && (js_rkey != NULL) && (json_is_string(js_rkey))) {
+            *rkey = strdup(json_string_value(js_rkey));
+
+        }
+        if ((action != NULL)  && (js_action != NULL)  && (json_is_string(js_action))) {
+            *action = strdup(json_string_value(js_action));
+        }
+        if ((value != NULL) && (js_value != NULL) && (json_is_string(js_value))) {
+            *value = strdup(json_string_value(js_value));
+        }
+        if (js_root != NULL) {
+            json_decref(js_root);
+        }
+
+    }
+
+    if (reply.memory) {
+        free(reply.memory);
+    }
+
+    return retVal;
+}
+
+/**
+ * etcd_del
+ */
+int etcd_del(const char* key) {
+    json_error_t error;
+    json_t* js_root = NULL;
+    json_t* js_node = NULL;
+    int retVal = -1;
+    char *url;
+    int res;
+    struct MemoryStruct reply;
+
+    reply.memory = malloc(1); /* will be grown as needed by the realloc above */
+    reply.size = 0; /* no data at this point */
+
+    asprintf(&url, "http://%s:%d/v2/keys/%s?recursive=true", etcd_server, etcd_port, key);
+    res = performRequest(url, DELETE, WriteMemoryCallback, NULL, (void*) &reply);
+    free(url);
+
+    if (res == CURLE_OK) {
+        js_root = json_loads(reply.memory, 0, &error);
+        if (js_root != NULL) {
+            js_node = json_object_get(js_root, ETCD_JSON_NODE);
+        }
+
+        if (js_node != NULL) {
+            retVal = 0;
+        }
+
+        if (js_root != NULL) {
+            json_decref(js_root);
+        }
+    }
+
+    if (reply.memory) {
+        free(reply.memory);
+    }
+
+    return retVal;
+}
+
+
+static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) {
+    size_t realsize = size * nmemb;
+    struct MemoryStruct *mem = (struct MemoryStruct *) userp;
+
+    mem->memory = realloc(mem->memory, mem->size + realsize + 1);
+    if (mem->memory == NULL) {
+        /* out of memory! */
+        printf("not enough memory (realloc returned NULL)\n");
+        return 0;
+    }
+
+    memcpy(&(mem->memory[mem->size]), contents, realsize);
+    mem->size += realsize;
+    mem->memory[mem->size] = 0;
+
+    return realsize;
+}
+
+static int performRequest(char* url, request_t request, void* callback, void* reqData, void* repData) {
+    CURL *curl = NULL;
+    CURLcode res = 0;
+    curl = curl_easy_init();
+    curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
+    curl_easy_setopt(curl, CURLOPT_TIMEOUT, DEFAULT_CURL_TIMEOUT);
+    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, DEFAULT_CURL_CONECTTIMEOUT);
+    curl_easy_setopt(curl, CURLOPT_URL, url);
+    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
+    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, callback);
+    curl_easy_setopt(curl, CURLOPT_WRITEDATA, repData);
+
+    if (request == PUT) {
+        curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
+        curl_easy_setopt(curl, CURLOPT_POST, 1L);
+        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, reqData);
+    } else if (request == DELETE) {
+        curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
+    } else if (request == GET) {
+        curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET");
+    }
+
+    res = curl_easy_perform(curl);
+    curl_easy_cleanup(curl);
+    return res;
+}

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_common/public/src/log_helper.c
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_common/public/src/log_helper.c b/celix-pubsub/pubsub/pubsub_common/public/src/log_helper.c
new file mode 100644
index 0000000..7a63363
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_common/public/src/log_helper.c
@@ -0,0 +1,209 @@
+/**
+ *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.
+ */
+/*
+ * log_helper.c
+ *
+ *  \date       Nov 10, 2014
+ *  \author     <a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright  Apache License, Version 2.0
+ */
+
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "bundle_context.h"
+#include "service_tracker.h"
+#include "celix_threads.h"
+#include "array_list.h"
+
+#include "celix_errno.h"
+#include "log_service.h"
+
+#include "log_helper.h"
+
+#define LOGHELPER_ENABLE_STDOUT_FALLBACK_PROPERTY_NAME 	"LOGHELPER_ENABLE_STDOUT_FALLBACK"
+
+
+struct log_helper {
+	bundle_context_pt bundleContext;
+    service_tracker_pt logServiceTracker;
+	celix_thread_mutex_t logListLock;
+	array_list_pt logServices;
+	bool stdOutFallback;
+};
+
+celix_status_t logHelper_logServiceAdded(void *handle, service_reference_pt reference, void *service);
+celix_status_t logHelper_logServiceRemoved(void *handle, service_reference_pt reference, void *service);
+
+
+celix_status_t logHelper_create(bundle_context_pt context, log_helper_pt* loghelper)
+{
+	celix_status_t status = CELIX_SUCCESS;
+
+	(*loghelper) = calloc(1, sizeof(**loghelper));
+
+	if (!(*loghelper))
+	{
+		status = CELIX_ENOMEM;
+	}
+	else
+	{
+		const char* stdOutFallbackStr = NULL;
+		(*loghelper)->bundleContext = context;
+		(*loghelper)->logServiceTracker = NULL;
+		(*loghelper)->stdOutFallback = false;
+
+		bundleContext_getProperty(context, LOGHELPER_ENABLE_STDOUT_FALLBACK_PROPERTY_NAME, &stdOutFallbackStr);
+
+		if (stdOutFallbackStr != NULL) {
+			(*loghelper)->stdOutFallback = true;
+		}
+
+		pthread_mutex_init(&(*loghelper)->logListLock, NULL);
+        arrayList_create(&(*loghelper)->logServices);
+	}
+
+	return status;
+}
+
+celix_status_t logHelper_start(log_helper_pt loghelper)
+{
+	celix_status_t status = CELIX_SUCCESS;
+	service_tracker_customizer_pt logTrackerCustomizer = NULL;
+
+	status = serviceTrackerCustomizer_create(loghelper, NULL, logHelper_logServiceAdded, NULL, logHelper_logServiceRemoved, &logTrackerCustomizer);
+
+	if (status == CELIX_SUCCESS) {
+		status = serviceTracker_create(loghelper->bundleContext, (char*) OSGI_LOGSERVICE_NAME, logTrackerCustomizer, &loghelper->logServiceTracker);
+	}
+
+	if (status == CELIX_SUCCESS) {
+		status = serviceTracker_open(loghelper->logServiceTracker);
+	}
+
+	return status;
+}
+
+
+
+celix_status_t logHelper_logServiceAdded(void *handle, service_reference_pt reference, void *service)
+{
+	log_helper_pt loghelper = handle;
+
+	pthread_mutex_lock(&loghelper->logListLock);
+	arrayList_add(loghelper->logServices, service);
+	pthread_mutex_unlock(&loghelper->logListLock);
+
+	return CELIX_SUCCESS;
+}
+
+celix_status_t logHelper_logServiceRemoved(void *handle, service_reference_pt reference, void *service)
+{
+	log_helper_pt loghelper = handle;
+
+	pthread_mutex_lock(&loghelper->logListLock);
+	arrayList_removeElement(loghelper->logServices, service);
+	pthread_mutex_unlock(&loghelper->logListLock);
+
+	return CELIX_SUCCESS;
+}
+
+
+celix_status_t logHelper_stop(log_helper_pt loghelper) {
+	celix_status_t status = CELIX_SUCCESS;
+
+    status = serviceTracker_close(loghelper->logServiceTracker);
+
+    return status;
+}
+
+celix_status_t logHelper_destroy(log_helper_pt* loghelper) {
+        celix_status_t status = CELIX_SUCCESS;
+
+        serviceTracker_destroy((*loghelper)->logServiceTracker);
+
+        pthread_mutex_lock(&(*loghelper)->logListLock);
+        arrayList_destroy((*loghelper)->logServices);
+    	pthread_mutex_unlock(&(*loghelper)->logListLock);
+
+        pthread_mutex_destroy(&(*loghelper)->logListLock);
+
+        free(*loghelper);
+        *loghelper = NULL;
+        return status;
+}
+
+
+
+
+celix_status_t logHelper_log(log_helper_pt loghelper, log_level_t level, char* message, ... )
+{
+    celix_status_t status = CELIX_SUCCESS;
+	va_list listPointer;
+    char msg[1024];
+    msg[0] = '\0';
+    bool logged = false;
+
+	va_start(listPointer, message);
+	vsnprintf(msg, 1024, message, listPointer);
+
+	if (loghelper != NULL) {
+		pthread_mutex_lock(&loghelper->logListLock);
+
+		int i = 0;
+
+		for (; i < arrayList_size(loghelper->logServices); i++) {
+
+			log_service_pt logService = arrayList_get(loghelper->logServices, i);
+
+			if (logService != NULL) {
+				(logService->log)(logService->logger, level, msg);
+				logged = true;
+			}
+		}
+
+		pthread_mutex_unlock(&loghelper->logListLock);
+	}
+
+
+    if (!logged && loghelper->stdOutFallback) {
+        char *levelStr = NULL;
+
+        switch (level) {
+            case OSGI_LOGSERVICE_ERROR:
+                levelStr = "ERROR";
+                break;
+            case OSGI_LOGSERVICE_WARNING:
+                levelStr = "WARNING";
+                break;
+            case OSGI_LOGSERVICE_INFO:
+                levelStr = "INFO";
+                break;
+            case OSGI_LOGSERVICE_DEBUG:
+            default:
+                levelStr = "DEBUG";
+                break;
+        }
+
+        printf("%s: %s\n", levelStr, msg);
+    }
+
+
+	return status;
+}

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_common/public/src/pubsub_endpoint.c
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_common/public/src/pubsub_endpoint.c b/celix-pubsub/pubsub/pubsub_common/public/src/pubsub_endpoint.c
new file mode 100644
index 0000000..4af52ac
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_common/public/src/pubsub_endpoint.c
@@ -0,0 +1,156 @@
+/**
+ *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.
+ */
+/*
+ * endpoint_description.c
+ *
+ *  \date       25 Jul 2014
+ *  \author     <a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright  Apache License, Version 2.0
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "celix_errno.h"
+#include "celix_log.h"
+
+#include "pubsub_common.h"
+#include "pubsub_endpoint.h"
+#include "constants.h"
+#include "subscriber.h"
+
+celix_status_t pubsubEndpoint_create(const char* fwUUID, const char* scope, const char* topic, long serviceId, const char* endpoint, pubsub_endpoint_pt* psEp) {
+    celix_status_t status = CELIX_SUCCESS;
+    *psEp = calloc(1, sizeof(**psEp));
+
+    if (fwUUID != NULL) {
+        (*psEp)->frameworkUUID = strdup(fwUUID);
+    }
+
+    if (scope != NULL) {
+        (*psEp)->scope = strdup(scope);
+    }
+
+    if (topic != NULL) {
+        (*psEp)->topic = strdup(topic);
+    }
+
+    (*psEp)->serviceID = serviceId;
+
+    if (endpoint != NULL) {
+        (*psEp)->endpoint = strdup(endpoint);
+    }
+
+    return status;
+
+}
+
+celix_status_t pubsubEndpoint_createFromServiceReference(service_reference_pt reference, pubsub_endpoint_pt* psEp){
+	celix_status_t status = CELIX_SUCCESS;
+
+	*psEp = calloc(1,sizeof(**psEp));
+
+	bundle_pt bundle = NULL;
+	bundle_context_pt ctxt = NULL;
+	const char* fwUUID = NULL;
+	serviceReference_getBundle(reference,&bundle);
+	bundle_getContext(bundle,&ctxt);
+	bundleContext_getProperty(ctxt,OSGI_FRAMEWORK_FRAMEWORK_UUID,&fwUUID);
+
+	const char* scope = NULL;
+	serviceReference_getProperty(reference, PUBSUB_SUBSCRIBER_SCOPE,&scope);
+
+	const char* topic = NULL;
+	serviceReference_getProperty(reference, PUBSUB_SUBSCRIBER_TOPIC,&topic);
+
+	const char* serviceId = NULL;
+	serviceReference_getProperty(reference,(char*)OSGI_FRAMEWORK_SERVICE_ID,&serviceId);
+
+
+	if(fwUUID!=NULL){
+		(*psEp)->frameworkUUID=strdup(fwUUID);
+	}
+
+	if(scope!=NULL){
+		(*psEp)->scope=strdup(scope);
+	} else {
+	    (*psEp)->scope=strdup(PUBSUB_SUBSCRIBER_SCOPE_DEFAULT);
+	}
+
+	if(topic!=NULL){
+		(*psEp)->topic=strdup(topic);
+	}
+
+	if(serviceId!=NULL){
+		(*psEp)->serviceID = strtol(serviceId,NULL,10);
+	}
+
+	if (!(*psEp)->frameworkUUID || !(*psEp)->serviceID || !(*psEp)->scope || !(*psEp)->topic) {
+		fw_log(logger, OSGI_FRAMEWORK_LOG_ERROR, "PUBSUB_ENDPOINT: incomplete description!.");
+		status = CELIX_BUNDLE_EXCEPTION;
+	}
+
+	return status;
+
+}
+
+celix_status_t pubsubEndpoint_destroy(pubsub_endpoint_pt psEp){
+    if(psEp->frameworkUUID!=NULL){
+		free(psEp->frameworkUUID);
+		psEp->frameworkUUID = NULL;
+	}
+
+	if(psEp->scope!=NULL){
+		free(psEp->scope);
+		psEp->scope = NULL;
+	}
+
+	if(psEp->topic!=NULL){
+		free(psEp->topic);
+		psEp->topic = NULL;
+	}
+
+	if(psEp->endpoint!=NULL){
+		free(psEp->endpoint);
+		psEp->endpoint = NULL;
+	}
+
+	free(psEp);
+	return CELIX_SUCCESS;
+
+}
+
+bool pubsubEndpoint_equals(pubsub_endpoint_pt psEp1,pubsub_endpoint_pt psEp2){
+
+	return ((strcmp(psEp1->frameworkUUID,psEp2->frameworkUUID)==0) &&
+			(strcmp(psEp1->scope,psEp2->scope)==0) &&
+			(strcmp(psEp1->topic,psEp2->topic)==0) &&
+			(psEp1->serviceID == psEp2->serviceID) /*&&
+			((psEp1->endpoint==NULL && psEp2->endpoint==NULL)||(strcmp(psEp1->endpoint,psEp2->endpoint)==0))*/
+	);
+
+
+}
+
+char *createScopeTopicKey(const char* scope, const char* topic) {
+	char *result = NULL;
+	asprintf(&result, "%s:%s", scope, topic);
+
+	return result;
+}

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_common/public/src/pubsub_serializer.c
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_common/public/src/pubsub_serializer.c b/celix-pubsub/pubsub/pubsub_common/public/src/pubsub_serializer.c
new file mode 100644
index 0000000..85ef868
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_common/public/src/pubsub_serializer.c
@@ -0,0 +1,105 @@
+/**
+ *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.
+ */
+/*
+ * pubsub_serializer_json.c
+ *
+ *  \date       Dec 7, 2016
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#include "pubsub_serializer.h"
+
+#include "utils.h"
+#include "json_serializer.h"
+#include "dyn_msg_utils.h"
+#include "dyn_type.h"
+#include "string.h"
+#include "dyn_message.h"
+#include "dyn_common.h"
+
+struct _pubsub_message_type {	/* _dyn_message_type */
+	struct namvals_head header;
+	struct namvals_head annotations;
+	struct types_head types;
+	dyn_type *msgType;
+	version_pt msgVersion;
+};
+
+int pubsubSerializer_serialize(pubsub_message_type *msgType, const void *input, void **output, int *outputLen){
+
+	int rc = 0;
+
+	dyn_type *type = NULL;
+	dynMessage_getMessageType((dyn_message_type *) msgType, &type);
+
+	char *jsonOutput = NULL;
+	rc = jsonSerializer_serialize(type, (void *) input, &jsonOutput);
+
+	*output = (void *) jsonOutput;
+	*outputLen = strlen(jsonOutput) + 1;
+
+	return rc;
+}
+
+int pubsubSerializer_deserialize(pubsub_message_type *msgType, const void *input, void **output){
+
+	int rc = 0;
+
+	dyn_type *type = NULL;
+	dynMessage_getMessageType((dyn_message_type *) msgType, &type);
+
+	void *textOutput = NULL;
+	rc = jsonSerializer_deserialize(type, (const char *) input, &textOutput);
+
+	*output = textOutput;
+
+	return rc;
+}
+
+unsigned int pubsubSerializer_hashCode(const char *string){
+	return utils_stringHash(string);
+}
+
+version_pt pubsubSerializer_getVersion(pubsub_message_type *msgType){
+	version_pt msgVersion = NULL;
+	dynMessage_getVersion((dyn_message_type *) msgType, &msgVersion);
+	return msgVersion;
+}
+
+char* pubsubSerializer_getName(pubsub_message_type *msgType){
+	char *name = NULL;
+	dynMessage_getName((dyn_message_type *) msgType, &name);
+	return name;
+}
+
+void pubsubSerializer_fillMsgTypesMap(hash_map_pt msgTypesMap,bundle_pt bundle){
+	fillMsgTypesMap(msgTypesMap, bundle);
+}
+
+void pubsubSerializer_emptyMsgTypesMap(hash_map_pt msgTypesMap){
+	emptyMsgTypesMap(msgTypesMap);
+}
+
+void pubsubSerializer_freeMsg(pubsub_message_type *msgType, void *msg){
+	dyn_type *type = NULL;
+	dynMessage_getMessageType((dyn_message_type *) msgType, &type);
+	dynType_free(type, msg);
+}
+

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_common/public/src/pubsub_utils.c
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_common/public/src/pubsub_utils.c b/celix-pubsub/pubsub/pubsub_common/public/src/pubsub_utils.c
new file mode 100644
index 0000000..5f1b7ba
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_common/public/src/pubsub_utils.c
@@ -0,0 +1,163 @@
+/**
+ *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.
+ */
+/*
+ * pubsub_utils.c
+ *
+ *  \date       Sep 24, 2015
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "constants.h"
+
+#include "pubsub_common.h"
+#include "publisher.h"
+#include "pubsub_utils.h"
+
+#include "array_list.h"
+#include "bundle.h"
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#define MAX_KEYBUNDLE_LENGTH 256
+
+char* pubsub_getScopeFromFilter(char* bundle_filter){
+
+	char* scope = NULL;
+
+	char* filter = strdup(bundle_filter);
+
+	char* oc = strstr(filter,OSGI_FRAMEWORK_OBJECTCLASS);
+	if(oc!=NULL){
+		oc+=strlen(OSGI_FRAMEWORK_OBJECTCLASS)+1;
+		if(strncmp(oc,PUBSUB_PUBLISHER_SERVICE_NAME,strlen(PUBSUB_PUBLISHER_SERVICE_NAME))==0){
+
+			char* scopes = strstr(filter,PUBSUB_PUBLISHER_SCOPE);
+			if(scopes!=NULL){
+
+				scopes+=strlen(PUBSUB_PUBLISHER_SCOPE)+1;
+				char* bottom=strchr(scopes,')');
+				*bottom='\0';
+
+				scope=strdup(scopes);
+			} else {
+			    scope=strdup(PUBSUB_PUBLISHER_SCOPE_DEFAULT);
+			}
+		}
+	}
+
+	free(filter);
+
+	return scope;
+}
+
+char* pubsub_getTopicFromFilter(char* bundle_filter){
+
+	char* topic = NULL;
+
+	char* filter = strdup(bundle_filter);
+
+	char* oc = strstr(filter,OSGI_FRAMEWORK_OBJECTCLASS);
+	if(oc!=NULL){
+		oc+=strlen(OSGI_FRAMEWORK_OBJECTCLASS)+1;
+		if(strncmp(oc,PUBSUB_PUBLISHER_SERVICE_NAME,strlen(PUBSUB_PUBLISHER_SERVICE_NAME))==0){
+
+			char* topics = strstr(filter,PUBSUB_PUBLISHER_TOPIC);
+			if(topics!=NULL){
+
+				topics+=strlen(PUBSUB_PUBLISHER_TOPIC)+1;
+				char* bottom=strchr(topics,')');
+				*bottom='\0';
+
+				topic=strdup(topics);
+
+			}
+		}
+	}
+
+	free(filter);
+
+	return topic;
+
+}
+
+array_list_pt pubsub_getTopicsFromString(char* string){
+
+	array_list_pt topic_list = NULL;
+	arrayList_create(&topic_list);
+
+	char* topics = strdup(string);
+
+	char* topic = strtok(topics,",;|# ");
+	arrayList_add(topic_list,strdup(topic));
+
+	while( (topic = strtok(NULL,",;|# ")) !=NULL){
+		arrayList_add(topic_list,strdup(topic));
+	}
+
+	free(topics);
+
+	return topic_list;
+
+}
+
+/**
+ * Loop through all bundles and look for the bundle with the keys inside.
+ * If no key bundle found, return NULL
+ *
+ * Caller is responsible for freeing the object
+ */
+char* pubsub_getKeysBundleDir(bundle_context_pt ctx)
+{
+	array_list_pt bundles = NULL;
+	bundleContext_getBundles(ctx, &bundles);
+	int nrOfBundles = arrayList_size(bundles);
+
+	char* result = NULL;
+
+	for (int i = 0; i < nrOfBundles; i++){
+		bundle_pt b = arrayList_get(bundles, i);
+		char* dir = NULL;
+		bundle_getEntry(b, ".", &dir);
+
+		char cert_dir[MAX_KEYBUNDLE_LENGTH];
+		snprintf(cert_dir, MAX_KEYBUNDLE_LENGTH, "%s/META-INF/keys", dir);
+
+		struct stat s;
+		int err = stat(cert_dir, &s);
+		if (err != -1){
+			if (S_ISDIR(s.st_mode)){
+				result = dir;
+				break;
+			}
+		}
+
+		free(dir);
+	}
+
+	arrayList_destroy(bundles);
+
+	return result;
+}
+

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_discovery/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_discovery/CMakeLists.txt b/celix-pubsub/pubsub/pubsub_discovery/CMakeLists.txt
new file mode 100644
index 0000000..bf95368
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_discovery/CMakeLists.txt
@@ -0,0 +1,43 @@
+# 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.
+
+find_package(CURL REQUIRED)
+find_package(Jansson REQUIRED)
+
+include_directories("${CURL_INCLUDE_DIR}")
+include_directories("${JANSSON_INCLUDE_DIR}")
+include_directories("${PROJECT_SOURCE_DIR}/pubsub/pubsub_common/public/include")
+include_directories("${PROJECT_SOURCE_DIR}/pubsub/api/pubsub")
+include_directories("private/include")
+include_directories("public/include")
+
+add_bundle(org.apache.celix.pubsub_discovery.etcd.PubsubDiscovery
+    BUNDLE_SYMBOLICNAME "apache_celix_pubsub_discovery_etcd"
+    VERSION "1.0.0"
+    SOURCES
+		private/src/psd_activator.c
+		private/src/pubsub_discovery_impl.c
+		private/src/etcd_common.c
+		private/src/etcd_watcher.c
+		private/src/etcd_writer.c
+		${PROJECT_SOURCE_DIR}/pubsub/pubsub_common/public/src/pubsub_endpoint.c
+		${PROJECT_SOURCE_DIR}/pubsub/pubsub_common/public/src/etcd.c
+)
+
+install_bundle(org.apache.celix.pubsub_discovery.etcd.PubsubDiscovery)
+	
+target_link_libraries(org.apache.celix.pubsub_discovery.etcd.PubsubDiscovery ${CURL_LIBRARIES} ${JANSSON_LIBRARIES})

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_discovery/private/include/etcd_common.h
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_discovery/private/include/etcd_common.h b/celix-pubsub/pubsub/pubsub_discovery/private/include/etcd_common.h
new file mode 100644
index 0000000..7a3e7b6
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_discovery/private/include/etcd_common.h
@@ -0,0 +1,28 @@
+/**
+ *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.
+ */
+
+#ifndef ETCD_COMMON_H_
+#define ETCD_COMMON_H_
+
+#include "bundle_context.h"
+#include "celix_errno.h"
+
+celix_status_t etcdCommon_init(bundle_context_pt context);
+
+#endif /* ETCD_COMMON_H_ */

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_discovery/private/include/etcd_watcher.h
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_discovery/private/include/etcd_watcher.h b/celix-pubsub/pubsub/pubsub_discovery/private/include/etcd_watcher.h
new file mode 100644
index 0000000..c425e60
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_discovery/private/include/etcd_watcher.h
@@ -0,0 +1,38 @@
+/**
+ *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.
+ */
+
+#ifndef ETCD_WATCHER_H_
+#define ETCD_WATCHER_H_
+
+#include "bundle_context.h"
+#include "celix_errno.h"
+
+#include "pubsub_discovery.h"
+#include "pubsub_endpoint.h"
+
+typedef struct etcd_watcher *etcd_watcher_pt;
+
+celix_status_t etcdWatcher_create(pubsub_discovery_pt discovery,  bundle_context_pt context, const char *scope, const char* topic, etcd_watcher_pt *watcher);
+celix_status_t etcdWatcher_destroy(etcd_watcher_pt watcher);
+celix_status_t etcdWatcher_stop(etcd_watcher_pt watcher);
+
+celix_status_t etcdWatcher_getPublisherEndpointFromKey(pubsub_discovery_pt discovery, const char* key, const char* value, pubsub_endpoint_pt* pubEP);
+
+
+#endif /* ETCD_WATCHER_H_ */

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_discovery/private/include/etcd_writer.h
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_discovery/private/include/etcd_writer.h b/celix-pubsub/pubsub/pubsub_discovery/private/include/etcd_writer.h
new file mode 100644
index 0000000..3ff98b9
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_discovery/private/include/etcd_writer.h
@@ -0,0 +1,39 @@
+/**
+ *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.
+ */
+
+#ifndef ETCD_WRITER_H_
+#define ETCD_WRITER_H_
+
+#include "bundle_context.h"
+#include "celix_errno.h"
+
+#include "pubsub_discovery.h"
+#include "pubsub_endpoint.h"
+
+typedef struct etcd_writer *etcd_writer_pt;
+
+
+etcd_writer_pt etcdWriter_create(pubsub_discovery_pt discovery);
+void etcdWriter_destroy(etcd_writer_pt writer);
+
+celix_status_t etcdWriter_addPublisherEndpoint(etcd_writer_pt writer, pubsub_endpoint_pt pubEP,bool storeEP);
+celix_status_t etcdWriter_deletePublisherEndpoint(etcd_writer_pt writer, pubsub_endpoint_pt pubEP);
+
+
+#endif /* ETCD_WRITER_H_ */

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_discovery/private/include/pubsub_discovery_impl.h
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_discovery/private/include/pubsub_discovery_impl.h b/celix-pubsub/pubsub/pubsub_discovery/private/include/pubsub_discovery_impl.h
new file mode 100644
index 0000000..d5be8d6
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_discovery/private/include/pubsub_discovery_impl.h
@@ -0,0 +1,73 @@
+/**
+ *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.
+ */
+
+#ifndef PUBSUB_DISCOVERY_IMPL_H_
+#define PUBSUB_DISCOVERY_IMPL_H_
+
+#include "bundle_context.h"
+#include "service_reference.h"
+
+#include "etcd_watcher.h"
+#include "etcd_writer.h"
+#include "pubsub_endpoint.h"
+
+#define FREE_MEM(ptr) if(ptr) {free(ptr); ptr = NULL;}
+
+struct watcher_info {
+    etcd_watcher_pt watcher;
+    int nr_references;
+};
+
+struct pubsub_discovery {
+	bundle_context_pt context;
+
+	celix_thread_mutex_t discoveredPubsMutex;
+	hash_map_pt discoveredPubs; //<topic,List<pubsub_endpoint_pt>>
+
+	celix_thread_mutex_t listenerReferencesMutex;
+	hash_map_pt listenerReferences; //key=serviceReference, value=nop
+
+	celix_thread_mutex_t watchersMutex;
+	hash_map_pt watchers; //key = topicname, value = struct watcher_info
+
+	etcd_writer_pt writer;
+};
+
+
+celix_status_t pubsub_discovery_create(bundle_context_pt context, pubsub_discovery_pt* node_discovery);
+celix_status_t pubsub_discovery_destroy(pubsub_discovery_pt node_discovery);
+celix_status_t pubsub_discovery_start(pubsub_discovery_pt node_discovery);
+celix_status_t pubsub_discovery_stop(pubsub_discovery_pt node_discovery);
+
+celix_status_t pubsub_discovery_addNode(pubsub_discovery_pt node_discovery, pubsub_endpoint_pt pubEP);
+celix_status_t pubsub_discovery_removeNode(pubsub_discovery_pt node_discovery, pubsub_endpoint_pt pubEP);
+
+celix_status_t pubsub_discovery_tmPublisherAnnounceAdding(void * handle, service_reference_pt reference, void **service);
+celix_status_t pubsub_discovery_tmPublisherAnnounceAdded(void * handle, service_reference_pt reference, void * service);
+celix_status_t pubsub_discovery_tmPublisherAnnounceModified(void * handle, service_reference_pt reference, void * service);
+celix_status_t pubsub_discovery_tmPublisherAnnounceRemoved(void * handle, service_reference_pt reference, void * service);
+
+celix_status_t pubsub_discovery_announcePublisher(void *handle, pubsub_endpoint_pt pubEP);
+celix_status_t pubsub_discovery_removePublisher(void *handle, pubsub_endpoint_pt pubEP);
+celix_status_t pubsub_discovery_interestedInTopic(void *handle, const char* scope, const char* topic);
+celix_status_t pubsub_discovery_uninterestedInTopic(void *handle, const char* scope, const char* topic);
+
+celix_status_t pubsub_discovery_informPublishersListeners(pubsub_discovery_pt discovery, pubsub_endpoint_pt endpoint, bool endpointAdded);
+
+#endif /* PUBSUB_DISCOVERY_IMPL_H_ */

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_discovery/private/src/etcd_common.c
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_discovery/private/src/etcd_common.c b/celix-pubsub/pubsub/pubsub_discovery/private/src/etcd_common.c
new file mode 100644
index 0000000..16102b0
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_discovery/private/src/etcd_common.c
@@ -0,0 +1,81 @@
+/**
+ *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 <stdbool.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "celix_log.h"
+#include "constants.h"
+
+#include "etcd.h"
+#include "etcd_watcher.h"
+
+#include "pubsub_discovery.h"
+#include "pubsub_discovery_impl.h"
+
+
+#define MAX_ROOTNODE_LENGTH		128
+#define MAX_LOCALNODE_LENGTH 	4096
+#define MAX_FIELD_LENGTH		128
+
+#define CFG_ETCD_SERVER_IP		"PUBSUB_DISCOVERY_ETCD_SERVER_IP"
+#define DEFAULT_ETCD_SERVER_IP	"127.0.0.1"
+
+#define CFG_ETCD_SERVER_PORT	"PUBSUB_DISCOVERY_ETCD_SERVER_PORT"
+#define DEFAULT_ETCD_SERVER_PORT 2379
+
+// be careful - this should be higher than the curl timeout
+#define CFG_ETCD_TTL   "DISCOVERY_ETCD_TTL"
+#define DEFAULT_ETCD_TTL 30
+
+
+celix_status_t etcdCommon_init(bundle_context_pt context) {
+    celix_status_t status = CELIX_SUCCESS;
+    const char* etcd_server = NULL;
+    const char* etcd_port_string = NULL;
+    int etcd_port = 0;
+
+    if ((bundleContext_getProperty(context, CFG_ETCD_SERVER_IP, &etcd_server) != CELIX_SUCCESS) || !etcd_server) {
+        etcd_server = DEFAULT_ETCD_SERVER_IP;
+    }
+
+    if ((bundleContext_getProperty(context, CFG_ETCD_SERVER_PORT, &etcd_port_string) != CELIX_SUCCESS) || !etcd_port_string) {
+        etcd_port = DEFAULT_ETCD_SERVER_PORT;
+    } else {
+        char* endptr = NULL;
+        errno = 0;
+        etcd_port = strtol(etcd_port_string, &endptr, 10);
+        if (*endptr || errno != 0) {
+            etcd_port = DEFAULT_ETCD_SERVER_PORT;
+        }
+    }
+
+    printf("PSD: Using discovery HOST:PORT: %s:%i\n", etcd_server, etcd_port);
+
+    if (etcd_init(etcd_server, etcd_port) != 0) {
+        status = CELIX_BUNDLE_EXCEPTION;
+    } else {
+        status = CELIX_SUCCESS;
+    }
+
+    return status;
+}
+

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_discovery/private/src/etcd_watcher.c
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_discovery/private/src/etcd_watcher.c b/celix-pubsub/pubsub/pubsub_discovery/private/src/etcd_watcher.c
new file mode 100644
index 0000000..a394045
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_discovery/private/src/etcd_watcher.c
@@ -0,0 +1,292 @@
+/**
+ *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 <stdbool.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "celix_log.h"
+#include "constants.h"
+
+#include "etcd.h"
+#include "etcd_watcher.h"
+
+#include "pubsub_discovery.h"
+#include "pubsub_discovery_impl.h"
+
+
+
+#define MAX_ROOTNODE_LENGTH             128
+#define MAX_LOCALNODE_LENGTH            4096
+#define MAX_FIELD_LENGTH                128
+
+#define CFG_ETCD_ROOT_PATH              "PUBSUB_DISCOVERY_ETCD_ROOT_PATH"
+#define DEFAULT_ETCD_ROOTPATH           "pubsub/discovery"
+
+#define CFG_ETCD_SERVER_IP              "PUBSUB_DISCOVERY_ETCD_SERVER_IP"
+#define DEFAULT_ETCD_SERVER_IP          "127.0.0.1"
+
+#define CFG_ETCD_SERVER_PORT            "PUBSUB_DISCOVERY_ETCD_SERVER_PORT"
+#define DEFAULT_ETCD_SERVER_PORT        2379
+
+// be careful - this should be higher than the curl timeout
+#define CFG_ETCD_TTL                    "DISCOVERY_ETCD_TTL"
+#define DEFAULT_ETCD_TTL                30
+
+
+struct etcd_watcher {
+	pubsub_discovery_pt pubsub_discovery;
+
+	celix_thread_mutex_t watcherLock;
+	celix_thread_t watcherThread;
+
+    char *scope;
+	char *topic;
+	volatile bool running;
+};
+
+struct etcd_writer {
+    pubsub_discovery_pt pubsub_discovery;
+    celix_thread_mutex_t localPubsLock;
+    array_list_pt localPubs;
+    volatile bool running;
+    celix_thread_t writerThread;
+};
+
+
+// note that the rootNode shouldn't have a leading slash
+static celix_status_t etcdWatcher_getTopicRootPath(bundle_context_pt context, const char *scope, const char *topic, char* rootNode, int rootNodeLen) {
+	celix_status_t status = CELIX_SUCCESS;
+	const char* rootPath = NULL;
+
+	if (((bundleContext_getProperty(context, CFG_ETCD_ROOT_PATH, &rootPath)) != CELIX_SUCCESS) || (!rootPath)) {
+	    snprintf(rootNode, rootNodeLen, "%s/%s/%s", DEFAULT_ETCD_ROOTPATH, scope, topic);
+	} else {
+        snprintf(rootNode, rootNodeLen, "%s/%s/%s", rootPath, scope, topic);
+	}
+
+	return status;
+}
+
+static celix_status_t etcdWatcher_getRootPath(bundle_context_pt context, char* rootNode) {
+    celix_status_t status = CELIX_SUCCESS;
+    const char* rootPath = NULL;
+
+    if (((bundleContext_getProperty(context, CFG_ETCD_ROOT_PATH, &rootPath)) != CELIX_SUCCESS) || (!rootPath)) {
+        strncpy(rootNode, DEFAULT_ETCD_ROOTPATH, MAX_ROOTNODE_LENGTH);
+    } else {
+        strncpy(rootNode, rootPath, MAX_ROOTNODE_LENGTH);
+    }
+
+    return status;
+}
+
+
+static void add_node(const char *key, const char *value, void* arg) {
+    pubsub_discovery_pt ps_discovery = (pubsub_discovery_pt) arg;
+    pubsub_endpoint_pt pubEP = NULL;
+    celix_status_t status = etcdWatcher_getPublisherEndpointFromKey(ps_discovery, key, value, &pubEP);
+    if(!status && pubEP) {
+        pubsub_discovery_addNode(ps_discovery, pubEP);
+    }
+}
+
+static celix_status_t etcdWatcher_addAlreadyExistingPublishers(pubsub_discovery_pt ps_discovery, const char *rootPath, long long * highestModified) {
+	celix_status_t status = CELIX_SUCCESS;
+	if(etcd_get_directory(rootPath, add_node, ps_discovery, highestModified)) {
+	    status = CELIX_ILLEGAL_ARGUMENT;
+	}
+	return status;
+}
+
+// gets everything from provided key
+celix_status_t etcdWatcher_getPublisherEndpointFromKey(pubsub_discovery_pt pubsub_discovery, const char* etcdKey, const char* etcdValue, pubsub_endpoint_pt* pubEP) {
+
+	celix_status_t status = CELIX_SUCCESS;
+
+	char rootPath[MAX_ROOTNODE_LENGTH];
+	char *expr = NULL;
+	char scope[MAX_FIELD_LENGTH];
+	char topic[MAX_FIELD_LENGTH];
+	char fwUUID[MAX_FIELD_LENGTH];
+	char serviceId[MAX_FIELD_LENGTH];
+
+	memset(rootPath,0,MAX_ROOTNODE_LENGTH);
+	memset(topic,0,MAX_FIELD_LENGTH);
+	memset(fwUUID,0,MAX_FIELD_LENGTH);
+	memset(serviceId,0,MAX_FIELD_LENGTH);
+
+	etcdWatcher_getRootPath(pubsub_discovery->context, rootPath);
+
+	asprintf(&expr, "/%s/%%[^/]/%%[^/]/%%[^/]/%%[^/].*", rootPath);
+	if(expr) {
+            int foundItems = sscanf(etcdKey, expr, scope, topic, fwUUID, serviceId);
+            free(expr);
+            if (foundItems != 4) { // Could happen when a directory is removed, just don't process this.
+                    status = CELIX_ILLEGAL_STATE;
+            }
+            else{
+                    status = pubsubEndpoint_create(fwUUID,scope,topic,strtol(serviceId,NULL,10),etcdValue,pubEP);
+            }
+	}
+	return status;
+}
+
+/*
+ * performs (blocking) etcd_watch calls to check for
+ * changing discovery endpoint information within etcd.
+ */
+static void* etcdWatcher_run(void* data) {
+    etcd_watcher_pt watcher = (etcd_watcher_pt) data;
+    time_t timeBeforeWatch = time(NULL);
+    char rootPath[MAX_ROOTNODE_LENGTH];
+    long long highestModified = 0;
+
+    pubsub_discovery_pt ps_discovery = watcher->pubsub_discovery;
+    bundle_context_pt context = ps_discovery->context;
+
+    memset(rootPath, 0, MAX_ROOTNODE_LENGTH);
+
+    //TODO: add topic to etcd key
+    etcdWatcher_getTopicRootPath(context, watcher->scope, watcher->topic, rootPath, MAX_ROOTNODE_LENGTH);
+    etcdWatcher_addAlreadyExistingPublishers(ps_discovery, rootPath, &highestModified);
+
+    while ((celixThreadMutex_lock(&watcher->watcherLock) == CELIX_SUCCESS) && watcher->running) {
+
+        char *rkey = NULL;
+        char *value = NULL;
+        char *preValue = NULL;
+        char *action = NULL;
+        long long modIndex;
+
+        celixThreadMutex_unlock(&watcher->watcherLock);
+
+        if (etcd_watch(rootPath, highestModified + 1, &action, &preValue, &value, &rkey, &modIndex) == 0 && action != NULL) {
+            pubsub_endpoint_pt pubEP = NULL;
+            if ((strcmp(action, "set") == 0) || (strcmp(action, "create") == 0)) {
+                if (etcdWatcher_getPublisherEndpointFromKey(ps_discovery, rkey, value, &pubEP) == CELIX_SUCCESS) {
+                    pubsub_discovery_addNode(ps_discovery, pubEP);
+                }
+            } else if (strcmp(action, "delete") == 0) {
+                if (etcdWatcher_getPublisherEndpointFromKey(ps_discovery, rkey, preValue, &pubEP) == CELIX_SUCCESS) {
+                    pubsub_discovery_removeNode(ps_discovery, pubEP);
+                }
+            } else if (strcmp(action, "expire") == 0) {
+                if (etcdWatcher_getPublisherEndpointFromKey(ps_discovery, rkey, preValue, &pubEP) == CELIX_SUCCESS) {
+                    pubsub_discovery_removeNode(ps_discovery, pubEP);
+                }
+            } else if (strcmp(action, "update") == 0) {
+                if (etcdWatcher_getPublisherEndpointFromKey(ps_discovery, rkey, value, &pubEP) == CELIX_SUCCESS) {
+                    pubsub_discovery_addNode(ps_discovery, pubEP);
+                }
+            } else {
+                fw_log(logger, OSGI_FRAMEWORK_LOG_INFO, "Unexpected action: %s", action);
+            }
+            highestModified = modIndex;
+        } else if (time(NULL) - timeBeforeWatch <= (DEFAULT_ETCD_TTL / 4)) {
+            sleep(DEFAULT_ETCD_TTL / 4);
+        }
+
+        FREE_MEM(action);
+        FREE_MEM(value);
+        FREE_MEM(preValue);
+        FREE_MEM(rkey);
+
+        /* prevent busy waiting, in case etcd_watch returns false */
+
+
+        if (time(NULL) - timeBeforeWatch > (DEFAULT_ETCD_TTL / 4)) {
+            timeBeforeWatch = time(NULL);
+        }
+
+    }
+
+    if (watcher->running == false) {
+        celixThreadMutex_unlock(&watcher->watcherLock);
+    }
+
+    return NULL;
+}
+
+celix_status_t etcdWatcher_create(pubsub_discovery_pt pubsub_discovery, bundle_context_pt context, const char *scope, const char *topic, etcd_watcher_pt *watcher) {
+	celix_status_t status = CELIX_SUCCESS;
+
+
+	if (pubsub_discovery == NULL) {
+		return CELIX_BUNDLE_EXCEPTION;
+	}
+
+	(*watcher) = calloc(1, sizeof(struct etcd_watcher));
+
+	if(*watcher == NULL){
+		return CELIX_ENOMEM;
+	}
+
+	(*watcher)->pubsub_discovery = pubsub_discovery;
+	(*watcher)->scope = strdup(scope);
+	(*watcher)->topic = strdup(topic);
+
+
+    celixThreadMutex_create(&(*watcher)->watcherLock, NULL);
+
+    celixThreadMutex_lock(&(*watcher)->watcherLock);
+
+    if ((status = celixThread_create(&(*watcher)->watcherThread, NULL, etcdWatcher_run, *watcher)) != CELIX_SUCCESS) {
+        return status;
+    }
+    (*watcher)->running = true;
+
+    celixThreadMutex_unlock(&(*watcher)->watcherLock);
+
+
+	return status;
+}
+
+celix_status_t etcdWatcher_destroy(etcd_watcher_pt watcher) {
+
+	celix_status_t status = CELIX_SUCCESS;
+
+	char rootPath[MAX_ROOTNODE_LENGTH];
+	etcdWatcher_getTopicRootPath(watcher->pubsub_discovery->context, watcher->scope, watcher->topic, rootPath, MAX_ROOTNODE_LENGTH);
+	celixThreadMutex_destroy(&(watcher->watcherLock));
+
+	free(watcher->scope);
+	free(watcher->topic);
+	free(watcher);
+
+	return status;
+}
+
+celix_status_t etcdWatcher_stop(etcd_watcher_pt watcher){
+	celix_status_t status = CELIX_SUCCESS;
+
+	celixThreadMutex_lock(&(watcher->watcherLock));
+	watcher->running = false;
+	celixThreadMutex_unlock(&(watcher->watcherLock));
+
+	watcher->running = false;
+
+	celixThread_join(watcher->watcherThread, NULL);
+
+	return status;
+
+}
+
+

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_discovery/private/src/etcd_writer.c
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_discovery/private/src/etcd_writer.c b/celix-pubsub/pubsub/pubsub_discovery/private/src/etcd_writer.c
new file mode 100644
index 0000000..687d802
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_discovery/private/src/etcd_writer.c
@@ -0,0 +1,189 @@
+/**
+ *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 <stdbool.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "celix_log.h"
+#include "constants.h"
+
+#include "etcd.h"
+#include "etcd_writer.h"
+
+#include "pubsub_discovery.h"
+#include "pubsub_discovery_impl.h"
+
+#define MAX_ROOTNODE_LENGTH		128
+
+#define CFG_ETCD_ROOT_PATH		"PUBSUB_DISCOVERY_ETCD_ROOT_PATH"
+#define DEFAULT_ETCD_ROOTPATH	"pubsub/discovery"
+
+#define CFG_ETCD_SERVER_IP		"PUBSUB_DISCOVERY_ETCD_SERVER_IP"
+#define DEFAULT_ETCD_SERVER_IP	"127.0.0.1"
+
+#define CFG_ETCD_SERVER_PORT	"PUBSUB_DISCOVERY_ETCD_SERVER_PORT"
+#define DEFAULT_ETCD_SERVER_PORT 2379
+
+// be careful - this should be higher than the curl timeout
+#define CFG_ETCD_TTL   "DISCOVERY_ETCD_TTL"
+#define DEFAULT_ETCD_TTL 30
+
+struct etcd_writer {
+    pubsub_discovery_pt pubsub_discovery;
+    celix_thread_mutex_t localPubsLock;
+    array_list_pt localPubs;
+    volatile bool running;
+    celix_thread_t writerThread;
+};
+
+
+static const char* etcdWriter_getRootPath(bundle_context_pt context);
+static void* etcdWriter_run(void* data);
+
+
+etcd_writer_pt etcdWriter_create(pubsub_discovery_pt disc) {
+    etcd_writer_pt writer = calloc(1, sizeof(*writer));
+    if(writer) {
+        celixThreadMutex_create(&writer->localPubsLock, NULL);
+        arrayList_create(&writer->localPubs);
+        writer->pubsub_discovery = disc;
+        writer->running = true;
+        celixThread_create(&writer->writerThread, NULL, etcdWriter_run, writer);
+    }
+    return writer;
+}
+
+void etcdWriter_destroy(etcd_writer_pt writer) {
+    char dir[MAX_ROOTNODE_LENGTH];
+    const char *rootPath = etcdWriter_getRootPath(writer->pubsub_discovery->context);
+
+    writer->running = false;
+    celixThread_join(writer->writerThread, NULL);
+
+    celixThreadMutex_lock(&writer->localPubsLock);
+    for(int i = 0; i < arrayList_size(writer->localPubs); i++) {
+        pubsub_endpoint_pt pubEP = (pubsub_endpoint_pt)arrayList_get(writer->localPubs,i);
+        memset(dir,0,MAX_ROOTNODE_LENGTH);
+        snprintf(dir,MAX_ROOTNODE_LENGTH,"%s/%s/%s/%s",rootPath,pubEP->scope,pubEP->topic,pubEP->frameworkUUID);
+        etcd_del(dir);
+        pubsubEndpoint_destroy(pubEP);
+    }
+    arrayList_destroy(writer->localPubs);
+
+    celixThreadMutex_unlock(&writer->localPubsLock);
+    celixThreadMutex_destroy(&(writer->localPubsLock));
+
+    free(writer);
+}
+
+celix_status_t etcdWriter_addPublisherEndpoint(etcd_writer_pt writer, pubsub_endpoint_pt pubEP, bool storeEP){
+	celix_status_t status = CELIX_BUNDLE_EXCEPTION;
+
+	if(storeEP){
+		const char *fwUUID = NULL;
+		bundleContext_getProperty(writer->pubsub_discovery->context, OSGI_FRAMEWORK_FRAMEWORK_UUID, &fwUUID);
+		if(fwUUID && strcmp(pubEP->frameworkUUID, fwUUID) == 0) {
+	            celixThreadMutex_lock(&writer->localPubsLock);
+		    pubsub_endpoint_pt p = NULL;
+		    pubsubEndpoint_create(pubEP->frameworkUUID,pubEP->scope,pubEP->topic,pubEP->serviceID,pubEP->endpoint,&p);
+		    arrayList_add(writer->localPubs,p);
+	            celixThreadMutex_unlock(&writer->localPubsLock);
+		}
+	}
+
+	char *key;
+
+	const char* ttlStr = NULL;
+	int ttl = 0;
+
+	// determine ttl
+	if ((bundleContext_getProperty(writer->pubsub_discovery->context, CFG_ETCD_TTL, &ttlStr) != CELIX_SUCCESS) || !ttlStr) {
+		ttl = DEFAULT_ETCD_TTL;
+	} else {
+		char* endptr = NULL;
+		errno = 0;
+		ttl = strtol(ttlStr, &endptr, 10);
+		if (*endptr || errno != 0) {
+			ttl = DEFAULT_ETCD_TTL;
+		}
+	}
+
+	const char *rootPath = etcdWriter_getRootPath(writer->pubsub_discovery->context);
+
+	asprintf(&key,"%s/%s/%s/%s/%ld",rootPath,pubEP->scope,pubEP->topic,pubEP->frameworkUUID,pubEP->serviceID);
+
+	if(!etcd_set(key,pubEP->endpoint,ttl,false)){
+		status = CELIX_ILLEGAL_ARGUMENT;
+	}
+	FREE_MEM(key);
+	return status;
+}
+
+celix_status_t etcdWriter_deletePublisherEndpoint(etcd_writer_pt writer, pubsub_endpoint_pt pubEP) {
+    celix_status_t status = CELIX_SUCCESS;
+    char *key = NULL;
+
+    const char *rootPath = etcdWriter_getRootPath(writer->pubsub_discovery->context);
+
+    asprintf(&key, "%s/%s/%s/%s/%ld", rootPath, pubEP->scope, pubEP->topic, pubEP->frameworkUUID, pubEP->serviceID);
+
+    celixThreadMutex_lock(&writer->localPubsLock);
+    for (unsigned int i = 0; i < arrayList_size(writer->localPubs); i++) {
+        pubsub_endpoint_pt ep = arrayList_get(writer->localPubs, i);
+        if (pubsubEndpoint_equals(ep, pubEP)) {
+            arrayList_remove(writer->localPubs, i);
+            pubsubEndpoint_destroy(ep);
+            break;
+        }
+    }
+    celixThreadMutex_unlock(&writer->localPubsLock);
+
+    if (etcd_del(key)) {
+        printf("Failed to remove key %s from ETCD\n",key);
+        status = CELIX_ILLEGAL_ARGUMENT;
+    }
+    FREE_MEM(key);
+    return status;
+}
+
+static void* etcdWriter_run(void* data) {
+    etcd_writer_pt writer = (etcd_writer_pt)data;
+    while(writer->running) {
+          celixThreadMutex_lock(&writer->localPubsLock);
+          for(int i=0; i < arrayList_size(writer->localPubs); i++) {
+              etcdWriter_addPublisherEndpoint(writer,(pubsub_endpoint_pt)arrayList_get(writer->localPubs,i),false);
+          }
+          celixThreadMutex_unlock(&writer->localPubsLock);
+          sleep(DEFAULT_ETCD_TTL / 2);
+    }
+
+    return NULL;
+}
+
+static const char* etcdWriter_getRootPath(bundle_context_pt context) {
+    const char* rootPath = NULL;
+    bundleContext_getProperty(context, CFG_ETCD_ROOT_PATH, &rootPath);
+    if(rootPath == NULL) {
+        rootPath = DEFAULT_ETCD_ROOTPATH;
+    }
+    return rootPath;
+}
+

http://git-wip-us.apache.org/repos/asf/celix/blob/f9a5fb11/celix-pubsub/pubsub/pubsub_discovery/private/src/psd_activator.c
----------------------------------------------------------------------
diff --git a/celix-pubsub/pubsub/pubsub_discovery/private/src/psd_activator.c b/celix-pubsub/pubsub/pubsub_discovery/private/src/psd_activator.c
new file mode 100644
index 0000000..afbe282
--- /dev/null
+++ b/celix-pubsub/pubsub/pubsub_discovery/private/src/psd_activator.c
@@ -0,0 +1,171 @@
+/**
+ *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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bundle_activator.h"
+#include "service_tracker.h"
+#include "service_registration.h"
+#include "constants.h"
+#include "celix_log.h"
+
+#include "pubsub_common.h"
+#include "publisher_endpoint_announce.h"
+#include "pubsub_discovery.h"
+#include "pubsub_discovery_impl.h"
+
+struct activator {
+	bundle_context_pt context;
+	pubsub_discovery_pt pubsub_discovery;
+
+	service_tracker_pt pstmPublishersTracker;
+
+	publisher_endpoint_announce_pt publisherEPAnnounce;
+	service_registration_pt publisherEPAnnounceService;
+};
+
+static celix_status_t createTMPublisherAnnounceTracker(struct activator *activator, service_tracker_pt *tracker) {
+	celix_status_t status = CELIX_SUCCESS;
+
+	service_tracker_customizer_pt customizer = NULL;
+
+	status = serviceTrackerCustomizer_create(activator->pubsub_discovery,
+			pubsub_discovery_tmPublisherAnnounceAdding,
+			pubsub_discovery_tmPublisherAnnounceAdded,
+			pubsub_discovery_tmPublisherAnnounceModified,
+			pubsub_discovery_tmPublisherAnnounceRemoved,
+			&customizer);
+
+	if (status == CELIX_SUCCESS) {
+		status = serviceTracker_create(activator->context, (char *) PUBSUB_TM_ANNOUNCE_PUBLISHER_SERVICE, customizer, tracker);
+	}
+
+	return status;
+}
+
+celix_status_t bundleActivator_create(bundle_context_pt context, void **userData) {
+	celix_status_t status = CELIX_SUCCESS;
+
+	struct activator* activator = calloc(1, sizeof(*activator));
+
+	if (activator) {
+		activator->context = context;
+		activator->pstmPublishersTracker = NULL;
+		activator->publisherEPAnnounce = NULL;
+		activator->publisherEPAnnounceService = NULL;
+
+		status = pubsub_discovery_create(context, &activator->pubsub_discovery);
+
+		if (status == CELIX_SUCCESS) {
+			status = createTMPublisherAnnounceTracker(activator, &(activator->pstmPublishersTracker));
+		}
+
+		if (status == CELIX_SUCCESS) {
+			*userData = activator;
+		} else {
+			free(activator);
+		}
+	} else {
+		status = CELIX_ENOMEM;
+	}
+
+	return status;
+
+}
+
+celix_status_t bundleActivator_start(void * userData, bundle_context_pt context) {
+	celix_status_t status = CELIX_SUCCESS;
+
+	struct activator *activator = userData;
+
+	publisher_endpoint_announce_pt pubEPAnnouncer = calloc(1, sizeof(*pubEPAnnouncer));
+
+	if (pubEPAnnouncer) {
+
+		pubEPAnnouncer->handle = activator->pubsub_discovery;
+		pubEPAnnouncer->announcePublisher = pubsub_discovery_announcePublisher;
+		pubEPAnnouncer->removePublisher = pubsub_discovery_removePublisher;
+		pubEPAnnouncer->interestedInTopic = pubsub_discovery_interestedInTopic;
+		pubEPAnnouncer->uninterestedInTopic = pubsub_discovery_uninterestedInTopic;
+		activator->publisherEPAnnounce = pubEPAnnouncer;
+
+		properties_pt props = properties_create();
+		properties_set(props, "PUBSUB_DISCOVERY", "true");
+
+		// pubsub_discovery_start needs to be first to initalize the propert etcd_watcher values
+		status = pubsub_discovery_start(activator->pubsub_discovery);
+
+		if (status == CELIX_SUCCESS) {
+			status = serviceTracker_open(activator->pstmPublishersTracker);
+		}
+
+		if (status == CELIX_SUCCESS) {
+			status = bundleContext_registerService(context, (char *) PUBSUB_DISCOVERY_SERVICE, pubEPAnnouncer, props, &activator->publisherEPAnnounceService);
+		}
+
+
+	}
+	else{
+		status = CELIX_ENOMEM;
+	}
+
+	if(status!=CELIX_SUCCESS && pubEPAnnouncer!=NULL){
+		free(pubEPAnnouncer);
+	}
+
+
+	return status;
+}
+
+celix_status_t bundleActivator_stop(void * userData, bundle_context_pt context) {
+	celix_status_t status = CELIX_SUCCESS;
+	struct activator *activator = userData;
+
+	status += pubsub_discovery_stop(activator->pubsub_discovery);
+
+	status += serviceTracker_close(activator->pstmPublishersTracker);
+
+	status += serviceRegistration_unregister(activator->publisherEPAnnounceService);
+
+	if (status == CELIX_SUCCESS) {
+		free(activator->publisherEPAnnounce);
+	}
+
+	return status;
+}
+
+celix_status_t bundleActivator_destroy(void * userData, bundle_context_pt context) {
+	celix_status_t status = CELIX_SUCCESS;
+	struct activator *activator = userData;
+
+	status += serviceTracker_destroy(activator->pstmPublishersTracker);
+	status += pubsub_discovery_destroy(activator->pubsub_discovery);
+
+	activator->publisherEPAnnounce = NULL;
+	activator->publisherEPAnnounceService = NULL;
+	activator->pstmPublishersTracker = NULL;
+	activator->pubsub_discovery = NULL;
+	activator->context = NULL;
+
+	free(activator);
+
+	return status;
+}