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 2018/05/27 18:52:40 UTC
[32/60] [abbrv] [partial] celix git commit: CELIX-424: Cleans up the
directory structure. Moves all libraries to the libs subdir and all bundles
to the bundles subdir
http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/remote_services/discovery_common/src/endpoint_discovery_server.c
----------------------------------------------------------------------
diff --git a/bundles/remote_services/discovery_common/src/endpoint_discovery_server.c b/bundles/remote_services/discovery_common/src/endpoint_discovery_server.c
new file mode 100644
index 0000000..7620bbf
--- /dev/null
+++ b/bundles/remote_services/discovery_common/src/endpoint_discovery_server.c
@@ -0,0 +1,454 @@
+/**
+ * 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_discovery_server.c
+ *
+ * \date Aug 12, 2014
+ * \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 <arpa/inet.h>
+#include <netdb.h>
+#ifndef ANDROID
+#include <ifaddrs.h>
+#endif
+#include "civetweb.h"
+#include "celix_errno.h"
+#include "utils.h"
+#include "log_helper.h"
+#include "discovery.h"
+#include "endpoint_descriptor_writer.h"
+
+// defines how often the webserver is restarted (with an increased port number)
+#define MAX_NUMBER_OF_RESTARTS 15
+#define DEFAULT_SERVER_THREADS "1"
+
+#define CIVETWEB_REQUEST_NOT_HANDLED 0
+#define CIVETWEB_REQUEST_HANDLED 1
+
+static const char *response_headers =
+ "HTTP/1.1 200 OK\r\n"
+ "Cache: no-cache\r\n"
+ "Content-Type: application/xml;charset=utf-8\r\n"
+ "\r\n";
+
+struct endpoint_discovery_server {
+ log_helper_pt* loghelper;
+ hash_map_pt entries; // key = endpointId, value = endpoint_descriptor_pt
+
+ celix_thread_mutex_t serverLock;
+
+ const char* path;
+ const char *port;
+ const char* ip;
+ struct mg_context* ctx;
+};
+
+// Forward declarations...
+static int endpointDiscoveryServer_callback(struct mg_connection *conn);
+static char* format_path(const char* path);
+
+#ifndef ANDROID
+static celix_status_t endpointDiscoveryServer_getIpAdress(char* interface, char** ip);
+#endif
+
+celix_status_t endpointDiscoveryServer_create(
+ discovery_pt discovery,
+ bundle_context_pt context,
+ const char* defaultServerPath,
+ const char* defaultServerPort,
+ const char* defaultServerIp,
+ endpoint_discovery_server_pt *server) {
+ celix_status_t status;
+
+ const char *port = NULL;
+ const char *ip = NULL;
+ char *detectedIp = NULL;
+ const char *path = NULL;
+ const char *retries = NULL;
+
+ int max_ep_num = MAX_NUMBER_OF_RESTARTS;
+
+ *server = malloc(sizeof(struct endpoint_discovery_server));
+ if (!*server) {
+ return CELIX_ENOMEM;
+ }
+
+ (*server)->loghelper = &discovery->loghelper;
+ (*server)->entries = hashMap_create(&utils_stringHash, NULL, &utils_stringEquals, NULL);
+ if (!(*server)->entries) {
+ return CELIX_ENOMEM;
+ }
+
+ status = celixThreadMutex_create(&(*server)->serverLock, NULL);
+ if (status != CELIX_SUCCESS) {
+ return CELIX_BUNDLE_EXCEPTION;
+ }
+
+ bundleContext_getProperty(context, DISCOVERY_SERVER_IP, &ip);
+#ifndef ANDROID
+ if (ip == NULL) {
+ const char *interface = NULL;
+
+ bundleContext_getProperty(context, DISCOVERY_SERVER_INTERFACE, &interface);
+ if ((interface != NULL) && (endpointDiscoveryServer_getIpAdress((char*)interface, &detectedIp) != CELIX_SUCCESS)) {
+ logHelper_log(*(*server)->loghelper, OSGI_LOGSERVICE_WARNING, "Could not retrieve IP adress for interface %s", interface);
+ }
+
+ if (detectedIp == NULL) {
+ endpointDiscoveryServer_getIpAdress(NULL, &detectedIp);
+ }
+
+ ip = detectedIp;
+ }
+#endif
+
+ if (ip != NULL) {
+ logHelper_log(*(*server)->loghelper, OSGI_LOGSERVICE_INFO, "Using %s for service annunciation", ip);
+ (*server)->ip = strdup(ip);
+ }
+ else {
+ logHelper_log(*(*server)->loghelper, OSGI_LOGSERVICE_WARNING, "No IP address for service annunciation set. Using %s", defaultServerIp);
+ (*server)->ip = strdup((char*) defaultServerIp);
+ }
+
+ if (detectedIp != NULL) {
+ free(detectedIp);
+ }
+
+ bundleContext_getProperty(context, DISCOVERY_SERVER_PORT, &port);
+ if (port == NULL) {
+ port = defaultServerPort;
+ }
+
+ bundleContext_getProperty(context, DISCOVERY_SERVER_PATH, &path);
+ if (path == NULL) {
+ path = defaultServerPath;
+ }
+
+ bundleContext_getProperty(context, DISCOVERY_SERVER_MAX_EP, &retries);
+ if (retries != NULL) {
+ errno=0;
+ max_ep_num = strtol(retries,NULL,10);
+ if(errno!=0 || max_ep_num<=0){
+ max_ep_num=MAX_NUMBER_OF_RESTARTS;
+ }
+ }
+
+ (*server)->path = format_path(path);
+
+ const struct mg_callbacks callbacks = {
+ .begin_request = endpointDiscoveryServer_callback,
+ };
+
+ unsigned int port_counter = 0;
+ char newPort[10];
+
+ do {
+ const char *options[] = {
+ "listening_ports", port,
+ "num_threads", DEFAULT_SERVER_THREADS,
+ NULL
+ };
+
+ (*server)->ctx = mg_start(&callbacks, (*server), options);
+
+ if ((*server)->ctx != NULL)
+ {
+ logHelper_log(discovery->loghelper, OSGI_LOGSERVICE_INFO, "Starting discovery server on port %s...", port);
+ }
+ else {
+ errno = 0;
+ char* endptr = (char*)port;
+ long currentPort = strtol(port, &endptr, 10);
+
+ if (*endptr || errno != 0) {
+ currentPort = strtol(defaultServerPort, NULL, 10);
+ }
+
+ port_counter++;
+ snprintf(&newPort[0], 10, "%ld", (currentPort+1));
+
+ logHelper_log(discovery->loghelper, OSGI_LOGSERVICE_ERROR, "Error while starting discovery server on port %s - retrying on port %s...", port, newPort);
+ port = newPort;
+
+ }
+
+ } while(((*server)->ctx == NULL) && (port_counter < max_ep_num));
+
+ (*server)->port = strdup(port);
+
+ return status;
+}
+
+celix_status_t endpointDiscoveryServer_getUrl(endpoint_discovery_server_pt server, char* url)
+{
+ celix_status_t status = CELIX_BUNDLE_EXCEPTION;
+
+ if (server->ip && server->port && server->path) {
+ sprintf(url, "http://%s:%s/%s", server->ip, server->port, server->path);
+ status = CELIX_SUCCESS;
+ }
+
+ return status;
+}
+
+celix_status_t endpointDiscoveryServer_destroy(endpoint_discovery_server_pt server) {
+ celix_status_t status;
+
+ // stop & block until the actual server is shut down...
+ if (server->ctx != NULL) {
+ mg_stop(server->ctx);
+ server->ctx = NULL;
+ }
+
+ status = celixThreadMutex_lock(&server->serverLock);
+
+ hashMap_destroy(server->entries, true /* freeKeys */, false /* freeValues */);
+
+ status = celixThreadMutex_unlock(&server->serverLock);
+ status = celixThreadMutex_destroy(&server->serverLock);
+
+ free((void*) server->path);
+ free((void*) server->port);
+ free((void*) server->ip);
+
+ free(server);
+
+ return status;
+}
+
+celix_status_t endpointDiscoveryServer_addEndpoint(endpoint_discovery_server_pt server, endpoint_description_pt endpoint) {
+ celix_status_t status;
+
+ status = celixThreadMutex_lock(&server->serverLock);
+ if (status != CELIX_SUCCESS) {
+ return CELIX_BUNDLE_EXCEPTION;
+ }
+
+ // create a local copy of the endpointId which we can control...
+ char* endpointId = strdup(endpoint->id);
+ endpoint_description_pt cur_value = hashMap_get(server->entries, endpointId);
+ if (!cur_value) {
+ logHelper_log(*server->loghelper, OSGI_LOGSERVICE_INFO, "exposing new endpoint \"%s\"...", endpointId);
+
+ hashMap_put(server->entries, endpointId, endpoint);
+ }
+
+ status = celixThreadMutex_unlock(&server->serverLock);
+ if (status != CELIX_SUCCESS) {
+ return CELIX_BUNDLE_EXCEPTION;
+ }
+
+ return status;
+}
+
+celix_status_t endpointDiscoveryServer_removeEndpoint(endpoint_discovery_server_pt server, endpoint_description_pt endpoint) {
+ celix_status_t status;
+
+ status = celixThreadMutex_lock(&server->serverLock);
+ if (status != CELIX_SUCCESS) {
+ return CELIX_BUNDLE_EXCEPTION;
+ }
+
+ hash_map_entry_pt entry = hashMap_getEntry(server->entries, endpoint->id);
+ if (entry) {
+ char* key = hashMapEntry_getKey(entry);
+
+ logHelper_log(*server->loghelper, OSGI_LOGSERVICE_INFO, "removing endpoint \"%s\"...\n", key);
+
+ hashMap_remove(server->entries, key);
+
+ // we've made this key, see _addEnpoint above...
+ free((void*) key);
+ }
+
+ status = celixThreadMutex_unlock(&server->serverLock);
+ if (status != CELIX_SUCCESS) {
+ return CELIX_BUNDLE_EXCEPTION;
+ }
+
+ return status;
+}
+
+static char* format_path(const char* path) {
+ char* result = strdup(path);
+ result = utils_stringTrim(result);
+ // check whether the path starts with a leading slash...
+ if (result[0] != '/') {
+ size_t len = strlen(result);
+ result = realloc(result, len + 2);
+ memmove(result + 1, result, len);
+ result[0] = '/';
+ result[len + 1] = 0;
+ }
+ return result;
+}
+
+static celix_status_t endpointDiscoveryServer_getEndpoints(endpoint_discovery_server_pt server, const char* the_endpoint_id, array_list_pt *endpoints) {
+ celix_status_t status;
+
+ status = arrayList_create(endpoints);
+ if (status != CELIX_SUCCESS) {
+ return CELIX_ENOMEM;
+ }
+
+
+ hash_map_iterator_pt iter = hashMapIterator_create(server->entries);
+ while (hashMapIterator_hasNext(iter)) {
+ hash_map_entry_pt entry = hashMapIterator_nextEntry(iter);
+
+ char* endpoint_id = hashMapEntry_getKey(entry);
+ if (the_endpoint_id == NULL || strcmp(the_endpoint_id, endpoint_id) == 0) {
+ endpoint_description_pt endpoint = hashMapEntry_getValue(entry);
+
+ arrayList_add(*endpoints, endpoint);
+ }
+ }
+ hashMapIterator_destroy(iter);
+
+ return status;
+}
+
+static int endpointDiscoveryServer_writeEndpoints(struct mg_connection* conn, array_list_pt endpoints) {
+ celix_status_t status;
+ int rv = CIVETWEB_REQUEST_NOT_HANDLED;
+
+ endpoint_descriptor_writer_pt writer = NULL;
+ status = endpointDescriptorWriter_create(&writer);
+ if (status == CELIX_SUCCESS) {
+
+ char *buffer = NULL;
+ status = endpointDescriptorWriter_writeDocument(writer, endpoints, &buffer);
+ if (buffer) {
+ mg_write(conn, response_headers, strlen(response_headers));
+ mg_write(conn, buffer, strlen(buffer));
+ }
+
+ rv = CIVETWEB_REQUEST_HANDLED;
+ }
+
+ if(writer!=NULL){
+ endpointDescriptorWriter_destroy(writer);
+ }
+
+ return rv;
+}
+
+// returns all endpoints as XML...
+static int endpointDiscoveryServer_returnAllEndpoints(endpoint_discovery_server_pt server, struct mg_connection* conn) {
+ int status = CIVETWEB_REQUEST_NOT_HANDLED;
+
+ array_list_pt endpoints = NULL;
+
+ if (celixThreadMutex_lock(&server->serverLock) == CELIX_SUCCESS) {
+ endpointDiscoveryServer_getEndpoints(server, NULL, &endpoints);
+ if (endpoints) {
+ status = endpointDiscoveryServer_writeEndpoints(conn, endpoints);
+
+ arrayList_destroy(endpoints);
+ }
+
+
+ celixThreadMutex_unlock(&server->serverLock);
+ }
+
+ return status;
+}
+
+// returns a single endpoint as XML...
+static int endpointDiscoveryServer_returnEndpoint(endpoint_discovery_server_pt server, struct mg_connection* conn, const char* endpoint_id) {
+ int status = CIVETWEB_REQUEST_NOT_HANDLED;
+
+ array_list_pt endpoints = NULL;
+
+ if (celixThreadMutex_lock(&server->serverLock) == CELIX_SUCCESS) {
+ endpointDiscoveryServer_getEndpoints(server, endpoint_id, &endpoints);
+ if (endpoints) {
+ status = endpointDiscoveryServer_writeEndpoints(conn, endpoints);
+
+ arrayList_destroy(endpoints);
+ }
+
+ celixThreadMutex_unlock(&server->serverLock);
+ }
+
+ return status;
+}
+
+static int endpointDiscoveryServer_callback(struct mg_connection* conn) {
+ int status = CIVETWEB_REQUEST_NOT_HANDLED;
+
+ const struct mg_request_info *request_info = mg_get_request_info(conn);
+ if (request_info->uri != NULL && strcmp("GET", request_info->request_method) == 0) {
+ endpoint_discovery_server_pt server = request_info->user_data;
+
+ const char *uri = request_info->uri;
+ const size_t path_len = strlen(server->path);
+ const size_t uri_len = strlen(uri);
+
+ if (strncmp(server->path, uri, strlen(server->path)) == 0) {
+ // Be lenient when it comes to the trailing slash...
+ if (path_len == uri_len || (uri_len == (path_len + 1) && uri[path_len] == '/')) {
+ status = endpointDiscoveryServer_returnAllEndpoints(server, conn);
+ } else {
+ const char* endpoint_id = uri + path_len + 1; // right after the slash...
+
+ status = endpointDiscoveryServer_returnEndpoint(server, conn, endpoint_id);
+ }
+ }
+ }
+
+ return status;
+}
+
+#ifndef ANDROID
+static celix_status_t endpointDiscoveryServer_getIpAdress(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
http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/remote_services/discovery_configured/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/bundles/remote_services/discovery_configured/CMakeLists.txt b/bundles/remote_services/discovery_configured/CMakeLists.txt
new file mode 100644
index 0000000..089d1bd
--- /dev/null
+++ b/bundles/remote_services/discovery_configured/CMakeLists.txt
@@ -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.
+celix_subproject(RSA_DISCOVERY_CONFIGURED "Option to enable building the Discovery (Configured) bundle" ON)
+if (RSA_DISCOVERY_CONFIGURED)
+ find_package(CURL REQUIRED)
+ find_package(LibXml2 REQUIRED)
+
+ add_celix_bundle(rsa_discovery_configured
+ VERSION 0.9.0
+ SYMBOLIC_NAME "apache_celix_rsa_discovery_configured"
+ NAME "Apache Celix RSA Configured Discovery"
+ SOURCES
+ src/discovery_impl.c
+ $<TARGET_OBJECTS:Celix::rsa_discovery_common>
+ $<TARGET_OBJECTS:Celix::civetweb>
+ )
+ target_include_directories(rsa_discovery_configured PRIVATE
+ src
+ $<TARGET_PROPERTY:Celix::rsa_discovery_common,INCLUDE_DIRECTORIES>
+ $<TARGET_PROPERTY:Celix::civetweb,INCLUDE_DIRECTORIES>
+ )
+ target_link_libraries(rsa_discovery_configured PRIVATE ${CURL_LIBRARIES} ${LIBXML2_LIBRARIES} Celix::log_helper Celix::rsa_common)
+
+ install_celix_bundle(rsa_discovery_configured EXPORT celix COMPONENT rsa)
+ #Setup target aliases to match external usage
+ add_library(Celix::rsa_discovery_configured ALIAS rsa_discovery_configured)
+endif (RSA_DISCOVERY_CONFIGURED)
http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/remote_services/discovery_configured/src/desc.xml
----------------------------------------------------------------------
diff --git a/bundles/remote_services/discovery_configured/src/desc.xml b/bundles/remote_services/discovery_configured/src/desc.xml
new file mode 100644
index 0000000..5998992
--- /dev/null
+++ b/bundles/remote_services/discovery_configured/src/desc.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ *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-descriptions xmlns="http://www.osgi.org/xmlns/rsa/v1.0.0">
+ <endpoint-description>
+ <property name="service.intents">
+ <list>
+ <value>SOAP</value>
+ <value>HTTP</value>
+ </list>
+ </property>
+ <property name="endpoint.id" value="http://ws.acme.com:9000/hello" />
+ <property name="objectClass" value="com.acme.Foo" />
+ <property name="endpoint.package.version.com.acme" value="4.2" />
+ <property name="service.imported.configs" value="com.acme" />
+ <property name="com.acme.ws.xml">
+ <xml>
+ <config xmlns="http://acme.com/defs">
+ <port>1029</port>
+ <host>www.acme.com</host>
+ </config>
+ </xml>
+ </property>
+ </endpoint-description>
+</endpoint-descriptions>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/remote_services/discovery_configured/src/discovery_impl.c
----------------------------------------------------------------------
diff --git a/bundles/remote_services/discovery_configured/src/discovery_impl.c b/bundles/remote_services/discovery_configured/src/discovery_impl.c
new file mode 100644
index 0000000..89c777e
--- /dev/null
+++ b/bundles/remote_services/discovery_configured/src/discovery_impl.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.
+ */
+/*
+ * discovery_impl.c
+ *
+ * \date Aug 8, 2014
+ * \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 <stdbool.h>
+#include <netdb.h>
+
+#include "celix_threads.h"
+#include "bundle_context.h"
+#include "utils.h"
+#include "log_helper.h"
+
+#include "discovery.h"
+#include "discovery_impl.h"
+
+
+celix_status_t discovery_create(bundle_context_pt context, discovery_pt *discovery) {
+ celix_status_t status;
+
+ *discovery = malloc(sizeof(struct discovery));
+ if (!*discovery) {
+ status = CELIX_ENOMEM;
+ }
+ else {
+ (*discovery)->context = context;
+ (*discovery)->poller = NULL;
+ (*discovery)->server = NULL;
+
+ (*discovery)->listenerReferences = hashMap_create(serviceReference_hashCode, NULL, serviceReference_equals2, NULL);
+ (*discovery)->discoveredServices = hashMap_create(utils_stringHash, NULL, utils_stringEquals, NULL);
+
+ status = celixThreadMutex_create(&(*discovery)->listenerReferencesMutex, NULL);
+ status = celixThreadMutex_create(&(*discovery)->discoveredServicesMutex, NULL);
+
+ logHelper_create(context, &(*discovery)->loghelper);
+ }
+
+ return status;
+}
+
+celix_status_t discovery_start(discovery_pt discovery) {
+ celix_status_t status;
+
+ logHelper_start(discovery->loghelper);
+
+ status = endpointDiscoveryPoller_create(discovery, discovery->context, DEFAULT_POLL_ENDPOINTS, &discovery->poller);
+ if (status != CELIX_SUCCESS) {
+ return CELIX_BUNDLE_EXCEPTION;
+ }
+
+ status = endpointDiscoveryServer_create(discovery, discovery->context, DEFAULT_SERVER_PATH, DEFAULT_SERVER_PORT, DEFAULT_SERVER_IP, &discovery->server);
+ if (status != CELIX_SUCCESS) {
+ return CELIX_BUNDLE_EXCEPTION;
+ }
+
+ return status;
+}
+
+celix_status_t discovery_stop(discovery_pt discovery) {
+ celix_status_t status;
+
+ status = endpointDiscoveryServer_destroy(discovery->server);
+ status = endpointDiscoveryPoller_destroy(discovery->poller);
+
+ logHelper_stop(discovery->loghelper);
+
+ return status;
+}
+
+celix_status_t discovery_destroy(discovery_pt discovery) {
+ celix_status_t status = CELIX_SUCCESS;
+
+ discovery->context = NULL;
+ discovery->poller = NULL;
+ discovery->server = NULL;
+
+ celixThreadMutex_lock(&discovery->discoveredServicesMutex);
+
+ hashMap_destroy(discovery->discoveredServices, false, false);
+ discovery->discoveredServices = NULL;
+
+ celixThreadMutex_unlock(&discovery->discoveredServicesMutex);
+
+ celixThreadMutex_destroy(&discovery->discoveredServicesMutex);
+
+ celixThreadMutex_lock(&discovery->listenerReferencesMutex);
+
+ hashMap_destroy(discovery->listenerReferences, false, false);
+ discovery->listenerReferences = NULL;
+
+ celixThreadMutex_unlock(&discovery->listenerReferencesMutex);
+
+ celixThreadMutex_destroy(&discovery->listenerReferencesMutex);
+
+ logHelper_destroy(&discovery->loghelper);
+
+ free(discovery);
+
+ return status;
+}
http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/remote_services/discovery_configured/src/discovery_impl.h
----------------------------------------------------------------------
diff --git a/bundles/remote_services/discovery_configured/src/discovery_impl.h b/bundles/remote_services/discovery_configured/src/discovery_impl.h
new file mode 100644
index 0000000..a9d56c1
--- /dev/null
+++ b/bundles/remote_services/discovery_configured/src/discovery_impl.h
@@ -0,0 +1,62 @@
+/**
+ *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.
+ */
+/*
+ * discovery_impl.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 DISCOVERY_IMPL_H_
+#define DISCOVERY_IMPL_H_
+
+#include "bundle_context.h"
+#include "service_reference.h"
+
+#include "endpoint_description.h"
+#include "endpoint_listener.h"
+
+#include "endpoint_discovery_poller.h"
+#include "endpoint_discovery_server.h"
+
+#include "log_helper.h"
+
+#define DEFAULT_SERVER_IP "127.0.0.1"
+#define DEFAULT_SERVER_PORT "9999"
+#define DEFAULT_SERVER_PATH "/org.apache.celix.discovery.configured"
+#define DEFAULT_POLL_ENDPOINTS "http://localhost:9999/org.apache.celix.discovery.configured"
+
+
+//struct discovery_impl {
+// bundle_context_pt context;
+//
+// celix_thread_mutex_t listenerReferencesMutex;
+// celix_thread_mutex_t discoveredServicesMutex;
+//
+// hash_map_pt listenerReferences; //key=serviceReference, value=nop
+// hash_map_pt discoveredServices; //key=endpointId (string), value=endpoint_description_pt
+//
+// endpoint_discovery_poller_pt poller;
+// endpoint_discovery_server_pt server;
+//
+// log_helper_pt loghelper;
+//};
+
+#endif /* DISCOVERY_IMPL_H_ */
http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/remote_services/discovery_etcd/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/bundles/remote_services/discovery_etcd/CMakeLists.txt b/bundles/remote_services/discovery_etcd/CMakeLists.txt
new file mode 100644
index 0000000..c20c4f9
--- /dev/null
+++ b/bundles/remote_services/discovery_etcd/CMakeLists.txt
@@ -0,0 +1,50 @@
+# 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(RSA_DISCOVERY_ETCD "Option to enable building the Discovery (ETCD) bundle" ON)
+if (RSA_DISCOVERY_ETCD)
+ find_package(CURL REQUIRED)
+ find_package(LibXml2 REQUIRED)
+ find_package(Jansson REQUIRED)
+
+ add_celix_bundle(rsa_discovery_etcd
+ VERSION 0.9.0
+ SYMBOLIC_NAME "apache_celix_rsa_discovery_etcd"
+ NAME "Apache Celix RSA Discovery ETCD"
+ SOURCES
+ src/discovery_impl.c
+ src/etcd_watcher.c
+ $<TARGET_OBJECTS:Celix::rsa_discovery_common>
+ $<TARGET_OBJECTS:Celix::civetweb>
+ )
+ target_link_libraries(rsa_discovery_etcd PRIVATE Celix::log_helper Celix::etcdlib_static Celix::rsa_common)
+ target_include_directories(rsa_discovery_etcd PRIVATE src)
+ target_include_directories(rsa_discovery_etcd PRIVATE
+ $<TARGET_PROPERTY:Celix::rsa_discovery_common,INCLUDE_DIRECTORIES>
+ $<TARGET_PROPERTY:Celix::civetweb,INCLUDE_DIRECTORIES>
+ )
+ target_include_directories(rsa_discovery_etcd SYSTEM PRIVATE
+ ${CURL_INCLUDE_DIR}
+ ${JANSSON_INCLUDE_DIR}
+ ${LIBXML2_INCLUDE_DIR}
+ )
+ target_link_libraries(rsa_discovery_etcd PRIVATE ${CURL_LIBRARIES} ${LIBXML2_LIBRARIES} ${JANSSON_LIBRARIES})
+
+ install_celix_bundle(rsa_discovery_etcd EXPORT celix COMPONENT rsa)
+ #Setup target aliases to match external usage
+ add_library(Celix::rsa_discovery_etcd ALIAS rsa_discovery_etcd)
+endif (RSA_DISCOVERY_ETCD)
http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/remote_services/discovery_etcd/README.md
----------------------------------------------------------------------
diff --git a/bundles/remote_services/discovery_etcd/README.md b/bundles/remote_services/discovery_etcd/README.md
new file mode 100644
index 0000000..e560264
--- /dev/null
+++ b/bundles/remote_services/discovery_etcd/README.md
@@ -0,0 +1,29 @@
+<!--
+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.
+-->
+
+## Discovery ETCD
+
+The Celix Discovery ETCD bundles realizes OSGi services discovery based on [etcd](https://github.com/coreos/etcd).
+
+###### Properties
+ DISCOVERY_ETCD_ROOT_PATH used path (default: discovery)
+ DEFAULT_ETCD_SERVER_IP ip address of the etcd server (default: 127.0.0.1)
+ DEFAULT_ETCD_SERVER_PORT port of the etcd server (default: 2379)
+ DEFAULT_ETCD_TTL time-to-live for etcd entries in seconds (default: 30)
+
+###### CMake option
+ BUILD_RSA_DISCOVERY_ETCD=ON
http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/remote_services/discovery_etcd/src/discovery_impl.c
----------------------------------------------------------------------
diff --git a/bundles/remote_services/discovery_etcd/src/discovery_impl.c b/bundles/remote_services/discovery_etcd/src/discovery_impl.c
new file mode 100644
index 0000000..500399e
--- /dev/null
+++ b/bundles/remote_services/discovery_etcd/src/discovery_impl.c
@@ -0,0 +1,193 @@
+/**
+ * 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.
+ */
+/*
+ * discovery_impl.c
+ *
+ * \date Aug 8, 2014
+ * \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 <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 "remote_constants.h"
+
+
+#include "discovery.h"
+#include "discovery_impl.h"
+#include "etcd_watcher.h"
+#include "endpoint_discovery_poller.h"
+#include "endpoint_discovery_server.h"
+
+
+
+celix_status_t discovery_create(bundle_context_pt context, discovery_t** out) {
+ celix_status_t status = CELIX_SUCCESS;
+
+ discovery_t* discovery = calloc(1, sizeof(*discovery));
+ discovery_impl_t* pImpl = calloc(1, sizeof(*pImpl));
+
+ if (discovery != NULL && pImpl != NULL) {
+ discovery->pImpl = pImpl;
+ discovery->context = context;
+ discovery->poller = NULL;
+ discovery->server = NULL;
+
+ discovery->listenerReferences = hashMap_create(serviceReference_hashCode, NULL, serviceReference_equals2,
+ NULL);
+ discovery->discoveredServices = hashMap_create(utils_stringHash, NULL, utils_stringEquals, NULL);
+
+ status = celixThreadMutex_create(&discovery->listenerReferencesMutex, NULL);
+ status = celixThreadMutex_create(&discovery->discoveredServicesMutex, NULL);
+
+ logHelper_create(context, &discovery->loghelper);
+ } else {
+ status = CELIX_ENOMEM;
+ free(discovery);
+ free(pImpl);
+ }
+
+ if (status == CELIX_SUCCESS) {
+ *out = discovery;
+ }
+
+ return status;
+}
+
+
+
+celix_status_t discovery_destroy(discovery_pt discovery) {
+ celix_status_t status = CELIX_SUCCESS;
+
+ discovery->context = NULL;
+ discovery->poller = NULL;
+ discovery->server = NULL;
+
+ celixThreadMutex_lock(&discovery->discoveredServicesMutex);
+
+ hashMap_destroy(discovery->discoveredServices, false, false);
+ discovery->discoveredServices = NULL;
+
+ celixThreadMutex_unlock(&discovery->discoveredServicesMutex);
+
+ celixThreadMutex_destroy(&discovery->discoveredServicesMutex);
+
+ celixThreadMutex_lock(&discovery->listenerReferencesMutex);
+
+ hashMap_destroy(discovery->listenerReferences, false, false);
+ discovery->listenerReferences = NULL;
+
+ celixThreadMutex_unlock(&discovery->listenerReferencesMutex);
+
+ celixThreadMutex_destroy(&discovery->listenerReferencesMutex);
+
+ logHelper_destroy(&discovery->loghelper);
+
+ free(discovery);
+
+ return status;
+}
+
+celix_status_t discovery_start(discovery_pt discovery) {
+ celix_status_t status = CELIX_SUCCESS;
+ const char *port = NULL;
+ const char *path = NULL;
+
+ logHelper_start(discovery->loghelper);
+
+ bundleContext_getProperty(discovery->context, DISCOVERY_SERVER_PORT, &port);
+ if (port == NULL) {
+ port = DEFAULT_SERVER_PORT;
+ }
+
+ bundleContext_getProperty(discovery->context, DISCOVERY_SERVER_PATH, &path);
+ if (path == NULL) {
+ path = DEFAULT_SERVER_PATH;
+ }
+
+ status = endpointDiscoveryPoller_create(discovery, discovery->context, DEFAULT_POLL_ENDPOINTS, &discovery->poller);
+ if (status != CELIX_SUCCESS) {
+ return CELIX_BUNDLE_EXCEPTION;
+ }
+
+ status = endpointDiscoveryServer_create(discovery, discovery->context, DEFAULT_SERVER_PATH, DEFAULT_SERVER_PORT, DEFAULT_SERVER_IP, &discovery->server);
+ if (status != CELIX_SUCCESS) {
+ return CELIX_BUNDLE_EXCEPTION;
+ }
+
+ status = etcdWatcher_create(discovery, discovery->context, &discovery->pImpl->watcher);
+ if (status != CELIX_SUCCESS) {
+ return CELIX_BUNDLE_EXCEPTION;
+ }
+ return status;
+}
+
+celix_status_t discovery_stop(discovery_pt discovery) {
+ celix_status_t status;
+
+ status = etcdWatcher_destroy(discovery->pImpl->watcher);
+ if (status != CELIX_SUCCESS) {
+ return CELIX_BUNDLE_EXCEPTION;
+ }
+
+ status = endpointDiscoveryServer_destroy(discovery->server);
+ if (status != CELIX_SUCCESS) {
+ return CELIX_BUNDLE_EXCEPTION;
+ }
+
+ status = endpointDiscoveryPoller_destroy(discovery->poller);
+ if (status != CELIX_SUCCESS) {
+ return CELIX_BUNDLE_EXCEPTION;
+ }
+ hash_map_iterator_pt iter;
+
+ celixThreadMutex_lock(&discovery->discoveredServicesMutex);
+
+ iter = hashMapIterator_create(discovery->discoveredServices);
+ while (hashMapIterator_hasNext(iter)) {
+ hash_map_entry_pt entry = hashMapIterator_nextEntry(iter);
+ endpoint_description_pt endpoint = hashMapEntry_getValue(entry);
+
+ discovery_informEndpointListeners(discovery, endpoint, false);
+ }
+ hashMapIterator_destroy(iter);
+
+ celixThreadMutex_unlock(&discovery->discoveredServicesMutex);
+
+
+ logHelper_stop(discovery->loghelper);
+
+ return status;
+}
+
+
+
http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/remote_services/discovery_etcd/src/discovery_impl.h
----------------------------------------------------------------------
diff --git a/bundles/remote_services/discovery_etcd/src/discovery_impl.h b/bundles/remote_services/discovery_etcd/src/discovery_impl.h
new file mode 100644
index 0000000..f28017b
--- /dev/null
+++ b/bundles/remote_services/discovery_etcd/src/discovery_impl.h
@@ -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.
+ */
+/*
+ * discovery_impl.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 DISCOVERY_IMPL_H_
+#define DISCOVERY_IMPL_H_
+
+#include "bundle_context.h"
+#include "service_reference.h"
+
+#include "endpoint_description.h"
+#include "endpoint_listener.h"
+
+#include "endpoint_discovery_poller.h"
+#include "endpoint_discovery_server.h"
+#include "etcd_watcher.h"
+
+#include "log_helper.h"
+
+#define DEFAULT_SERVER_IP "127.0.0.1"
+#define DEFAULT_SERVER_PORT "9999"
+#define DEFAULT_SERVER_PATH "/org.apache.celix.discovery.etcd"
+
+#define DEFAULT_POLL_ENDPOINTS ""
+
+#define FREE_MEM(ptr) if(ptr) {free(ptr); ptr = NULL;}
+
+struct discovery_impl {
+ etcd_watcher_t* watcher;
+};
+
+#endif /* DISCOVERY_H_ */
http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/remote_services/discovery_etcd/src/etcd_watcher.c
----------------------------------------------------------------------
diff --git a/bundles/remote_services/discovery_etcd/src/etcd_watcher.c b/bundles/remote_services/discovery_etcd/src/etcd_watcher.c
new file mode 100644
index 0000000..ebeac4f
--- /dev/null
+++ b/bundles/remote_services/discovery_etcd/src/etcd_watcher.c
@@ -0,0 +1,397 @@
+/**
+ * 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.
+ */
+/*
+ * etcd_watcher.c
+ *
+ * \date 16 Sep 2014
+ * \author <a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ * \copyright Apache License, Version 2.0
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "log_helper.h"
+#include "log_service.h"
+#include "constants.h"
+#include "utils.h"
+#include "discovery.h"
+#include "discovery_impl.h"
+
+#include <curl/curl.h>
+#include "etcd.h"
+#include "etcd_watcher.h"
+
+#include "endpoint_discovery_poller.h"
+
+struct etcd_watcher {
+ discovery_pt discovery;
+ log_helper_pt* loghelper;
+ hash_map_pt entries;
+
+ celix_thread_mutex_t watcherLock;
+ celix_thread_t watcherThread;
+
+ volatile bool running;
+};
+
+
+#define MAX_ROOTNODE_LENGTH 128
+#define MAX_LOCALNODE_LENGTH 4096
+#define MAX_VALUE_LENGTH 256
+
+#define CFG_ETCD_ROOT_PATH "DISCOVERY_ETCD_ROOT_PATH"
+#define DEFAULT_ETCD_ROOTPATH "discovery"
+
+#define CFG_ETCD_SERVER_IP "DISCOVERY_ETCD_SERVER_IP"
+#define DEFAULT_ETCD_SERVER_IP "127.0.0.1"
+
+#define CFG_ETCD_SERVER_PORT "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
+
+
+// note that the rootNode shouldn't have a leading slash
+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 celix_status_t etcdWatcher_getLocalNodePath(bundle_context_pt context, char* localNodePath) {
+ celix_status_t status = CELIX_SUCCESS;
+ char rootPath[MAX_ROOTNODE_LENGTH];
+ const char* uuid = NULL;
+
+ if ((etcdWatcher_getRootPath(context, rootPath) != CELIX_SUCCESS)) {
+ status = CELIX_ILLEGAL_STATE;
+ }
+ else if (((bundleContext_getProperty(context, OSGI_FRAMEWORK_FRAMEWORK_UUID, &uuid)) != CELIX_SUCCESS) || (!uuid)) {
+ status = CELIX_ILLEGAL_STATE;
+ }
+ else if (rootPath[strlen(rootPath) - 1] == '/') {
+ snprintf(localNodePath, MAX_LOCALNODE_LENGTH, "%s%s", rootPath, uuid);
+ }
+ else {
+ snprintf(localNodePath, MAX_LOCALNODE_LENGTH, "%s/%s", rootPath, uuid);
+ }
+
+ return status;
+}
+
+static void add_node(const char *key, const char *value, void* arg) {
+ discovery_pt discovery = (discovery_pt) arg;
+ endpointDiscoveryPoller_addDiscoveryEndpoint(discovery->poller, (char *) value);
+}
+
+/*
+ * retrieves all already existing discovery endpoints
+ * from etcd and adds them to the poller.
+ *
+ * returns the modifiedIndex of the last modified
+ * discovery endpoint (see etcd documentation).
+ */
+static celix_status_t etcdWatcher_addAlreadyExistingWatchpoints(discovery_pt discovery, long long* highestModified) {
+ celix_status_t status = CELIX_SUCCESS;
+
+ char rootPath[MAX_ROOTNODE_LENGTH];
+ status = etcdWatcher_getRootPath(discovery->context, rootPath);
+
+ if (status == CELIX_SUCCESS) {
+ if(etcd_get_directory(rootPath, add_node, discovery, highestModified)) {
+ status = CELIX_ILLEGAL_ARGUMENT;
+ }
+ }
+
+ return status;
+}
+
+
+static celix_status_t etcdWatcher_addOwnFramework(etcd_watcher_pt watcher)
+{
+ celix_status_t status = CELIX_BUNDLE_EXCEPTION;
+ char localNodePath[MAX_LOCALNODE_LENGTH];
+ char *value;
+ char url[MAX_VALUE_LENGTH];
+ int modIndex;
+ char* endpoints = NULL;
+ const char* ttlStr = NULL;
+ int ttl;
+
+ bundle_context_pt context = watcher->discovery->context;
+ endpoint_discovery_server_pt server = watcher->discovery->server;
+
+ // register own framework
+ if ((status = etcdWatcher_getLocalNodePath(context, localNodePath)) != CELIX_SUCCESS) {
+ return status;
+ }
+
+ if (endpointDiscoveryServer_getUrl(server, url) != CELIX_SUCCESS) {
+ snprintf(url, MAX_VALUE_LENGTH, "http://%s:%s/%s", DEFAULT_SERVER_IP, DEFAULT_SERVER_PORT, DEFAULT_SERVER_PATH);
+ }
+
+ endpoints = url;
+
+ if ((bundleContext_getProperty(context, CFG_ETCD_TTL, &ttlStr) != CELIX_SUCCESS) || !ttlStr) {
+ ttl = DEFAULT_ETCD_TTL;
+ }
+ else
+ {
+ char* endptr = (char *) ttlStr;
+ errno = 0;
+ ttl = strtol(ttlStr, &endptr, 10);
+ if (*endptr || errno != 0) {
+ ttl = DEFAULT_ETCD_TTL;
+ }
+ }
+
+ if (etcd_get(localNodePath, &value, &modIndex) != true) {
+ etcd_set(localNodePath, endpoints, ttl, false);
+ }
+ else if (etcd_set(localNodePath, endpoints, ttl, true) == false) {
+ logHelper_log(*watcher->loghelper, OSGI_LOGSERVICE_WARNING, "Cannot register local discovery");
+ }
+ else {
+ status = CELIX_SUCCESS;
+ }
+
+ FREE_MEM(value);
+
+ return status;
+}
+
+
+
+
+static celix_status_t etcdWatcher_addEntry(etcd_watcher_pt watcher, char* key, char* value) {
+ celix_status_t status = CELIX_BUNDLE_EXCEPTION;
+ endpoint_discovery_poller_pt poller = watcher->discovery->poller;
+
+ if (!hashMap_containsKey(watcher->entries, key)) {
+ status = endpointDiscoveryPoller_addDiscoveryEndpoint(poller, value);
+
+ if (status == CELIX_SUCCESS) {
+ hashMap_put(watcher->entries, strdup(key), strdup(value));
+ }
+ }
+
+ return status;
+}
+
+static celix_status_t etcdWatcher_removeEntry(etcd_watcher_pt watcher, char* key, char* value) {
+ celix_status_t status = CELIX_BUNDLE_EXCEPTION;
+ endpoint_discovery_poller_pt poller = watcher->discovery->poller;
+
+ hash_map_entry_pt entry = hashMap_getEntry(watcher->entries, key);
+
+ if (entry != NULL) {
+ void* origKey = hashMapEntry_getKey(entry);
+ void* value = hashMap_remove(watcher->entries, key);
+
+ free(origKey);
+
+ // check if there is another entry with the same value
+ hash_map_iterator_pt iter = hashMapIterator_create(watcher->entries);
+ unsigned int valueFound = 0;
+
+ while (hashMapIterator_hasNext(iter) && valueFound <= 1) {
+ if (strcmp(value, hashMapIterator_nextValue(iter)) == 0)
+ valueFound++;
+ }
+
+ hashMapIterator_destroy(iter);
+
+ if (valueFound == 0)
+ status = endpointDiscoveryPoller_removeDiscoveryEndpoint(poller, value);
+
+ free(value);
+
+ }
+
+ 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;
+
+ bundle_context_pt context = watcher->discovery->context;
+
+ etcdWatcher_addAlreadyExistingWatchpoints(watcher->discovery, &highestModified);
+ etcdWatcher_getRootPath(context, rootPath);
+
+ while (watcher->running) {
+
+ char *rkey = NULL;
+ char *value = NULL;
+ char *preValue = NULL;
+ char *action = NULL;
+ long long modIndex;
+
+ if (etcd_watch(rootPath, highestModified + 1, &action, &preValue, &value, &rkey, &modIndex) == 0 && action != NULL) {
+ if (strcmp(action, "set") == 0) {
+ etcdWatcher_addEntry(watcher, rkey, value);
+ } else if (strcmp(action, "delete") == 0) {
+ etcdWatcher_removeEntry(watcher, rkey, value);
+ } else if (strcmp(action, "expire") == 0) {
+ etcdWatcher_removeEntry(watcher, rkey, value);
+ } else if (strcmp(action, "update") == 0) {
+ etcdWatcher_addEntry(watcher, rkey, value);
+ } else {
+ logHelper_log(*watcher->loghelper, OSGI_LOGSERVICE_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);
+
+ // update own framework uuid
+ if (time(NULL) - timeBeforeWatch > (DEFAULT_ETCD_TTL / 4)) {
+ etcdWatcher_addOwnFramework(watcher);
+ timeBeforeWatch = time(NULL);
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * the ectdWatcher needs to have access to the endpoint_discovery_poller and therefore is only
+ * allowed to be created after the endpoint_discovery_poller
+ */
+celix_status_t etcdWatcher_create(discovery_pt discovery, bundle_context_pt context,
+ etcd_watcher_pt *watcher)
+{
+ celix_status_t status = CELIX_SUCCESS;
+
+ const char* etcd_server = NULL;
+ const char* etcd_port_string = NULL;
+ int etcd_port = 0;
+
+ if (discovery == NULL) {
+ return CELIX_BUNDLE_EXCEPTION;
+ }
+
+ (*watcher) = calloc(1, sizeof(struct etcd_watcher));
+ if (!*watcher) {
+ return CELIX_ENOMEM;
+ }
+ else
+ {
+ (*watcher)->discovery = discovery;
+ (*watcher)->loghelper = &discovery->loghelper;
+ (*watcher)->entries = hashMap_create(utils_stringHash, NULL, utils_stringEquals, NULL);
+ }
+
+ 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 = (char*)etcd_port_string;
+ errno = 0;
+ etcd_port = strtol(etcd_port_string, &endptr, 10);
+ if (*endptr || errno != 0) {
+ etcd_port = DEFAULT_ETCD_SERVER_PORT;
+ }
+ }
+
+ if (etcd_init((char*) etcd_server, etcd_port, CURL_GLOBAL_DEFAULT) != 0) {
+ status = CELIX_BUNDLE_EXCEPTION;
+ } else {
+ status = CELIX_SUCCESS;
+ }
+
+ if (status == CELIX_SUCCESS) {
+ etcdWatcher_addOwnFramework(*watcher);
+ status = celixThreadMutex_create(&(*watcher)->watcherLock, NULL);
+ }
+
+ if (status == CELIX_SUCCESS) {
+ if (celixThreadMutex_lock(&(*watcher)->watcherLock) == CELIX_SUCCESS) {
+ status = celixThread_create(&(*watcher)->watcherThread, NULL, etcdWatcher_run, *watcher);
+ if (status == CELIX_SUCCESS) {
+ (*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 localNodePath[MAX_LOCALNODE_LENGTH];
+
+ celixThreadMutex_lock(&watcher->watcherLock);
+ watcher->running = false;
+ celixThreadMutex_unlock(&watcher->watcherLock);
+
+ celixThread_join(watcher->watcherThread, NULL);
+
+ // register own framework
+ status = etcdWatcher_getLocalNodePath(watcher->discovery->context, localNodePath);
+
+ if (status != CELIX_SUCCESS || etcd_del(localNodePath) == false)
+ {
+ logHelper_log(*watcher->loghelper, OSGI_LOGSERVICE_WARNING, "Cannot remove local discovery registration.");
+ }
+
+ watcher->loghelper = NULL;
+
+ hashMap_destroy(watcher->entries, true, true);
+
+ free(watcher);
+
+ return status;
+}
+
http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/remote_services/discovery_etcd/src/etcd_watcher.h
----------------------------------------------------------------------
diff --git a/bundles/remote_services/discovery_etcd/src/etcd_watcher.h b/bundles/remote_services/discovery_etcd/src/etcd_watcher.h
new file mode 100644
index 0000000..56bae92
--- /dev/null
+++ b/bundles/remote_services/discovery_etcd/src/etcd_watcher.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.
+ */
+/*
+ * etcd_watcher.h
+ *
+ * \date 17 Sep 2014
+ * \author <a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ * \copyright Apache License, Version 2.0
+ */
+
+#ifndef ETCD_WATCHER_H_
+#define ETCD_WATCHER_H_
+
+#include "celix_errno.h"
+#include "discovery.h"
+#include "endpoint_discovery_poller.h"
+
+typedef struct etcd_watcher etcd_watcher_t;
+typedef struct etcd_watcher *etcd_watcher_pt;
+
+celix_status_t etcdWatcher_create(discovery_pt discovery, bundle_context_pt context, etcd_watcher_pt *watcher);
+celix_status_t etcdWatcher_destroy(etcd_watcher_pt watcher);
+
+
+#endif /* ETCD_WATCHER_H_ */
http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/remote_services/discovery_shm/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/bundles/remote_services/discovery_shm/CMakeLists.txt b/bundles/remote_services/discovery_shm/CMakeLists.txt
new file mode 100644
index 0000000..28c1fd4
--- /dev/null
+++ b/bundles/remote_services/discovery_shm/CMakeLists.txt
@@ -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.
+
+celix_subproject(RSA_DISCOVERY_SHM "Option to enable building the Discovery (SHM) bundle" OFF)
+if (RSA_DISCOVERY_SHM)
+find_package(CURL REQUIRED)
+ find_package(LibXml2 REQUIRED)
+
+ add_celix_bundle(rsa_discovery_shm
+ VERSION 0.0.1
+ SYMBOLIC_NAME "apache_celix_rsa_discovery_shm"
+ NAME "Apache Celix RSA Discovery SHM"
+ SOURCES
+ src/discovery_shm.c
+ src/discovery_shmWatcher.c
+ src/discovery_impl.c
+ $<TARGET_OBJECTS:Celix::rsa_discovery_common>
+ $<TARGET_OBJECTS:Celix::civetweb>
+ )
+ target_include_directories(rsa_discovery_shm PRIVATE
+ src
+ ${LIBXML2_INCLUDE_DIR}
+ ${CURL_INCLUDE_DIR}
+ $<TARGET_PROPERTY:Celix::rsa_discovery_common,INCLUDE_DIRECTORIES>
+ $<TARGET_PROPERTY:Celix::civetweb,INCLUDE_DIRECTORIES>
+ )
+ target_link_libraries(rsa_discovery_shm PRIVATE Celix::framework ${CURL_LIBRARIES} ${LIBXML2_LIBRARIES})
+
+ install_celix_bundle(rsa_discovery_shm EXPORT celix COMPONENT rsa)
+
+ #Setup target aliases to match external usage
+ add_library(Celix::rsa_discovery_shm ALIAS rsa_discovery_shm)
+endif (RSA_DISCOVERY_SHM)
http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/remote_services/discovery_shm/src/discovery_impl.c
----------------------------------------------------------------------
diff --git a/bundles/remote_services/discovery_shm/src/discovery_impl.c b/bundles/remote_services/discovery_shm/src/discovery_impl.c
new file mode 100644
index 0000000..fadff8c
--- /dev/null
+++ b/bundles/remote_services/discovery_shm/src/discovery_impl.c
@@ -0,0 +1,169 @@
+/**
+ * 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.
+ */
+/*
+ * discovery_impl.c
+ *
+ * \date Aug 8, 2014
+ * \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 <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 "remote_constants.h"
+
+
+#include "discovery.h"
+#include "discovery_impl.h"
+#include "discovery_shmWatcher.h"
+#include "endpoint_discovery_poller.h"
+#include "endpoint_discovery_server.h"
+
+celix_status_t discovery_create(bundle_context_pt context, discovery_t** out) {
+ celix_status_t status = CELIX_SUCCESS;
+
+ discovery_t* discovery = calloc(1, sizeof(*discovery));
+ discovery_impl_t* pImpl = calloc(1, sizeof(*pImpl));
+ if (discovery != NULL && pImpl != NULL) {
+ discovery->pImpl = pImpl;
+ discovery->context = context;
+ discovery->poller = NULL;
+ discovery->server = NULL;
+
+ discovery->listenerReferences = hashMap_create(serviceReference_hashCode, NULL, serviceReference_equals2, NULL);
+ discovery->discoveredServices = hashMap_create(utils_stringHash, NULL, utils_stringEquals, NULL);
+
+ celixThreadMutex_create(&discovery->listenerReferencesMutex, NULL);
+ celixThreadMutex_create(&discovery->discoveredServicesMutex, NULL);
+
+ if (logHelper_create(context, &discovery->loghelper) == CELIX_SUCCESS) {
+ logHelper_start(discovery->loghelper);
+ }
+ } else {
+ status = CELIX_ENOMEM;
+ free(discovery);
+ free(pImpl);
+ }
+
+ if (status == CELIX_SUCCESS) {
+ *out = discovery;
+ }
+
+ return status;
+}
+
+
+
+celix_status_t discovery_destroy(discovery_pt discovery) {
+ celix_status_t status = CELIX_SUCCESS;
+
+ discovery->context = NULL;
+ discovery->poller = NULL;
+ discovery->server = NULL;
+
+ celixThreadMutex_lock(&discovery->discoveredServicesMutex);
+
+ hashMap_destroy(discovery->discoveredServices, false, false);
+ discovery->discoveredServices = NULL;
+
+ celixThreadMutex_unlock(&discovery->discoveredServicesMutex);
+
+ celixThreadMutex_destroy(&discovery->discoveredServicesMutex);
+
+ celixThreadMutex_lock(&discovery->listenerReferencesMutex);
+
+ hashMap_destroy(discovery->listenerReferences, false, false);
+ discovery->listenerReferences = NULL;
+
+ celixThreadMutex_unlock(&discovery->listenerReferencesMutex);
+
+ celixThreadMutex_destroy(&discovery->listenerReferencesMutex);
+
+
+
+
+ free(discovery);
+
+ return status;
+}
+
+celix_status_t discovery_start(discovery_pt discovery) {
+ celix_status_t status;
+
+ status = endpointDiscoveryPoller_create(discovery, discovery->context, DEFAULT_POLL_ENDPOINTS, &discovery->poller);
+ if (status == CELIX_SUCCESS) {
+ status = endpointDiscoveryServer_create(discovery, discovery->context, DEFAULT_SERVER_PATH, DEFAULT_SERVER_PORT, DEFAULT_SERVER_IP, &discovery->server);
+ }
+
+ if (status == CELIX_SUCCESS) {
+ status = discoveryShmWatcher_create(discovery);
+ }
+
+ return status;
+}
+
+celix_status_t discovery_stop(discovery_pt discovery) {
+ celix_status_t status;
+
+ status = discoveryShmWatcher_destroy(discovery);
+
+ if (status == CELIX_SUCCESS) {
+ status = endpointDiscoveryServer_destroy(discovery->server);
+ }
+
+ endpointDiscoveryPoller_destroy(discovery->poller);
+
+ if (status == CELIX_SUCCESS) {
+ hash_map_iterator_pt iter;
+
+ celixThreadMutex_lock(&discovery->discoveredServicesMutex);
+
+ iter = hashMapIterator_create(discovery->discoveredServices);
+ while (hashMapIterator_hasNext(iter)) {
+ hash_map_entry_pt entry = hashMapIterator_nextEntry(iter);
+ endpoint_description_pt endpoint = hashMapEntry_getValue(entry);
+
+ discovery_informEndpointListeners(discovery, endpoint, false);
+ }
+ hashMapIterator_destroy(iter);
+
+ celixThreadMutex_unlock(&discovery->discoveredServicesMutex);
+
+ logHelper_stop(discovery->loghelper);
+ logHelper_destroy(&discovery->loghelper);
+ }
+
+ return status;
+}
+
+
+
http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/remote_services/discovery_shm/src/discovery_impl.h
----------------------------------------------------------------------
diff --git a/bundles/remote_services/discovery_shm/src/discovery_impl.h b/bundles/remote_services/discovery_shm/src/discovery_impl.h
new file mode 100644
index 0000000..e994b1f
--- /dev/null
+++ b/bundles/remote_services/discovery_shm/src/discovery_impl.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.
+ */
+/*
+ * discovery_impl.h
+ *
+ * \date Oct 01, 2014
+ * \author <a href="mailto:celix-dev@celix.apache.org">Apache Celix Project Team</a>
+ * \copyright Apache License, Version 2.0
+ */
+
+#ifndef DISCOVERY_IMPL_H_
+#define DISCOVERY_IMPL_H_
+
+#include "bundle_context.h"
+#include "service_reference.h"
+
+#include "endpoint_description.h"
+#include "endpoint_listener.h"
+
+#include "endpoint_discovery_poller.h"
+#include "endpoint_discovery_server.h"
+#include "discovery_shmWatcher.h"
+
+#define DEFAULT_SERVER_IP "127.0.0.1"
+#define DEFAULT_SERVER_PORT "9999"
+#define DEFAULT_SERVER_PATH "/org.apache.celix.discovery.shm"
+#define DEFAULT_POLL_ENDPOINTS "http://localhost:9999/org.apache.celix.discovery.shm"
+
+#define MAX_ROOTNODE_LENGTH 64
+#define MAX_LOCALNODE_LENGTH 256
+
+
+struct discovery_impl {
+ shm_watcher_t* watcher;
+};
+
+#endif /* DISCOVERY_H_ */
http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/remote_services/discovery_shm/src/discovery_shm.c
----------------------------------------------------------------------
diff --git a/bundles/remote_services/discovery_shm/src/discovery_shm.c b/bundles/remote_services/discovery_shm/src/discovery_shm.c
new file mode 100644
index 0000000..1b1170e
--- /dev/null
+++ b/bundles/remote_services/discovery_shm/src/discovery_shm.c
@@ -0,0 +1,284 @@
+/**
+ * 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.
+ */
+
+/*
+ * discovery_shm.c
+ *
+ * \date 26 Jul 2014
+ * \author <a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ * \copyright Apache License, Version 2.0
+ */
+
+
+
+#include <stdio.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <sys/types.h>
+#include <sys/sem.h>
+#include <sys/shm.h>
+
+#include <celix_errno.h>
+#include <celix_threads.h>
+
+#include "discovery_shm.h"
+
+#define DISCOVERY_SHM_MEMSIZE 262144
+#define DISCOVERY_SHM_FILENAME "/dev/null"
+#define DISCOVERY_SHM_FTOK_ID 50
+#define DISCOVERY_SEM_FILENAME "/dev/null"
+#define DISCOVERY_SEM_FTOK_ID 54
+
+struct shmEntry {
+ char key[SHM_ENTRY_MAX_KEY_LENGTH];
+ char value[SHM_ENTRY_MAX_VALUE_LENGTH];
+
+ time_t expires;
+};
+
+typedef struct shmEntry shmEntry;
+
+struct shmData {
+ shmEntry entries[SHM_DATA_MAX_ENTRIES];
+ int numOfEntries;
+ int shmId;
+
+ celix_thread_mutex_t globalLock;
+};
+
+void* shmAdress;
+
+static celix_status_t discoveryShm_removeWithIndex(shmData_pt data, int index);
+
+/* returns the ftok key to identify shared memory*/
+static key_t discoveryShm_getKey() {
+ return ftok(DISCOVERY_SHM_FILENAME, DISCOVERY_SHM_FTOK_ID);
+}
+
+/* creates a new shared memory block */
+celix_status_t discoveryShm_create(shmData_pt* data) {
+ celix_status_t status;
+
+ shmData_pt shmData = calloc(1, sizeof(*shmData));
+ key_t shmKey = discoveryShm_getKey();
+
+ if (!shmData) {
+ status = CELIX_ENOMEM;
+ } else if ((shmData->shmId = shmget(shmKey, DISCOVERY_SHM_MEMSIZE, IPC_CREAT | 0666)) < 0) {
+ status = CELIX_BUNDLE_EXCEPTION;
+ } else if ((shmAdress = shmat(shmData->shmId, 0, 0)) == (char*) -1) {
+ status = CELIX_BUNDLE_EXCEPTION;
+ } else {
+ celix_thread_mutexattr_t threadAttr;
+
+ shmData->numOfEntries = 0;
+
+ status = celixThreadMutexAttr_create(&threadAttr);
+
+#ifdef LINUX
+ if (status == CELIX_SUCCESS) {
+ // This is Linux specific
+ status = pthread_mutexattr_setrobust(&threadAttr, PTHREAD_MUTEX_ROBUST);
+ }
+#endif
+
+ if (status == CELIX_SUCCESS) {
+ status = celixThreadMutex_create(&shmData->globalLock, &threadAttr);
+ }
+
+ if (status == CELIX_SUCCESS) {
+ memcpy(shmAdress, shmData, sizeof(struct shmData));
+ (*data) = shmAdress;
+ }
+ }
+
+ free(shmData);
+
+ return status;
+}
+
+celix_status_t discoveryShm_attach(shmData_pt* data) {
+ celix_status_t status = CELIX_SUCCESS;
+ key_t shmKey = ftok(DISCOVERY_SHM_FILENAME, DISCOVERY_SHM_FTOK_ID);
+ int shmId = -1;
+
+ if ((shmId = shmget(shmKey, DISCOVERY_SHM_MEMSIZE, 0666)) < 0) {
+ status = CELIX_BUNDLE_EXCEPTION;
+ }
+
+ /* shmat has a curious return value of (void*)-1 in case of error */
+ void *mem=shmat(shmId, 0, 0);
+ if(mem==((void*)-1)){
+ status = CELIX_BUNDLE_EXCEPTION;
+ }
+ else{
+ (*data)=mem;
+ }
+
+ return status;
+}
+
+static celix_status_t discoveryShm_getwithIndex(shmData_pt data, char* key, char* value, int* index) {
+ celix_status_t status = CELIX_BUNDLE_EXCEPTION;
+ time_t currentTime = time(NULL);
+ unsigned int i;
+
+ for (i = 0; i < data->numOfEntries && status != CELIX_SUCCESS; i++) {
+ shmEntry entry = data->entries[i];
+ // check if entry is still valid
+ if (data->entries[i].expires < currentTime) {
+ discoveryShm_removeWithIndex(data, i);
+ } else if (strcmp(entry.key, key) == 0) {
+ if (value) {
+ strcpy(value, entry.value);
+ }
+ if (index) {
+ (*index) = i;
+ }
+ status = CELIX_SUCCESS;
+ }
+ }
+
+ return status;
+}
+
+celix_status_t discoveryShm_getKeys(shmData_pt data, char** keys, int* size) {
+ celix_status_t status;
+
+ status = celixThreadMutex_lock(&data->globalLock);
+
+ if (status == CELIX_SUCCESS) {
+ unsigned int i = 0;
+ for (i = 0; i < data->numOfEntries; i++) {
+ shmEntry entry = data->entries[i];
+
+ if (strlen(entry.key)>0) {
+ snprintf(keys[i], SHM_ENTRY_MAX_KEY_LENGTH, "%s", entry.key);
+ }
+ }
+
+ (*size) = i;
+
+ celixThreadMutex_unlock(&data->globalLock);
+ }
+
+ return status;
+}
+
+celix_status_t discoveryShm_set(shmData_pt data, char *key, char* value) {
+ celix_status_t status;
+ int index = -1;
+
+ if (data->numOfEntries >= SHM_DATA_MAX_ENTRIES) {
+ status = CELIX_ILLEGAL_STATE;
+ } else {
+ status = celixThreadMutex_lock(&data->globalLock);
+
+ if (status == CELIX_SUCCESS) {
+ // check if key already there
+ status = discoveryShm_getwithIndex(data, key, NULL, &index);
+ if (status != CELIX_SUCCESS) {
+ index = data->numOfEntries;
+
+ snprintf(data->entries[index].key, SHM_ENTRY_MAX_KEY_LENGTH, "%s", key);
+ data->numOfEntries++;
+
+ status = CELIX_SUCCESS;
+ }
+
+ snprintf(data->entries[index].value, SHM_ENTRY_MAX_VALUE_LENGTH, "%s", value);
+ data->entries[index].expires = (time(NULL) + SHM_ENTRY_DEFAULT_TTL);
+
+ celixThreadMutex_unlock(&data->globalLock);
+ }
+ }
+
+ return status;
+}
+
+celix_status_t discoveryShm_get(shmData_pt data, char* key, char* value) {
+ celix_status_t status;
+
+ status = celixThreadMutex_lock(&data->globalLock);
+
+ if (status == CELIX_SUCCESS) {
+ status = discoveryShm_getwithIndex(data, key, value, NULL);
+
+ celixThreadMutex_unlock(&data->globalLock);
+ }
+
+ return status;
+}
+
+static celix_status_t discoveryShm_removeWithIndex(shmData_pt data, int index) {
+ celix_status_t status = CELIX_SUCCESS;
+
+ data->numOfEntries--;
+ if (index < data->numOfEntries) {
+ memcpy((void*) &data->entries[index], (void*) &data->entries[index + 1], ((data->numOfEntries - index) * sizeof(struct shmEntry)));
+ }
+
+ return status;
+}
+
+celix_status_t discoveryShm_remove(shmData_pt data, char* key) {
+ celix_status_t status;
+ int index = -1;
+
+ status = celixThreadMutex_lock(&data->globalLock);
+
+ if (status == CELIX_SUCCESS) {
+ status = discoveryShm_getwithIndex(data, key, NULL, &index);
+
+ if (status == CELIX_SUCCESS) {
+ status = discoveryShm_removeWithIndex(data, index);
+ }
+
+ celixThreadMutex_unlock(&data->globalLock);
+ }
+
+ return status;
+}
+
+celix_status_t discoveryShm_detach(shmData_pt data) {
+ celix_status_t status = CELIX_BUNDLE_EXCEPTION;
+
+ if (data->numOfEntries == 0) {
+ status = discoveryShm_destroy(data);
+ }
+ else if (shmdt(shmAdress) == 0) {
+ status = CELIX_SUCCESS;
+ }
+
+ return status;
+}
+
+celix_status_t discoveryShm_destroy(shmData_pt data) {
+ celix_status_t status = CELIX_BUNDLE_EXCEPTION;
+
+ if (shmctl(data->shmId, IPC_RMID, 0) == 0) {
+ status = CELIX_SUCCESS;
+ }
+
+ return status;
+
+}
http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/remote_services/discovery_shm/src/discovery_shm.h
----------------------------------------------------------------------
diff --git a/bundles/remote_services/discovery_shm/src/discovery_shm.h b/bundles/remote_services/discovery_shm/src/discovery_shm.h
new file mode 100644
index 0000000..9c4593b
--- /dev/null
+++ b/bundles/remote_services/discovery_shm/src/discovery_shm.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.
+ */
+
+/*
+ * shm.h
+ *
+ * \date 26 Jul 2014
+ * \author <a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ * \copyright Apache License, Version 2.0
+ */
+
+
+
+#ifndef _DISCOVERY_SHM_H_
+#define _DISCOVERY_SHM_H_
+
+#include <celix_errno.h>
+
+#define SHM_ENTRY_MAX_KEY_LENGTH 256
+#define SHM_ENTRY_MAX_VALUE_LENGTH 256
+
+// defines the time-to-live in seconds
+#define SHM_ENTRY_DEFAULT_TTL 60
+
+// we currently support 64 separate discovery instances
+#define SHM_DATA_MAX_ENTRIES 64
+
+typedef struct shmData* shmData_pt;
+
+/* creates a new shared memory block */
+celix_status_t discoveryShm_create(shmData_pt* data);
+celix_status_t discoveryShm_attach(shmData_pt* data);
+celix_status_t discoveryShm_set(shmData_pt data, char *key, char* value);
+celix_status_t discoveryShm_get(shmData_pt data, char* key, char* value);
+celix_status_t discoveryShm_getKeys(shmData_pt data, char** keys, int* size);
+celix_status_t discoveryShm_remove(shmData_pt data, char* key);
+celix_status_t discoveryShm_detach(shmData_pt data);
+celix_status_t discoveryShm_destroy(shmData_pt data);
+
+#endif
http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/remote_services/discovery_shm/src/discovery_shmWatcher.c
----------------------------------------------------------------------
diff --git a/bundles/remote_services/discovery_shm/src/discovery_shmWatcher.c b/bundles/remote_services/discovery_shm/src/discovery_shmWatcher.c
new file mode 100644
index 0000000..ef7df71
--- /dev/null
+++ b/bundles/remote_services/discovery_shm/src/discovery_shmWatcher.c
@@ -0,0 +1,255 @@
+/**
+ * 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.
+ */
+/*
+ * discovery_shmWatcher.c
+ *
+ * \date 16 Sep 2014
+ * \author <a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ * \copyright Apache License, Version 2.0
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+
+
+#include "celix_log.h"
+#include "constants.h"
+#include "discovery_impl.h"
+
+#include "discovery_shm.h"
+#include "discovery_shmWatcher.h"
+
+#include "endpoint_discovery_poller.h"
+
+#define DEFAULT_SERVER_IP "127.0.0.1"
+#define DEFAULT_SERVER_PORT "9999"
+#define DEFAULT_SERVER_PATH "/org.apache.celix.discovery.shm"
+#define DEFAULT_POLL_ENDPOINTS "http://localhost:9999/org.apache.celix.discovery.shm"
+
+#define MAX_ROOTNODE_LENGTH 64
+#define MAX_LOCALNODE_LENGTH 256
+
+
+struct shm_watcher {
+ shmData_pt shmData;
+ celix_thread_t watcherThread;
+ celix_thread_mutex_t watcherLock;
+
+ volatile bool running;
+};
+
+// note that the rootNode shouldn't have a leading slash
+static celix_status_t discoveryShmWatcher_getRootPath(char* rootNode) {
+ celix_status_t status = CELIX_SUCCESS;
+
+ strcpy(rootNode, "discovery");
+
+ return status;
+}
+
+static celix_status_t discoveryShmWatcher_getLocalNodePath(bundle_context_pt context, char* localNodePath) {
+ celix_status_t status;
+ char rootPath[MAX_ROOTNODE_LENGTH];
+ const char* uuid = NULL;
+
+ status = discoveryShmWatcher_getRootPath(&rootPath[0]);
+
+ if (status == CELIX_SUCCESS) {
+ status = bundleContext_getProperty(context, OSGI_FRAMEWORK_FRAMEWORK_UUID, &uuid);
+ }
+
+ if (status == CELIX_SUCCESS) {
+ if (rootPath[strlen(&rootPath[0]) - 1] == '/') {
+ snprintf(localNodePath, MAX_LOCALNODE_LENGTH, "%s%s", &rootPath[0], uuid);
+ } else {
+ snprintf(localNodePath, MAX_LOCALNODE_LENGTH, "%s/%s", &rootPath[0], uuid);
+ }
+ }
+
+ return status;
+}
+
+/* retrieves all endpoints from shm and syncs them with the ones already available */
+static celix_status_t discoveryShmWatcher_syncEndpoints(discovery_pt discovery) {
+ celix_status_t status = CELIX_SUCCESS;
+ shm_watcher_pt watcher = discovery->pImpl->watcher;
+ char** shmKeyArr = calloc(SHM_DATA_MAX_ENTRIES, sizeof(*shmKeyArr));
+ array_list_pt registeredKeyArr = NULL;
+
+ int i, j, shmSize;
+
+ for (i = 0; i < SHM_DATA_MAX_ENTRIES; i++) {
+ shmKeyArr[i] = calloc(SHM_ENTRY_MAX_KEY_LENGTH, sizeof(*shmKeyArr[i]));
+ }
+
+ arrayList_create(®isteredKeyArr);
+
+ // get all urls available in shm
+ discoveryShm_getKeys(watcher->shmData, shmKeyArr, &shmSize);
+
+ // get all locally registered endpoints
+ endpointDiscoveryPoller_getDiscoveryEndpoints(discovery->poller, registeredKeyArr);
+
+ // add discovery points which are in shm, but not local yet
+ for (i = 0; i < shmSize; i++) {
+ char url[SHM_ENTRY_MAX_VALUE_LENGTH];
+
+ if (discoveryShm_get(watcher->shmData, shmKeyArr[i], &url[0]) == CELIX_SUCCESS) {
+ bool elementFound = false;
+
+ for (j = 0; j < arrayList_size(registeredKeyArr) && elementFound == false; j++) {
+
+ if (strcmp(url, (char*) arrayList_get(registeredKeyArr, j)) == 0) {
+ free(arrayList_remove(registeredKeyArr, j));
+ elementFound = true;
+ }
+ }
+
+ if (elementFound == false) {
+ endpointDiscoveryPoller_addDiscoveryEndpoint(discovery->poller, url);
+ }
+ }
+ }
+
+ // remove those which are not in shm
+ for (i = 0; i < arrayList_size(registeredKeyArr); i++) {
+ char* regUrl = arrayList_get(registeredKeyArr, i);
+
+ if (regUrl != NULL) {
+ endpointDiscoveryPoller_removeDiscoveryEndpoint(discovery->poller, regUrl);
+ }
+ }
+
+ for (i = 0; i < SHM_DATA_MAX_ENTRIES; i++) {
+ free(shmKeyArr[i]);
+ }
+
+ free(shmKeyArr);
+
+ for (j = 0; j < arrayList_size(registeredKeyArr); j++) {
+ free(arrayList_get(registeredKeyArr, j));
+ }
+
+ arrayList_destroy(registeredKeyArr);
+
+ return status;
+}
+
+static void* discoveryShmWatcher_run(void* data) {
+ discovery_pt discovery = (discovery_pt) data;
+ shm_watcher_pt watcher = discovery->pImpl->watcher;
+ char localNodePath[MAX_LOCALNODE_LENGTH];
+ char url[MAX_LOCALNODE_LENGTH];
+
+ if (discoveryShmWatcher_getLocalNodePath(discovery->context, &localNodePath[0]) != CELIX_SUCCESS) {
+ logHelper_log(discovery->loghelper, OSGI_LOGSERVICE_WARNING, "Cannot retrieve local discovery path.");
+ }
+
+ if (endpointDiscoveryServer_getUrl(discovery->server, &url[0]) != CELIX_SUCCESS) {
+ snprintf(url, MAX_LOCALNODE_LENGTH, "http://%s:%s/%s", DEFAULT_SERVER_IP, DEFAULT_SERVER_PORT, DEFAULT_SERVER_PATH);
+ }
+
+ while (watcher->running) {
+ // register own framework
+ if (discoveryShm_set(watcher->shmData, localNodePath, url) != CELIX_SUCCESS) {
+ logHelper_log(discovery->loghelper, OSGI_LOGSERVICE_WARNING, "Cannot set local discovery registration.");
+ }
+
+ discoveryShmWatcher_syncEndpoints(discovery);
+ sleep(5);
+ }
+
+ return NULL;
+}
+
+celix_status_t discoveryShmWatcher_create(discovery_pt discovery) {
+ celix_status_t status = CELIX_SUCCESS;
+ shm_watcher_pt watcher = NULL;
+
+ watcher = calloc(1, sizeof(*watcher));
+
+ if (!watcher) {
+ status = CELIX_ENOMEM;
+ } else {
+ status = discoveryShm_attach(&(watcher->shmData));
+
+ if (status != CELIX_SUCCESS) {
+ logHelper_log(discovery->loghelper, OSGI_LOGSERVICE_DEBUG, "Attaching to Shared Memory Failed. Trying to create.");
+
+ status = discoveryShm_create(&(watcher->shmData));
+
+ if (status != CELIX_SUCCESS) {
+ logHelper_log(discovery->loghelper, OSGI_LOGSERVICE_ERROR, "Failed to create Shared Memory Segment.");
+ }
+ }
+
+ if (status == CELIX_SUCCESS) {
+ discovery->pImpl->watcher = watcher;
+ }
+ else{
+ discovery->pImpl->watcher = NULL;
+ free(watcher);
+ }
+
+ }
+
+ if (status == CELIX_SUCCESS) {
+ status += celixThreadMutex_create(&watcher->watcherLock, NULL);
+ status += celixThreadMutex_lock(&watcher->watcherLock);
+ watcher->running = true;
+ status += celixThread_create(&watcher->watcherThread, NULL, discoveryShmWatcher_run, discovery);
+ status += celixThreadMutex_unlock(&watcher->watcherLock);
+ }
+
+ return status;
+}
+
+celix_status_t discoveryShmWatcher_destroy(discovery_pt discovery) {
+ celix_status_t status;
+ shm_watcher_pt watcher = discovery->pImpl->watcher;
+ char localNodePath[MAX_LOCALNODE_LENGTH];
+
+ celixThreadMutex_lock(&watcher->watcherLock);
+ watcher->running = false;
+ celixThreadMutex_unlock(&watcher->watcherLock);
+
+ celixThread_join(watcher->watcherThread, NULL);
+
+ // remove own framework
+ status = discoveryShmWatcher_getLocalNodePath(discovery->context, &localNodePath[0]);
+
+ if (status == CELIX_SUCCESS) {
+ status = discoveryShm_remove(watcher->shmData, localNodePath);
+ }
+
+ if (status == CELIX_SUCCESS) {
+ discoveryShm_detach(watcher->shmData);
+ free(watcher);
+ }
+ else {
+ logHelper_log(discovery->loghelper, OSGI_LOGSERVICE_WARNING, "Cannot remove local discovery registration.");
+ }
+
+
+ return status;
+}
+
http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/remote_services/discovery_shm/src/discovery_shmWatcher.h
----------------------------------------------------------------------
diff --git a/bundles/remote_services/discovery_shm/src/discovery_shmWatcher.h b/bundles/remote_services/discovery_shm/src/discovery_shmWatcher.h
new file mode 100644
index 0000000..4e7e1d5
--- /dev/null
+++ b/bundles/remote_services/discovery_shm/src/discovery_shmWatcher.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.
+ */
+/*
+ * shm_watcher.h
+ *
+ * \date 30 Sep 2014
+ * \author <a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ * \copyright Apache License, Version 2.0
+ */
+
+#ifndef DISCOVERY_SHM_WATCHER_H_
+#define DISCOVERY_SHM_WATCHER_H_
+
+#include "celix_errno.h"
+#include "discovery.h"
+#include "endpoint_discovery_poller.h"
+
+typedef struct shm_watcher shm_watcher_t;
+typedef struct shm_watcher *shm_watcher_pt;
+
+celix_status_t discoveryShmWatcher_create(discovery_pt discovery);
+celix_status_t discoveryShmWatcher_destroy(discovery_pt discovery);
+
+
+#endif /* DISCOVERY_SHM_WATCHER_H_ */
http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/remote_services/examples/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/bundles/remote_services/examples/CMakeLists.txt b/bundles/remote_services/examples/CMakeLists.txt
new file mode 100644
index 0000000..0f8e7a9
--- /dev/null
+++ b/bundles/remote_services/examples/CMakeLists.txt
@@ -0,0 +1,62 @@
+# 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(RSA_EXAMPLES "Option to enable building the RSA examples" ON DEPS LAUNCHER shell_tui log_writer RSA_TOPOLOGY_MANAGER)
+if (RSA_EXAMPLES)
+ add_subdirectory(calculator_api)
+ add_subdirectory(calculator_service)
+ add_subdirectory(calculator_shell)
+
+
+# TODO refactor shm remote service admin to use dfi
+# if (BUILD_RSA_REMOTE_SERVICE_ADMIN_SHM AND BUILD_RSA_DISCOVERY_SHM)
+# add_celix_container(remote-services-shm
+# NAME "server"
+# GROUP "remote-services/remote-services-shm"
+# BUNDLES discovery_shm topology_manager remote_service_admin_shm calculator shell shell_tui log_service log_writer
+# )
+# celix_container_bundles_dir(remote-services-shm DIR_NAME "endpoints"
+# BUNDLES org.apache.celix.calc.api.Calculator_endpoint
+# )
+#
+# add_celix_container(remote-services-shm-client
+# NAME "client"
+# GROUP "remote-services/remote-services-shm"
+# BUNDLES topology_manager remote_service_admin_shm shell shell_tui log_service log_writer calculator_shell discovery_shm
+# )
+# celix_container_bundles_dir(remote-services-shm-client DIR_NAME "endpoints"
+# BUNDLES org.apache.celix.calc.api.Calculator_proxy
+# )
+# endif ()
+
+
+ if (BUILD_RSA_DISCOVERY_ETCD AND BUILD_RSA_REMOTE_SERVICE_ADMIN_DFI)
+ add_celix_container(remote-services-dfi
+ NAME "server"
+ GROUP "remote-services/remote-services-dfi"
+ BUNDLES Celix::rsa_discovery_etcd Celix::rsa_topology_manager Celix::rsa_dfi calculator Celix::shell Celix::shell_tui Celix::log_service Celix::log_writer_stdout
+ )
+
+ add_celix_container("remote-services-dfi-client"
+ NAME "client"
+ GROUP "remote-services/remote-services-dfi"
+ BUNDLES Celix::rsa_topology_manager Celix::rsa_dfi Celix::shell Celix::shell_tui Celix::log_service Celix::log_writer_stdout calculator_shell Celix::rsa_discovery_etcd
+ )
+ endif ()
+endif (RSA_EXAMPLES)
+
+
http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/remote_services/examples/calculator_api/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/bundles/remote_services/examples/calculator_api/CMakeLists.txt b/bundles/remote_services/examples/calculator_api/CMakeLists.txt
new file mode 100644
index 0000000..76acfa7
--- /dev/null
+++ b/bundles/remote_services/examples/calculator_api/CMakeLists.txt
@@ -0,0 +1,22 @@
+# 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_library(calculator_api INTERFACE)
+target_include_directories(calculator_api INTERFACE include)
+set_target_properties(calculator_api PROPERTIES
+ "INTERFACE_CALCULATOR_DESCRIPTOR"
+ "${CMAKE_CURRENT_LIST_DIR}/include/org.apache.celix.calc.api.Calculator2.descriptor")
\ No newline at end of file