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:34 UTC

[26/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/topology_manager/tms_tst/tms_tests.cpp
----------------------------------------------------------------------
diff --git a/bundles/remote_services/topology_manager/tms_tst/tms_tests.cpp b/bundles/remote_services/topology_manager/tms_tst/tms_tests.cpp
new file mode 100644
index 0000000..0bbd4f0
--- /dev/null
+++ b/bundles/remote_services/topology_manager/tms_tst/tms_tests.cpp
@@ -0,0 +1,736 @@
+/**
+ *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.
+ */
+/*
+ * topology_manager_scoped_test.cpp
+ *
+ *  \date       Feb 11, 2013
+ *  \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 "CppUTest/TestHarness.h"
+#include "CppUTest/TestHarness_c.h"
+#include "CppUTest/CommandLineTestRunner.h"
+#include "CppUTestExt/MockSupport.h"
+
+extern "C" {
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <jansson.h>
+
+#include "celix_launcher.h"
+#include "constants.h"
+#include "endpoint_description.h"
+#include "framework.h"
+#include "topology_manager.h"
+#include "calculator_service.h"
+#include "tm_scope.h"
+#include "scope.h"
+#include "remote_service_admin.h"
+#include "remote_constants.h"
+#include "disc_mock_service.h"
+#include "tst_service.h"
+
+#define JSON_EXPORT_SERVICES  "exportServices"
+#define JSON_IMPORT_SERVICES  "importServices"
+
+#define JSON_SERVICE_NAME     "filter"
+#define JSON_SERVICE_ZONE     "zone"
+#define JSON_SERVICE_KEY1     "key1"
+#define JSON_SERVICE_KEY2     "key2"
+
+    static framework_pt framework = NULL;
+    static bundle_context_pt context = NULL;
+
+    static service_reference_pt scopeServiceRef = NULL;
+    static tm_scope_service_pt tmScopeService = NULL;
+
+    static service_reference_pt calcRef = NULL;
+    static calculator_service_pt calc = NULL;
+
+    static service_reference_pt rsaRef = NULL;
+    static remote_service_admin_service_pt rsa = NULL;
+
+    static service_reference_pt discRef = NULL;
+    static disc_mock_service_pt discMock = NULL;
+
+    static service_reference_pt testRef = NULL;
+    static tst_service_pt testImport = NULL;
+
+    static service_reference_pt eplRef = NULL;
+    static endpoint_listener_pt eplService = NULL; // actually this is the topology manager
+
+
+    static void setupFm(void) {
+        int rc = 0;
+        rc = celixLauncher_launch("config.properties", &framework);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+
+        bundle_pt bundle = NULL;
+        rc = framework_getFrameworkBundle(framework, &bundle);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+
+        rc = bundle_getContext(bundle, &context);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+
+        rc = bundleContext_getServiceReference(context, (char *)OSGI_RSA_REMOTE_SERVICE_ADMIN, &rsaRef);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+        CHECK(rsaRef != NULL);
+
+        rc = bundleContext_getService(context, rsaRef, (void **)&rsa);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+
+        rc = bundleContext_getServiceReference(context, (char *)TOPOLOGYMANAGER_SCOPE_SERVICE, &scopeServiceRef);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+        CHECK(scopeServiceRef != NULL);
+
+        rc = bundleContext_getService(context, scopeServiceRef, (void **)&tmScopeService);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+
+        rc = bundleContext_getServiceReference(context, (char *)CALCULATOR2_SERVICE, &calcRef);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+        CHECK(calcRef != NULL);
+
+        rc = bundleContext_getService(context, calcRef, (void **)&calc);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+
+        rc = bundleContext_getServiceReference(context, (char *)DISC_MOCK_SERVICE_NAME, &discRef);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+        CHECK(discRef != NULL);
+
+        rc = bundleContext_getService(context, discRef, (void **)&discMock);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+    }
+
+    static void teardownFm(void) {
+        int rc = 0;
+
+        rc = bundleContext_ungetService(context, scopeServiceRef, NULL);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+        rc = bundleContext_ungetServiceReference(context,scopeServiceRef);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+
+        rc = bundleContext_ungetService(context, calcRef, NULL);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+        rc = bundleContext_ungetServiceReference(context,calcRef);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+
+        rc = bundleContext_ungetService(context, rsaRef, NULL);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+        rc = bundleContext_ungetServiceReference(context,rsaRef);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+
+        rc = bundleContext_ungetService(context, discRef, NULL);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+        rc = bundleContext_ungetServiceReference(context,discRef);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+
+        celixLauncher_stop(framework);
+        celixLauncher_waitForShutdown(framework);
+        celixLauncher_destroy(framework);
+
+        scopeServiceRef = NULL;
+        tmScopeService = NULL;
+        calcRef = NULL;
+        calc = NULL;
+
+        rsaRef = NULL;
+        rsa = NULL;
+        discRef = NULL;
+        discMock = NULL;
+
+        testRef = NULL;
+        testImport = NULL;
+
+        eplRef = NULL;
+        eplService = NULL;
+
+        context = NULL;
+        framework = NULL;
+    }
+
+    static void setupFmImport(void) {
+        int rc = 0;
+        rc = celixLauncher_launch("config_import.properties", &framework);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+
+        bundle_pt bundle = NULL;
+        rc = framework_getFrameworkBundle(framework, &bundle);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+
+        rc = bundle_getContext(bundle, &context);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+
+        rc = bundleContext_getServiceReference(context, (char *)OSGI_RSA_REMOTE_SERVICE_ADMIN, &rsaRef);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+        CHECK(rsaRef != NULL);
+
+        rc = bundleContext_getService(context, rsaRef, (void **)&rsa);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+
+        rc = bundleContext_getServiceReference(context, (char *)TOPOLOGYMANAGER_SCOPE_SERVICE, &scopeServiceRef);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+        CHECK(scopeServiceRef != NULL);
+
+        rc = bundleContext_getService(context, scopeServiceRef, (void **)&tmScopeService);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+
+        rc = bundleContext_getServiceReference(context, (char *)TST_SERVICE_NAME, &testRef);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+        CHECK(testRef != NULL);
+
+        rc = bundleContext_getService(context, testRef, (void **)&testImport);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+
+        rc = bundleContext_getServiceReference(context, (char*)OSGI_ENDPOINT_LISTENER_SERVICE, &eplRef);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+        CHECK(eplRef != NULL);
+
+        rc = bundleContext_getService(context, eplRef, (void **)&eplService);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+    }
+
+    static void teardownFmImport(void) {
+        int rc = 0;
+
+        rc = bundleContext_ungetService(context, rsaRef, NULL);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+        rc = bundleContext_ungetServiceReference(context,rsaRef);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+
+        rc = bundleContext_ungetService(context, scopeServiceRef, NULL);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+        rc = bundleContext_ungetServiceReference(context,scopeServiceRef);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+
+        rc = bundleContext_ungetService(context, testRef, NULL);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+        rc = bundleContext_ungetServiceReference(context,testRef);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+
+        rc = bundleContext_ungetService(context, eplRef, NULL);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+        rc = bundleContext_ungetServiceReference(context,eplRef);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+
+        celixLauncher_stop(framework);
+        celixLauncher_waitForShutdown(framework);
+        celixLauncher_destroy(framework);
+
+        scopeServiceRef = NULL;
+        tmScopeService = NULL;
+        calcRef = NULL;
+        calc = NULL;
+
+        rsaRef = NULL;
+        rsa = NULL;
+        discRef = NULL;
+        discMock = NULL;
+
+        testRef = NULL;
+        testImport = NULL;
+
+        eplRef = NULL;
+        eplService = NULL;
+
+        context = NULL;
+        framework = NULL;
+    }
+
+
+    /// \TEST_CASE_ID{1}
+    /// \TEST_CASE_TITLE{Test register scope service}
+    /// \TEST_CASE_REQ{REQ-1}
+    /// \TEST_CASE_DESC Checks if 3 bundles are installed after the framework setup
+    static void testBundles(void) {
+    	printf("Begin: %s\n", __func__);
+            array_list_pt bundles = NULL;
+
+            int rc = bundleContext_getBundles(context, &bundles);
+            CHECK_EQUAL(0, rc);
+            CHECK_EQUAL(5, arrayList_size(bundles)); //framework, scopeService & calc & rsa
+
+            /*
+            int size = arrayList_size(bundles);
+            int i;
+            for (i = 0; i < size; i += 1) {
+                bundle_pt bundle = NULL;
+                module_pt module = NULL;
+                char *name = NULL;
+
+                bundle = (bundle_pt) arrayList_get(bundles, i);
+                bundle_getCurrentModule(bundle, &module);
+                module_getSymbolicName(module, &name);
+                printf("got bundle with symbolic name '%s'", name);
+            }*/
+
+            arrayList_destroy(bundles);
+        	printf("End: %s\n", __func__);
+    }
+
+    static void scopeInit(const char *fileName, int *nr_exported, int *nr_imported)
+    {
+    	celix_status_t	status = CELIX_SUCCESS;
+    	celix_status_t  added;
+
+        json_t *js_root;
+        json_error_t error;
+        properties_pt properties;
+
+        *nr_exported = 0;
+        *nr_imported = 0;
+        js_root = json_load_file(fileName, 0, &error);
+        if (js_root != NULL)
+        {
+            json_t *js_exportServices = json_object_get(js_root, JSON_EXPORT_SERVICES);
+            json_t *js_importServices = json_object_get(js_root, JSON_IMPORT_SERVICES);
+
+            if (js_exportServices != NULL)  {
+                 if (json_is_array(js_exportServices)) {
+                     int i = 0;
+                     int size = json_array_size(js_exportServices);
+
+                     for (; i < size; ++i) {
+                         json_t* js_service = json_array_get(js_exportServices, i);
+
+                         if (json_is_object(js_service)) {
+                        	 json_t* js_filter = json_object_get(js_service, JSON_SERVICE_NAME);
+                        	 json_t* js_serviceZone = json_object_get(js_service, JSON_SERVICE_ZONE);
+                        	 json_t* js_key1 = json_object_get(js_service, JSON_SERVICE_KEY1);
+                        	 json_t* js_key2 = json_object_get(js_service, JSON_SERVICE_KEY2);
+
+                             properties=properties_create();
+                             if (js_serviceZone != NULL) {
+                        	     properties_set(properties, (char*)JSON_SERVICE_ZONE,
+                        		    	                    (char*)json_string_value(js_serviceZone));
+			     }
+                             if (js_key1 != NULL) {
+                        	     properties_set(properties, (char*)JSON_SERVICE_KEY1,
+                        		    	 	 	  	 	    (char*)json_string_value(js_key1));
+			     }
+                             if (js_key2 != NULL) {
+                                 properties_set(properties, (char*)JSON_SERVICE_KEY2,
+                                    	 	 	  	 	    (char*)json_string_value(js_key2));
+			     }
+
+                        	 added = tmScopeService->addExportScope(tmScopeService->handle, (char*)json_string_value(js_filter), properties);
+                             if (added == CELIX_SUCCESS) {
+                            	 (*nr_exported)++;
+                             }
+                         }
+                     }
+                 }
+             }
+
+             if (js_importServices != NULL)  {
+                 if (json_is_array(js_importServices)) {
+                     int i = 0;
+                     int size = json_array_size(js_importServices);
+
+                     for (; i < size; ++i) {
+                         json_t* js_service = json_array_get(js_importServices, i);
+
+                         if (json_is_object(js_service)) {
+                        	 json_t* js_filter = json_object_get(js_service, JSON_SERVICE_NAME);
+
+                        	 added = tmScopeService->addImportScope(tmScopeService->handle, (char*)json_string_value(js_filter));
+                             if (added == CELIX_SUCCESS) {
+                            	 (*nr_imported)++;
+                             }
+                         }
+                     }
+                 }
+             }
+
+
+        	json_decref(js_root);
+        }
+        else
+        {
+        	printf("File error: %s\n", error.text);
+        	printf("File error: source %s\n", error.source);
+        	printf("File error: line %d position %d\n", error.line, error.position);
+        	status = CELIX_FILE_IO_EXCEPTION;
+        }
+        CHECK_EQUAL(CELIX_SUCCESS, status);
+    }
+
+    /// \TEST_CASE_ID{2}
+    /// \TEST_CASE_TITLE{Test scope initialisation}
+    /// \TEST_CASE_REQ{REQ-2}
+    /// \TEST_CASE_DESC Checks if scopes can be added, but not twice
+    static void testScope(void) {
+    	int nr_exported;
+    	int nr_imported;
+    	array_list_pt epList;
+
+    	printf("\nBegin: %s\n", __func__);
+        scopeInit("scope.json", &nr_exported, &nr_imported);
+        CHECK_EQUAL(1, nr_exported);
+        CHECK_EQUAL(0, nr_imported);
+
+        discMock->getEPDescriptors(discMock->handle, &epList);
+        // We export two services: Calculator and Calculator2, but only 1 has DFI bundle info
+        CHECK_EQUAL(1, arrayList_size(epList));
+        for (unsigned int i = 0; i < arrayList_size(epList); i++) {
+        	endpoint_description_pt ep = (endpoint_description_pt) arrayList_get(epList, i);
+        	properties_pt props = ep->properties;
+        	hash_map_entry_pt entry = hashMap_getEntry(props, (void*)"key2");
+        	char* value = (char*) hashMapEntry_getValue(entry);
+        	STRCMP_EQUAL("inaetics", value);
+        	/*
+        	printf("Service: %s ", ep->service);
+        	hash_map_iterator_pt iter = hashMapIterator_create(props);
+        	while (hashMapIterator_hasNext(iter)) {
+        		hash_map_entry_pt entry = hashMapIterator_nextEntry(iter);
+        		printf("%s - %s\n", (char*)hashMapEntry_getKey(entry),
+        						   (char*)hashMapEntry_getValue(entry));
+        	}
+        	printf("\n");
+        	hashMapIterator_destroy(iter);
+        	*/
+        }
+        printf("End: %s\n", __func__);
+    }
+
+    /// \TEST_CASE_ID{3}
+    /// \TEST_CASE_TITLE{Test scope initialisation}
+    /// \TEST_CASE_REQ{REQ-3}
+    /// \TEST_CASE_DESC Checks if scopes can be added, but not twice
+    static void testScope2(void) {
+    	int nr_exported;
+    	int nr_imported;
+    	array_list_pt epList;
+    	printf("\nBegin: %s\n", __func__);
+        scopeInit("scope2.json", &nr_exported, &nr_imported);
+        CHECK_EQUAL(2, nr_exported);
+        CHECK_EQUAL(1, nr_imported);
+        discMock->getEPDescriptors(discMock->handle, &epList);
+        // We export two services: Calculator and Calculator2, but only 1 has DFI bundle info
+        CHECK_EQUAL(1, arrayList_size(epList));
+        for (unsigned int i = 0; i < arrayList_size(epList); i++) {
+        	endpoint_description_pt ep = (endpoint_description_pt) arrayList_get(epList, i);
+        	properties_pt props = ep->properties;
+        	hash_map_entry_pt entry = hashMap_getEntry(props, (void*)"key2");
+        	char* value = (char*) hashMapEntry_getValue(entry);
+        	STRCMP_EQUAL("inaetics", value);
+        }
+        printf("End: %s\n", __func__);
+    }
+
+    /// \TEST_CASE_ID{4}
+    /// \TEST_CASE_TITLE{Test scope initialisation}
+    /// \TEST_CASE_REQ{REQ-4}
+    /// \TEST_CASE_DESC Checks if scopes can be added, but not twice
+    static void testScope3(void) {
+    	int nr_exported;
+    	int nr_imported;
+    	array_list_pt epList;
+    	printf("\nBegin: %s\n", __func__);
+        scopeInit("scope3.json", &nr_exported, &nr_imported);
+        CHECK_EQUAL(2, nr_exported);
+        discMock->getEPDescriptors(discMock->handle, &epList);
+        // We export two services: Calculator and Calculator2, but only 1 has DFI bundle info
+        CHECK_EQUAL(1, arrayList_size(epList));
+        for (unsigned int i = 0; i < arrayList_size(epList); i++) {
+        	endpoint_description_pt ep = (endpoint_description_pt) arrayList_get(epList, i);
+        	properties_pt props = ep->properties;
+        	hash_map_entry_pt entry = hashMap_getEntry(props, (void *)"key2");
+        	char* value = (char*) hashMapEntry_getValue(entry);
+        	STRCMP_EQUAL("inaetics", value);
+        }
+        printf("End: %s\n", __func__);
+    }
+
+    /// \TEST_CASE_ID{5}
+    /// \TEST_CASE_TITLE{Test scope initialisation}
+    /// \TEST_CASE_REQ{REQ-5}
+    /// \TEST_CASE_DESC Invalid input file, two partly matching filters with same key name
+    /*
+    static void testScope4(void) {
+    	int nr_exported;
+    	int nr_imported;
+    	array_list_pt epList;
+    	printf("\nBegin: %s\n", __func__);
+        scopeInit("scope4.json", &nr_exported, &nr_imported);
+        CHECK_EQUAL(2, nr_exported);
+        discMock->getEPDescriptors(discMock->handle, &epList);
+        // We export two services: Calculator and Calculator2, but only 1 has DFI bundle info
+        CHECK_EQUAL(1, arrayList_size(epList));
+        for (unsigned int i = 0; i < arrayList_size(epList); i++) {
+        	endpoint_description_pt ep = (endpoint_description_pt) arrayList_get(epList, i);
+        	properties_pt props = ep->properties;
+        	hash_map_entry_pt entry = hashMap_getEntry(props, (void*)"zone");
+        	char* value = (char*) hashMapEntry_getValue(entry);
+        	STRCMP_EQUAL("inaetics", value);
+        	CHECK_TRUE((entry == NULL));
+        }
+        printf("End: %s\n", __func__);
+    }*/
+
+
+    /// \TEST_CASE_ID{6}
+    /// \TEST_CASE_TITLE{Test import scope}
+    /// \TEST_CASE_REQ{REQ-3}
+    /// \TEST_CASE_DESC Checks if import succeeds if there is no import scope defined
+    static void testImportScope(void) {
+    	int nr_exported;
+    	int nr_imported;
+    	printf("\nBegin: %s\n", __func__);
+
+    	scopeInit("scope.json", &nr_exported, &nr_imported);
+    	CHECK_EQUAL(0, nr_imported);
+        int rc = 0;
+
+        endpoint_description_pt endpoint = NULL;
+
+        properties_pt props = properties_create();
+        properties_set(props, (char *)OSGI_RSA_ENDPOINT_SERVICE_ID, (char *)"42");
+        properties_set(props, (char *)OSGI_RSA_ENDPOINT_FRAMEWORK_UUID, (char *)"eec5404d-51d0-47ef-8d86-c825a8beda42");
+        properties_set(props, (char *)OSGI_RSA_ENDPOINT_ID, (char *)"eec5404d-51d0-47ef-8d86-c825a8beda42-42");
+        properties_set(props, (char *)OSGI_FRAMEWORK_OBJECTCLASS,(char *)"org.apache.celix.test.MyBundle");
+        properties_set(props, (char *)"service.version",(char *)"1.0.0"); //TODO find out standard in osgi spec
+        properties_set(props, (char *)"zone", (char *)"thales");
+
+        rc = endpointDescription_create(props, &endpoint);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+
+        rc = eplService->endpointAdded(eplService->handle, endpoint, NULL);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+
+        bool imported = testImport->IsImported(testImport);
+        CHECK_EQUAL(true, imported);
+
+        rc = eplService->endpointRemoved(eplService->handle, endpoint, NULL);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+
+        rc = endpointDescription_destroy(endpoint);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+
+        printf("*****After importService\n");
+        printf("End: %s\n", __func__);
+    }
+
+    /// \TEST_CASE_ID{7}
+    /// \TEST_CASE_TITLE{Test import scope}
+    /// \TEST_CASE_REQ{REQ-3}
+    /// \TEST_CASE_DESC Checks if import succeeds if there is a matching import scope defined
+    static void testImportScopeMatch(void) {
+        int nr_exported;
+        int nr_imported;
+        printf("\nBegin: %s\n", __func__);
+
+        scopeInit("scope2.json", &nr_exported, &nr_imported);
+        CHECK_EQUAL(1, nr_imported);
+        int rc = 0;
+
+        endpoint_description_pt endpoint = NULL;
+
+        properties_pt props = properties_create();
+        properties_set(props, (char *)OSGI_RSA_ENDPOINT_SERVICE_ID, (char *)"42");
+        properties_set(props, (char *)OSGI_RSA_ENDPOINT_FRAMEWORK_UUID, (char *)"eec5404d-51d0-47ef-8d86-c825a8beda42");
+        properties_set(props, (char *)OSGI_RSA_ENDPOINT_ID, (char *)"eec5404d-51d0-47ef-8d86-c825a8beda42-42");
+        properties_set(props, (char *)OSGI_FRAMEWORK_OBJECTCLASS,(char *)"org.apache.celix.test.MyBundle");
+        properties_set(props, (char *)"service.version",(char *)"1.0.0"); //TODO find out standard in osgi spec
+        properties_set(props, (char *)"zone", (char *)"thales");
+
+        rc = endpointDescription_create(props, &endpoint);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+
+        rc = eplService->endpointAdded(eplService->handle, endpoint, NULL);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+
+        bool imported = testImport->IsImported(testImport);
+        CHECK_EQUAL(true, imported);
+
+        rc = eplService->endpointRemoved(eplService->handle, endpoint, NULL);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+
+        rc = endpointDescription_destroy(endpoint);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+
+        printf("End: %s\n", __func__);
+    }
+
+
+    /// \TEST_CASE_ID{8}
+    /// \TEST_CASE_TITLE{Test import scope block}
+    /// \TEST_CASE_REQ{REQ-3}
+    /// \TEST_CASE_DESC Checks if import fails with non matching import scope defined
+    static void testImportScopeFail(void) {
+        int nr_exported;
+        int nr_imported;
+        printf("\nBegin: %s\n", __func__);
+
+        scopeInit("scope3.json", &nr_exported, &nr_imported);
+        CHECK_EQUAL(1, nr_imported);
+        int rc = 0;
+
+        endpoint_description_pt endpoint = NULL;
+
+        properties_pt props = properties_create();
+        properties_set(props, (char *)OSGI_RSA_ENDPOINT_SERVICE_ID, (char *)"42");
+        properties_set(props, (char *)OSGI_RSA_ENDPOINT_FRAMEWORK_UUID, (char *)"eec5404d-51d0-47ef-8d86-c825a8beda42");
+        properties_set(props, (char *)OSGI_RSA_ENDPOINT_ID, (char *)"eec5404d-51d0-47ef-8d86-c825a8beda42-42");
+        properties_set(props, (char *)OSGI_FRAMEWORK_OBJECTCLASS,(char *)"org.apache.celix.test.MyBundle");
+        properties_set(props, (char *)"service.version",(char *)"1.0.0"); //TODO find out standard in osgi spec
+        properties_set(props, (char *)"zone", (char *)"thales");
+
+        rc = endpointDescription_create(props, &endpoint);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+
+        rc = eplService->endpointAdded(eplService->handle, endpoint, NULL);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+
+        bool imported = testImport->IsImported(testImport);
+        CHECK_EQUAL(false, imported);
+
+        rc = eplService->endpointRemoved(eplService->handle, endpoint, NULL);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+
+        rc = endpointDescription_destroy(endpoint);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+
+        printf("End: %s\n", __func__);
+    }
+
+    /// \TEST_CASE_ID{8}
+    /// \TEST_CASE_TITLE{Test import scope block}
+    /// \TEST_CASE_REQ{REQ-3}
+    /// \TEST_CASE_DESC Checks if import fails with non matching import scope defined
+    static void testImportScopeMultiple(void) {
+        int nr_exported;
+        int nr_imported;
+        printf("\nBegin: %s\n", __func__);
+
+        scopeInit("scope4.json", &nr_exported, &nr_imported);
+        CHECK_EQUAL(2, nr_imported);
+        int rc = 0;
+
+        endpoint_description_pt endpoint = NULL;
+
+        properties_pt props = properties_create();
+        properties_set(props, (char *)OSGI_RSA_ENDPOINT_SERVICE_ID, (char *)"42");
+        properties_set(props, (char *)OSGI_RSA_ENDPOINT_FRAMEWORK_UUID, (char *)"eec5404d-51d0-47ef-8d86-c825a8beda42");
+        properties_set(props, (char *)OSGI_RSA_ENDPOINT_ID, (char *)"eec5404d-51d0-47ef-8d86-c825a8beda42-42");
+        properties_set(props, (char *)OSGI_FRAMEWORK_OBJECTCLASS,(char *)"org.apache.celix.test.MyBundle");
+        properties_set(props, (char *)"service.version",(char *)"1.0.0"); //TODO find out standard in osgi spec
+        properties_set(props, (char *)"zone", (char *)"thales");
+
+        rc = endpointDescription_create(props, &endpoint);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+
+        rc = eplService->endpointAdded(eplService->handle, endpoint, NULL);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+
+        bool imported = testImport->IsImported(testImport);
+        CHECK_EQUAL(true, imported);
+
+        rc = eplService->endpointRemoved(eplService->handle, endpoint, NULL);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+
+        rc = endpointDescription_destroy(endpoint);
+        CHECK_EQUAL(CELIX_SUCCESS, rc);
+
+        printf("End: %s\n", __func__);
+    }
+
+}
+
+TEST_GROUP(topology_manager_scoped_export) {
+	void setup(void) {
+		setupFm();
+	}
+
+	void teardown() {
+		teardownFm();
+	}
+};
+
+TEST_GROUP(topology_manager_scoped_import) {
+	void setup(void) {
+		setupFmImport();
+	}
+
+	void teardown() {
+		teardownFmImport();
+	}
+};
+
+// Test9
+TEST(topology_manager_scoped_import, scope_import_multiple) {
+	testImportScopeMultiple();
+
+}
+
+// Test8
+TEST(topology_manager_scoped_import, scope_import_fail) {
+	testImportScopeFail();
+
+}
+
+// Test7
+TEST(topology_manager_scoped_import, scope_import_match) {
+	testImportScopeMatch();
+
+}
+
+// Test6
+TEST(topology_manager_scoped_import, scope_import) {
+	testImportScope();
+
+}
+
+// Test5
+/*
+TODO: NYI
+TEST(topology_manager_scoped_export, scope_init4) {
+	testScope4();
+}
+*/
+
+// Test4
+TEST(topology_manager_scoped_export, scope_init3) {
+	testScope3();
+
+}
+
+// Test3
+TEST(topology_manager_scoped_export, scope_init2) {
+	testScope2();
+
+}
+
+// Test2
+TEST(topology_manager_scoped_export, scope_init) {
+	testScope();
+
+}
+
+// Test1
+TEST(topology_manager_scoped_export, init_test) {
+    testBundles();
+}

http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/shell/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/bundles/shell/CMakeLists.txt b/bundles/shell/CMakeLists.txt
new file mode 100644
index 0000000..ae2d39a
--- /dev/null
+++ b/bundles/shell/CMakeLists.txt
@@ -0,0 +1,21 @@
+# 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(shell)
+add_subdirectory(remote_shell)
+add_subdirectory(shell_bonjour)
+add_subdirectory(shell_tui)

http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/shell/remote_shell/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/bundles/shell/remote_shell/CMakeLists.txt b/bundles/shell/remote_shell/CMakeLists.txt
new file mode 100644
index 0000000..24a3080
--- /dev/null
+++ b/bundles/shell/remote_shell/CMakeLists.txt
@@ -0,0 +1,44 @@
+# 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(REMOTE_SHELL "Option to enable building the Remote Shell bundles" ON DEPS LAUNCHER SHELL_TUI)
+if (REMOTE_SHELL)
+
+    add_celix_bundle(remote_shell
+     	SYMBOLIC_NAME "apache_celix_remote_shell"
+     	VERSION "0.0.2"
+     	NAME: "Apache Celix Remote Shell"
+		SOURCES
+			src/activator
+			src/connection_listener
+			src/shell_mediator
+			src/remote_shell
+	)
+
+	target_include_directories(remote_shell PRIVATE src)
+	target_link_libraries(remote_shell PRIVATE log_helper)
+
+    include_directories("${PROJECT_SOURCE_DIR}/utils/public/include")
+    include_directories("${PROJECT_SOURCE_DIR}/log_service/public/include")
+    
+    target_link_libraries(remote_shell PRIVATE Celix::shell_api)
+
+        install_celix_bundle(remote_shell EXPORT celix COMPONENT remote_shell)
+	#Alias setup to match external usage
+	add_library(Celix::remote_shell ALIAS remote_shell)
+
+    add_celix_container("remote_shell_deploy" NAME "remote_shell"  BUNDLES Celix::shell Celix::remote_shell Celix::shell_tui log_service)
+endif (REMOTE_SHELL)

http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/shell/remote_shell/README.md
----------------------------------------------------------------------
diff --git a/bundles/shell/remote_shell/README.md b/bundles/shell/remote_shell/README.md
new file mode 100644
index 0000000..af28421
--- /dev/null
+++ b/bundles/shell/remote_shell/README.md
@@ -0,0 +1,27 @@
+<!--
+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.
+-->
+
+## Remote Shell
+
+The Celix Remote Shell implements a telnet interface for the Celix Shell.
+
+###### Properties
+    remote.shell.telnet.port              used port (default: 6666)
+    remote.shell.telnet.maxconn           amount of concurrent connections (default: 2)
+
+###### CMake option
+    BUILD_REMOTE_SHELL=ON

http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/shell/remote_shell/src/activator.c
----------------------------------------------------------------------
diff --git a/bundles/shell/remote_shell/src/activator.c b/bundles/shell/remote_shell/src/activator.c
new file mode 100644
index 0000000..541eda6
--- /dev/null
+++ b/bundles/shell/remote_shell/src/activator.c
@@ -0,0 +1,153 @@
+/**
+ *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.
+ */
+/*
+ * activator.c
+ *
+ *  \date       Nov 4, 2012
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#include <celix_errno.h>
+
+#include <stdlib.h>
+
+#include "bundle_activator.h"
+#include "bundle_context.h"
+
+#include "log_helper.h"
+#include "connection_listener.h"
+#include "shell_mediator.h"
+#include "remote_shell.h"
+
+#define REMOTE_SHELL_TELNET_PORT_PROPERTY_NAME 	"remote.shell.telnet.port"
+#define DEFAULT_REMOTE_SHELL_TELNET_PORT 		6666
+
+#define REMOTE_SHELL_TELNET_MAXCONN_PROPERTY_NAME 	"remote.shell.telnet.maxconn"
+#define DEFAULT_REMOTE_SHELL_TELNET_MAXCONN 		2
+
+struct bundle_instance {
+	log_helper_pt loghelper;
+	shell_mediator_pt shellMediator;
+	remote_shell_pt remoteShell;
+	connection_listener_pt connectionListener;
+};
+
+typedef struct bundle_instance *bundle_instance_pt;
+
+static int bundleActivator_getPort(bundle_instance_pt bi, bundle_context_pt context);
+static int bundleActivator_getMaximumConnections(bundle_instance_pt bi, bundle_context_pt context);
+static int bundleActivator_getProperty(bundle_instance_pt bi, bundle_context_pt context, char * propertyName, int defaultValue);
+
+celix_status_t bundleActivator_create(bundle_context_pt context, void **userData) {
+	celix_status_t status = CELIX_SUCCESS;
+
+	bundle_instance_pt bi = (bundle_instance_pt) calloc(1, sizeof(struct bundle_instance));
+
+	if (!bi)
+	{
+		status = CELIX_ENOMEM;
+	}
+	else if (userData != NULL) {
+		bi->shellMediator = NULL;
+		bi->remoteShell = NULL;
+		bi->connectionListener = NULL;
+
+		status = logHelper_create(context, &bi->loghelper);
+
+		(*userData) = bi;
+	} else {
+		status = CELIX_ILLEGAL_ARGUMENT;
+		free(bi);
+	}
+
+	return status;
+}
+
+celix_status_t bundleActivator_start(void * userData, bundle_context_pt context) {
+	celix_status_t status = CELIX_SUCCESS;
+	bundle_instance_pt bi = (bundle_instance_pt) userData;
+
+	int port = bundleActivator_getPort(bi, context);
+	int maxConn = bundleActivator_getMaximumConnections(bi, context);
+
+	status = logHelper_start(bi->loghelper);
+
+	status = CELIX_DO_IF(status, shellMediator_create(context, &bi->shellMediator));
+	status = CELIX_DO_IF(status, remoteShell_create(bi->shellMediator, maxConn, &bi->remoteShell));
+	status = CELIX_DO_IF(status, connectionListener_create(bi->remoteShell, port, &bi->connectionListener));
+	status = CELIX_DO_IF(status, connectionListener_start(bi->connectionListener));
+
+	return status;
+}
+
+celix_status_t bundleActivator_stop(void * userData, bundle_context_pt context) {
+	celix_status_t status = CELIX_SUCCESS;
+	bundle_instance_pt bi = (bundle_instance_pt) userData;
+
+	connectionListener_stop(bi->connectionListener);
+	shellMediator_stop(bi->shellMediator);
+	shellMediator_destroy(bi->shellMediator);
+
+	remoteShell_stopConnections(bi->remoteShell);
+
+	status = logHelper_stop(bi->loghelper);
+
+	return status;
+}
+
+celix_status_t bundleActivator_destroy(void * userData, bundle_context_pt context) {
+	celix_status_t status = CELIX_SUCCESS;
+	bundle_instance_pt bi = (bundle_instance_pt) userData;
+
+	connectionListener_destroy(bi->connectionListener);
+	status = logHelper_destroy(&bi->loghelper);
+
+	return status;
+}
+
+static int bundleActivator_getPort(bundle_instance_pt bi, bundle_context_pt context) {
+	return bundleActivator_getProperty(bi, context, REMOTE_SHELL_TELNET_PORT_PROPERTY_NAME, DEFAULT_REMOTE_SHELL_TELNET_PORT);
+}
+
+static int bundleActivator_getMaximumConnections(bundle_instance_pt bi, bundle_context_pt context) {
+	return bundleActivator_getProperty(bi, context, REMOTE_SHELL_TELNET_MAXCONN_PROPERTY_NAME, DEFAULT_REMOTE_SHELL_TELNET_MAXCONN);
+}
+
+static int bundleActivator_getProperty(bundle_instance_pt bi, bundle_context_pt context, char* propertyName, int defaultValue) {
+	const char *strValue = NULL;
+	int value;
+
+	bundleContext_getProperty(context, propertyName, &strValue);
+	if (strValue != NULL) {
+		char* endptr = (char*)strValue;
+
+		errno = 0;
+		value = strtol(strValue, &endptr, 10);
+		if (*endptr || errno != 0) {
+			logHelper_log(bi->loghelper, OSGI_LOGSERVICE_WARNING, "incorrect format for %s", propertyName);
+			value = defaultValue;
+		}
+	}
+	else {
+		value = defaultValue;
+	}
+
+	return value;
+}

http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/shell/remote_shell/src/connection_listener.c
----------------------------------------------------------------------
diff --git a/bundles/shell/remote_shell/src/connection_listener.c b/bundles/shell/remote_shell/src/connection_listener.c
new file mode 100644
index 0000000..3bef9e5
--- /dev/null
+++ b/bundles/shell/remote_shell/src/connection_listener.c
@@ -0,0 +1,221 @@
+/**
+ *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.
+ */
+/*
+ * connection_listener.c
+ *
+ *  \date       Nov 4, 2012
+ *  \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 <celix_errno.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <fcntl.h>
+
+#include "log_service.h"
+#include "log_helper.h"
+
+#include "connection_listener.h"
+
+#include "shell_mediator.h"
+#include "remote_shell.h"
+
+#define CONNECTION_LISTENER_TIMEOUT_SEC		5
+
+struct connection_listener {
+	//constant
+	int port;
+	log_helper_pt* loghelper;
+	remote_shell_pt remoteShell;
+	celix_thread_mutex_t mutex;
+
+	//protected by mutex
+	bool running;
+	celix_thread_t thread;
+	fd_set pollset;
+};
+
+static void* connection_listener_thread(void *data);
+
+celix_status_t connectionListener_create(remote_shell_pt remoteShell, int port, connection_listener_pt *instance) {
+	celix_status_t status = CELIX_SUCCESS;
+	(*instance) = calloc(1, sizeof(**instance));
+
+	if ((*instance) != NULL) {
+		(*instance)->port = port;
+		(*instance)->remoteShell = remoteShell;
+		(*instance)->running = false;
+		(*instance)->loghelper = remoteShell->loghelper;
+
+		FD_ZERO(&(*instance)-> pollset);
+
+		status = celixThreadMutex_create(&(*instance)->mutex, NULL);
+	} else {
+		status = CELIX_ENOMEM;
+	}
+	return status;
+}
+
+celix_status_t connectionListener_start(connection_listener_pt instance) {
+	celix_status_t status = CELIX_SUCCESS;
+	celixThreadMutex_lock(&instance->mutex);
+	celixThread_create(&instance->thread, NULL, connection_listener_thread, instance);
+	celixThreadMutex_unlock(&instance->mutex);
+	return status;
+}
+
+celix_status_t connectionListener_stop(connection_listener_pt instance) {
+	celix_status_t status = CELIX_SUCCESS;
+	celix_thread_t thread;
+	fd_set pollset;
+
+	instance->running = false;
+	FD_ZERO(&pollset);
+
+	logHelper_log(*instance->loghelper, OSGI_LOGSERVICE_INFO, "CONNECTION_LISTENER: Stopping thread\n");
+
+	celixThreadMutex_lock(&instance->mutex);
+	thread = instance->thread;
+
+	pollset = instance->pollset;
+	celixThreadMutex_unlock(&instance->mutex);
+
+	celixThread_join(thread, NULL);
+	return status;
+}
+
+celix_status_t connectionListener_destroy(connection_listener_pt instance) {
+	free(instance);
+
+	return CELIX_SUCCESS;
+}
+
+static void* connection_listener_thread(void *data) {
+	celix_status_t status = CELIX_BUNDLE_EXCEPTION;
+	connection_listener_pt instance = data;
+	struct timeval timeout; /* Timeout for select */
+	fd_set active_fd_set;
+	FD_ZERO(&active_fd_set);
+	int listenSocket = 0;
+	int on = 1;
+
+	struct addrinfo *result, *rp;
+	struct addrinfo hints;
+
+	memset(&hints, 0, sizeof(struct addrinfo));
+	hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
+	hints.ai_socktype = SOCK_STREAM; /* Datagram socket */
+	hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */
+	hints.ai_protocol = 0; /* Any protocol */
+	hints.ai_canonname = NULL;
+	hints.ai_addr = NULL;
+	hints.ai_next = NULL;
+
+	char portStr[10];
+	snprintf(&portStr[0], 10, "%d", instance->port);
+
+	getaddrinfo(NULL, portStr, &hints, &result);
+
+	for (rp = result; rp != NULL && status == CELIX_BUNDLE_EXCEPTION; rp = rp->ai_next) {
+
+		status = CELIX_BUNDLE_EXCEPTION;
+
+		/* Create socket */
+		listenSocket = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
+		if (listenSocket < 0) {
+			logHelper_log(*instance->loghelper, OSGI_LOGSERVICE_ERROR, "Error creating socket: %s", strerror(errno));
+		}
+		else if (setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)) < 0) {
+			logHelper_log(*instance->loghelper, OSGI_LOGSERVICE_ERROR, "cannot set socket option: %s", strerror(errno));
+		}
+		else if (bind(listenSocket, rp->ai_addr, rp->ai_addrlen) < 0) {
+			logHelper_log(*instance->loghelper, OSGI_LOGSERVICE_ERROR, "cannot bind: %s", strerror(errno));
+		}
+		else if (listen(listenSocket, 5) < 0) {
+			logHelper_log(*instance->loghelper, OSGI_LOGSERVICE_ERROR, "listen failed: %s", strerror(errno));
+		}
+		else {
+			status = CELIX_SUCCESS;
+		}
+	}
+
+	if (status == CELIX_SUCCESS) {
+
+		logHelper_log(*instance->loghelper, OSGI_LOGSERVICE_INFO, "Remote Shell accepting connections on port %d", instance->port);
+
+		celixThreadMutex_lock(&instance->mutex);
+		instance->pollset = active_fd_set;
+		celixThreadMutex_unlock(&instance->mutex);
+
+		instance->running = true;
+
+		while (status == CELIX_SUCCESS && instance->running) {
+			int selectRet = -1;
+			do {
+				timeout.tv_sec = CONNECTION_LISTENER_TIMEOUT_SEC;
+				timeout.tv_usec = 0;
+
+				FD_ZERO(&active_fd_set);
+				FD_SET(listenSocket, &active_fd_set);
+
+				selectRet = select(listenSocket + 1, &active_fd_set, NULL, NULL, &timeout);
+			} while (selectRet == -1 && errno == EINTR && instance->running == true);
+			if (selectRet < 0) {
+				logHelper_log(*instance->loghelper, OSGI_LOGSERVICE_ERROR, "select on listenSocket failed: %s", strerror(errno));
+				status = CELIX_BUNDLE_EXCEPTION;
+			}
+			else if (selectRet == 0) {
+				/* do nothing here */
+			}
+			else if (FD_ISSET(listenSocket, &active_fd_set)) {
+				int acceptedSocket = accept(listenSocket, NULL, NULL);
+
+				if (acceptedSocket < 0) {
+					logHelper_log(*instance->loghelper, OSGI_LOGSERVICE_ERROR, "REMOTE_SHELL: accept failed: %s.", strerror(errno));
+					status = CELIX_BUNDLE_EXCEPTION;
+				}
+				else {
+					logHelper_log(*instance->loghelper, OSGI_LOGSERVICE_INFO, "REMOTE_SHELL: connection established.");
+					remoteShell_addConnection(instance->remoteShell, acceptedSocket);
+				}
+			}
+			else {
+				logHelper_log(*instance->loghelper, OSGI_LOGSERVICE_DEBUG, "REMOTE_SHELL: received data on a not-expected file-descriptor?");
+			}
+		}
+	}
+
+	if (listenSocket >= 0) {
+		close(listenSocket);
+	}
+
+	freeaddrinfo(result);
+
+	return NULL;
+}
+

http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/shell/remote_shell/src/connection_listener.h
----------------------------------------------------------------------
diff --git a/bundles/shell/remote_shell/src/connection_listener.h b/bundles/shell/remote_shell/src/connection_listener.h
new file mode 100644
index 0000000..392d6ec
--- /dev/null
+++ b/bundles/shell/remote_shell/src/connection_listener.h
@@ -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.
+ */
+/*
+ * connection_listener.h
+ *
+ *  \date       Nov 4, 2012
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#ifndef connectionListener_H_
+#define connectionListener_H_
+
+#include <bundle_context.h>
+#include <celix_errno.h>
+
+#include "remote_shell.h"
+
+typedef struct connection_listener *connection_listener_pt;
+
+celix_status_t connectionListener_create(remote_shell_pt remoteShell, int port, connection_listener_pt *instance);
+celix_status_t connectionListener_destroy(connection_listener_pt instance);
+celix_status_t connectionListener_start(connection_listener_pt instance);
+celix_status_t connectionListener_stop(connection_listener_pt instance);
+
+#endif /* connectionListener_H_ */

http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/shell/remote_shell/src/remote_shell.c
----------------------------------------------------------------------
diff --git a/bundles/shell/remote_shell/src/remote_shell.c b/bundles/shell/remote_shell/src/remote_shell.c
new file mode 100644
index 0000000..8f42778
--- /dev/null
+++ b/bundles/shell/remote_shell/src/remote_shell.c
@@ -0,0 +1,242 @@
+/**
+ *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.
+ */
+/*
+ * remote_shell.c
+ *
+ *  \date       Nov 4, 2012
+ *  \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 <utils.h>
+#include <array_list.h>
+#include <sys/socket.h>
+
+#include "log_helper.h"
+
+#include "log_service.h"
+#include "remote_shell.h"
+
+#define COMMAND_BUFF_SIZE (256)
+
+#define RS_PROMPT ("-> ")
+#define RS_WELCOME ("\n---- Apache Celix Remote Shell ----\n---- Type exit to disconnect   ----\n\n-> ")
+#define RS_GOODBYE ("Goobye!\n")
+#define RS_ERROR ("Error executing command!\n")
+#define RS_MAXIMUM_CONNECTIONS_REACHED ("Maximum number of connections  reached. Disconnecting ...\n")
+
+#define CONNECTION_LISTENER_TIMEOUT_SEC		5
+
+
+
+struct connection {
+	remote_shell_pt parent;
+	FILE *socketStream;
+	fd_set pollset;
+	bool threadRunning;
+};
+
+typedef struct connection *connection_pt;
+
+static celix_status_t remoteShell_connection_print(connection_pt connection, char * text);
+static celix_status_t remoteShell_connection_execute(connection_pt connection, char *command);
+static void* remoteShell_connection_run(void *data);
+
+celix_status_t remoteShell_create(shell_mediator_pt mediator, int maximumConnections, remote_shell_pt *instance) {
+	celix_status_t status = CELIX_SUCCESS;
+	(*instance) = calloc(1, sizeof(**instance));
+	if ((*instance) != NULL) {
+		(*instance)->mediator = mediator;
+		(*instance)->maximumConnections = maximumConnections;
+		(*instance)->connections = NULL;
+		(*instance)->loghelper = &mediator->loghelper;
+
+		status = celixThreadMutex_create(&(*instance)->mutex, NULL);
+
+		if (status == CELIX_SUCCESS) {
+			status = arrayList_create(&(*instance)->connections);
+		}
+	} else {
+		status = CELIX_ENOMEM;
+	}
+	return status;
+}
+
+celix_status_t remoteShell_destroy(remote_shell_pt instance) {
+	celix_status_t status = CELIX_SUCCESS;
+
+	remoteShell_stopConnections(instance);
+
+	celixThreadMutex_lock(&instance->mutex);
+	arrayList_destroy(instance->connections);
+	celixThreadMutex_unlock(&instance->mutex);
+
+	return status;
+}
+
+celix_status_t remoteShell_addConnection(remote_shell_pt instance, int socket) {
+	celix_status_t status = CELIX_SUCCESS;
+	connection_pt connection = calloc(1, sizeof(struct connection));
+
+	if (connection != NULL) {
+		connection->parent = instance;
+		connection->threadRunning = false;
+		connection->socketStream = fdopen(socket, "w");
+
+		if (connection->socketStream != NULL) {
+
+			celixThreadMutex_lock(&instance->mutex);
+
+			if (arrayList_size(instance->connections) < instance->maximumConnections) {
+				celix_thread_t connectionRunThread = celix_thread_default;
+				arrayList_add(instance->connections, connection);
+				status = celixThread_create(&connectionRunThread, NULL, &remoteShell_connection_run, connection);
+			} else {
+				status = CELIX_BUNDLE_EXCEPTION;
+				remoteShell_connection_print(connection, RS_MAXIMUM_CONNECTIONS_REACHED);
+			}
+			celixThreadMutex_unlock(&instance->mutex);
+
+		} else {
+			status = CELIX_BUNDLE_EXCEPTION;
+		}
+	} else {
+		status = CELIX_ENOMEM;
+	}
+
+	if (status != CELIX_SUCCESS && connection != NULL) {
+		if (connection->socketStream != NULL) {
+			fclose(connection->socketStream);
+		}
+		free(connection);
+	}
+
+	return status;
+}
+
+celix_status_t remoteShell_stopConnections(remote_shell_pt instance) {
+	celix_status_t status = CELIX_SUCCESS;
+	int length = 0;
+	int i = 0;
+
+	celixThreadMutex_lock(&instance->mutex);
+	length = arrayList_size(instance->connections);
+
+	for (i = 0; i < length; i += 1) {
+		connection_pt connection = arrayList_get(instance->connections, i);
+		connection->threadRunning = false;
+	}
+
+	celixThreadMutex_unlock(&instance->mutex);
+
+	return status;
+}
+
+void *remoteShell_connection_run(void *data) {
+	celix_status_t status = CELIX_SUCCESS;
+	connection_pt connection = data;
+	size_t len;
+	int result;
+	struct timeval timeout; /* Timeout for select */
+
+	int fd = fileno(connection->socketStream);
+
+	connection->threadRunning = true;
+	status = remoteShell_connection_print(connection, RS_WELCOME);
+
+	while (status == CELIX_SUCCESS && connection->threadRunning == true) {
+		do {
+			timeout.tv_sec = CONNECTION_LISTENER_TIMEOUT_SEC;
+			timeout.tv_usec = 0;
+
+			FD_ZERO(&connection->pollset);
+			FD_SET(fd, &connection->pollset);
+			result = select(fd + 1, &connection->pollset, NULL, NULL, &timeout);
+		} while (result == -1 && errno == EINTR && connection->threadRunning == true);
+
+		/* The socket_fd has data available to be read */
+		if (result > 0 && FD_ISSET(fd, &connection->pollset)) {
+			char buff[COMMAND_BUFF_SIZE];
+
+			len = recv(fd, buff, COMMAND_BUFF_SIZE - 1, 0);
+			if (len < COMMAND_BUFF_SIZE) {
+				celix_status_t commandStatus = CELIX_SUCCESS;
+				buff[len] = '\0';
+
+				commandStatus = remoteShell_connection_execute(connection, buff);
+
+				if (commandStatus == CELIX_SUCCESS) {
+					remoteShell_connection_print(connection, RS_PROMPT);
+				} else if (commandStatus == CELIX_FILE_IO_EXCEPTION) {
+					//exit command
+					break;
+				} else { //error
+					remoteShell_connection_print(connection, RS_ERROR);
+					remoteShell_connection_print(connection, RS_PROMPT);
+				}
+
+			} else {
+				logHelper_log(*connection->parent->loghelper, OSGI_LOGSERVICE_ERROR, "REMOTE_SHELL: Error while retrieving data");
+			}
+		}
+	}
+
+	remoteShell_connection_print(connection, RS_GOODBYE);
+
+	logHelper_log(*connection->parent->loghelper, OSGI_LOGSERVICE_INFO, "REMOTE_SHELL: Closing socket");
+	celixThreadMutex_lock(&connection->parent->mutex);
+	arrayList_removeElement(connection->parent->connections, connection);
+	celixThreadMutex_unlock(&connection->parent->mutex);
+
+	fclose(connection->socketStream);
+
+	return NULL;
+}
+
+static celix_status_t remoteShell_connection_execute(connection_pt connection, char *command) {
+	celix_status_t status = CELIX_SUCCESS;
+
+	if (status == CELIX_SUCCESS) {
+		char *dline = strdup(command);
+		char *line = utils_stringTrim(dline);
+		int len = strlen(line);
+
+		if (len == 0) {
+			//ignore
+		} else if (len == 4 && strncmp("exit", line, 4) == 0) {
+			status = CELIX_FILE_IO_EXCEPTION;
+		} else {
+			status = shellMediator_executeCommand(connection->parent->mediator, line, connection->socketStream, connection->socketStream);
+            fflush(connection->socketStream);
+		}
+
+		free(dline);
+	}
+
+	return status;
+}
+
+celix_status_t remoteShell_connection_print(connection_pt connection, char *text) {
+	size_t len = strlen(text);
+    int fd = fileno(connection->socketStream);
+	return (send(fd, text, len, 0) > 0) ? CELIX_SUCCESS : CELIX_FILE_IO_EXCEPTION;
+}

http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/shell/remote_shell/src/remote_shell.h
----------------------------------------------------------------------
diff --git a/bundles/shell/remote_shell/src/remote_shell.h b/bundles/shell/remote_shell/src/remote_shell.h
new file mode 100644
index 0000000..55249a8
--- /dev/null
+++ b/bundles/shell/remote_shell/src/remote_shell.h
@@ -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.
+ */
+/*
+ * remote_shell.h
+ *
+ *  \date       Nov 4, 2012
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#ifndef REMOTE_SHELL_H_
+#define REMOTE_SHELL_H_
+
+#include <bundle_context.h>
+#include <celix_errno.h>
+
+#include "shell_mediator.h"
+
+struct remote_shell {
+	log_helper_pt* loghelper;
+	shell_mediator_pt mediator;
+	celix_thread_mutex_t mutex;
+	int maximumConnections;
+
+	array_list_pt connections;
+};
+typedef struct remote_shell *remote_shell_pt;
+
+celix_status_t remoteShell_create(shell_mediator_pt mediator, int maximumConnections, remote_shell_pt *instance);
+celix_status_t remoteShell_destroy(remote_shell_pt instance);
+celix_status_t remoteShell_addConnection(remote_shell_pt instance, int socket);
+celix_status_t remoteShell_stopConnections(remote_shell_pt instance);
+
+#endif /* REMOTE_SHELL_H_ */

http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/shell/remote_shell/src/shell_mediator.c
----------------------------------------------------------------------
diff --git a/bundles/shell/remote_shell/src/shell_mediator.c b/bundles/shell/remote_shell/src/shell_mediator.c
new file mode 100644
index 0000000..d9722a9
--- /dev/null
+++ b/bundles/shell/remote_shell/src/shell_mediator.c
@@ -0,0 +1,139 @@
+/**
+ *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.
+ */
+/*
+ * shell_mediator.c
+ *
+ *  \date       Nov 4, 2012
+ *  \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 <utils.h>
+#include <shell.h>
+#include <service_tracker.h>
+#include <command.h>
+#include <sys/socket.h>
+
+#include "log_helper.h"
+#include "log_service.h"
+#include "shell_mediator.h"
+
+static celix_status_t shellMediator_addedService(void *handler, service_reference_pt reference, void * service);
+static celix_status_t shellMediator_removedService(void *handler, service_reference_pt reference, void * service);
+
+celix_status_t shellMediator_create(bundle_context_pt context, shell_mediator_pt *instance) {
+	celix_status_t status = CELIX_SUCCESS;
+	service_tracker_customizer_pt customizer = NULL;
+
+	(*instance) = (shell_mediator_pt) calloc(1, sizeof(**instance));
+	if ((*instance) != NULL) {
+
+		(*instance)->context = context;
+		(*instance)->tracker = NULL;
+		(*instance)->shellService = NULL;
+
+		status = logHelper_create(context, &(*instance)->loghelper);
+
+		status = CELIX_DO_IF(status, celixThreadMutex_create(&(*instance)->mutex, NULL));
+
+		status = CELIX_DO_IF(status, serviceTrackerCustomizer_create((*instance), NULL, shellMediator_addedService,
+				NULL, shellMediator_removedService, &customizer));
+		status = CELIX_DO_IF(status, serviceTracker_create(context, (char * )OSGI_SHELL_SERVICE_NAME, customizer, &(*instance)->tracker));
+
+		if (status == CELIX_SUCCESS) {
+			logHelper_start((*instance)->loghelper);
+			serviceTracker_open((*instance)->tracker);
+		}
+	} else {
+		status = CELIX_ENOMEM;
+	}
+
+	if ((status != CELIX_SUCCESS) && ((*instance) != NULL)){
+		logHelper_log((*instance)->loghelper, OSGI_LOGSERVICE_ERROR, "Error creating shell_mediator, error code is %i\n", status);
+	}
+	return status;
+}
+
+celix_status_t shellMediator_stop(shell_mediator_pt instance) {
+	service_tracker_pt tracker;
+	celixThreadMutex_lock(&instance->mutex);
+	tracker = instance->tracker;
+	celixThreadMutex_unlock(&instance->mutex);
+
+	if (tracker != NULL) {
+		serviceTracker_close(tracker);
+	}
+
+    return CELIX_SUCCESS;
+}
+
+celix_status_t shellMediator_destroy(shell_mediator_pt instance) {
+	celix_status_t status = CELIX_SUCCESS;
+
+	celixThreadMutex_lock(&instance->mutex);
+
+	instance->shellService = NULL;
+	serviceTracker_destroy(instance->tracker);
+	logHelper_stop(instance->loghelper);
+	status = logHelper_destroy(&instance->loghelper);
+	celixThreadMutex_destroy(&instance->mutex);
+
+
+	free(instance);
+
+
+	return status;
+}
+
+celix_status_t shellMediator_executeCommand(shell_mediator_pt instance, char *command, FILE *out, FILE *err) {
+	celix_status_t status = CELIX_SUCCESS;
+
+	celixThreadMutex_lock(&instance->mutex);
+
+
+	if (instance->shellService != NULL) {
+		instance->shellService->executeCommand(instance->shellService->shell, command, out, err);
+	}
+
+	celixThreadMutex_unlock(&instance->mutex);
+
+	return status;
+}
+
+static celix_status_t shellMediator_addedService(void *handler, service_reference_pt reference, void * service) {
+	celix_status_t status = CELIX_SUCCESS;
+	shell_mediator_pt instance = (shell_mediator_pt) handler;
+	celixThreadMutex_lock(&instance->mutex);
+	instance->shellService = (shell_service_pt) service;
+	celixThreadMutex_unlock(&instance->mutex);
+	return status;
+}
+
+
+static celix_status_t shellMediator_removedService(void *handler, service_reference_pt reference, void * service) {
+	celix_status_t status = CELIX_SUCCESS;
+	shell_mediator_pt instance = (shell_mediator_pt) handler;
+	celixThreadMutex_lock(&instance->mutex);
+	instance->shellService = NULL;
+	celixThreadMutex_unlock(&instance->mutex);
+	return status;
+}
+

http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/shell/remote_shell/src/shell_mediator.h
----------------------------------------------------------------------
diff --git a/bundles/shell/remote_shell/src/shell_mediator.h b/bundles/shell/remote_shell/src/shell_mediator.h
new file mode 100644
index 0000000..24e8250
--- /dev/null
+++ b/bundles/shell/remote_shell/src/shell_mediator.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.
+ */
+/*
+ * shell_mediator.h
+ *
+ *  \date       Nov 4, 2012
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+
+#ifndef shellMediator_H_
+#define shellMediator_H_
+
+#include <bundle_context.h>
+#include <service_tracker.h>
+#include <celix_errno.h>
+
+#include <shell.h>
+
+struct shell_mediator {
+
+	log_helper_pt loghelper;
+	bundle_context_pt context;
+	service_tracker_pt tracker;
+	celix_thread_mutex_t mutex;
+
+	//protected by mutex
+	shell_service_pt shellService;
+};
+typedef struct shell_mediator *shell_mediator_pt;
+
+celix_status_t shellMediator_create(bundle_context_pt context, shell_mediator_pt *instance);
+celix_status_t shellMediator_stop(shell_mediator_pt instance);
+celix_status_t shellMediator_destroy(shell_mediator_pt instance);
+celix_status_t shellMediator_executeCommand(shell_mediator_pt instance, char *command, FILE *out, FILE *err);
+
+#endif /* shellMediator_H_ */

http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/shell/shell/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/bundles/shell/shell/CMakeLists.txt b/bundles/shell/shell/CMakeLists.txt
new file mode 100644
index 0000000..7bba23b
--- /dev/null
+++ b/bundles/shell/shell/CMakeLists.txt
@@ -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.
+celix_subproject(SHELL "Option to enable building the Shell bundles" ON DEPS LAUNCHER LOG_SERVICE)
+if (SHELL)
+	find_package(CURL REQUIRED)
+
+	add_library(shell_api INTERFACE)
+	target_include_directories(shell_api INTERFACE
+			$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>
+			$<INSTALL_INTERFACE:include/celix/shell>
+	)
+	install(TARGETS shell_api EXPORT celix COMPONENT shell)
+	install(DIRECTORY include/ DESTINATION include/celix/shell COMPONENT shell)
+
+    add_celix_bundle(shell
+        SYMBOLIC_NAME "apache_celix_shell"
+        VERSION "2.1.0"
+        NAME "Apache Celix Shell"
+        SOURCES
+          src/activator
+          src/shell
+          src/lb_command
+          src/start_command
+          src/stop_command
+          src/install_command
+          src/update_command
+          src/uninstall_command
+          src/log_command
+          src/inspect_command
+          src/help_command
+		  src/dm_shell_list_command
+	)
+	target_include_directories(shell PRIVATE src)
+	target_include_directories(shell SYSTEM PRIVATE	${CURL_INCLUDE_DIRS})
+	target_link_libraries(shell PRIVATE Celix::shell_api ${CURL_LIBRARIES} Celix::log_service_api Celix::log_helper)
+
+	install_celix_bundle(shell EXPORT celix COMPONENT shell)
+
+	#Setup target aliases to match external usage
+	add_library(Celix::shell_api ALIAS shell_api)
+	add_library(Celix::shell ALIAS shell)
+endif (SHELL)

http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/shell/shell/README.md
----------------------------------------------------------------------
diff --git a/bundles/shell/shell/README.md b/bundles/shell/shell/README.md
new file mode 100644
index 0000000..d9f38af
--- /dev/null
+++ b/bundles/shell/shell/README.md
@@ -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.
+-->
+
+# Shell
+
+The Celix Shell provides a service interface which can be used to interact with the Celix framework. Note that it does not offer a user interface. This modular approach enables having multiple frontends, e.g. textual or graphical.
+
+While the shell can be extended with additional commands by other bundles, it already offers some built in commands:
+
+    lb            list bundles
+    install       install additional bundle
+    uninstall     uninstall bundles
+    update        update bundles
+
+    start         start bundle
+    stop          stop bundle
+
+    help          displays available commands
+    inspect       inspect service and components
+
+    log           print log
+
+Further information about a command can be retrieved by using `help` combined with the command.
+
+## CMake options
+    BUILD_SHELL=ON
+
+## Shell Config Options
+
+- SHELL_USE_ANSI_COLORS - Whether shell command are allowed to use
+ANSI colors when printing info. default is true.
+
+## Using info
+
+If the Celix Shell is installed, 'find_package(Celix)' will set:
+ - The `Celix::shell_api` interface (i.e. header only) library target
+ - The `Celix::shell` bundle target

http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/shell/shell/include/command.h
----------------------------------------------------------------------
diff --git a/bundles/shell/shell/include/command.h b/bundles/shell/shell/include/command.h
new file mode 100644
index 0000000..65e4306
--- /dev/null
+++ b/bundles/shell/shell/include/command.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.
+ */
+/*
+ * command.h
+ *
+ *  \date       Aug 13, 2010
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#ifndef COMMAND_H_
+#define COMMAND_H_
+
+#include "celix_errno.h"
+#include <stdio.h>
+
+#define OSGI_SHELL_COMMAND_NAME "command.name"
+#define OSGI_SHELL_COMMAND_USAGE "command.usage"
+#define OSGI_SHELL_COMMAND_DESCRIPTION "command.description"
+
+static const char * const OSGI_SHELL_COMMAND_SERVICE_NAME = "commandService";
+static const char * const OSGI_SHELL_COMMAND_SERVICE_VERSION = "1.0.0";
+
+typedef struct commandService command_service_t;
+typedef command_service_t * command_service_pt;
+
+/**
+ * The command service can be used to register additional shell commands.
+ * The service should be register with the following properties:
+ *  - command.name: mandatory, name of the command e.g. 'lb'
+ *  - command.usage: optional, string describing how tu use the commmand e.g. 'lb [-l | -s | -u]'
+ *  - command.descrription: optional, string describing the command e.g. 'list bundles.'
+ */
+struct commandService {
+	void *handle;
+	celix_status_t (*executeCommand)(void *handle, char * commandLine, FILE *outStream, FILE *errorStream);
+};
+
+
+
+
+#endif /* COMMAND_H_ */

http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/shell/shell/include/dm_shell_list_command.h
----------------------------------------------------------------------
diff --git a/bundles/shell/shell/include/dm_shell_list_command.h b/bundles/shell/shell/include/dm_shell_list_command.h
new file mode 100644
index 0000000..6ab0581
--- /dev/null
+++ b/bundles/shell/shell/include/dm_shell_list_command.h
@@ -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.
+ */
+
+#ifndef DM_SHELL_LIST_COMMAND_H_
+#define DM_SHELL_LIST_COMMAND_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include "command.h"
+
+typedef struct dm_command_handle {
+    bundle_context_pt context;
+    bool useColors;
+} dm_command_handle_t;
+
+void dmListCommand_execute(dm_command_handle_t* handle, char * line, FILE *out, FILE *err);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //DM_SHELL_LSIT_COMMAND_H_
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/shell/shell/include/shell.h
----------------------------------------------------------------------
diff --git a/bundles/shell/shell/include/shell.h b/bundles/shell/shell/include/shell.h
new file mode 100644
index 0000000..c8e7d60
--- /dev/null
+++ b/bundles/shell/shell/include/shell.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.
+ */
+/*
+ * shell.h
+ *
+ *  \date       Aug 12, 2010
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#ifndef SHELL_H_
+#define SHELL_H_
+
+#include "array_list.h"
+#include "service_reference.h"
+
+static const char * const OSGI_SHELL_SERVICE_NAME = "shellService";
+
+typedef struct shell shell_t;
+typedef shell_t* shell_pt;
+
+struct shellService {
+	shell_pt shell;
+
+	celix_status_t (*getCommands)(shell_pt shell_ptr, array_list_pt *commands_ptr);
+	celix_status_t (*getCommandUsage)(shell_pt shell_ptr, char *command_name_str, char **usage_str);
+	celix_status_t (*getCommandDescription)(shell_pt shell_ptr, char *command_name_str, char **command_description_str);
+	celix_status_t (*getCommandReference)(shell_pt shell_ptr, char *command_name_str, service_reference_pt *command_reference_ptr);
+	celix_status_t (*executeCommand)(shell_pt shell_ptr, char * command_line_str, FILE *out, FILE *err);
+};
+
+typedef struct shellService shell_service_t;
+typedef shell_service_t* shell_service_pt;
+
+#endif /* SHELL_H_ */

http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/shell/shell/include/shell_constants.h
----------------------------------------------------------------------
diff --git a/bundles/shell/shell/include/shell_constants.h b/bundles/shell/shell/include/shell_constants.h
new file mode 100644
index 0000000..1e7f875
--- /dev/null
+++ b/bundles/shell/shell/include/shell_constants.h
@@ -0,0 +1,27 @@
+/**
+ *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 SHELL_CONSTANTS_H_
+#define SHELL_CONSTANTS_H_
+
+#define SHELL_USE_ANSI_COLORS "SHELL_USE_ANSI_COLORS"
+#define SHELL_USE_ANSI_COLORS_DEFAULT_VALUE "true"
+
+#endif /* SHELL_CONSTANTS_H_ */

http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/shell/shell/src/activator.c
----------------------------------------------------------------------
diff --git a/bundles/shell/shell/src/activator.c b/bundles/shell/shell/src/activator.c
new file mode 100644
index 0000000..16923cf
--- /dev/null
+++ b/bundles/shell/shell/src/activator.c
@@ -0,0 +1,273 @@
+/**
+ *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.
+ */
+/*
+ * activator.c
+ *
+ *  \date       Aug 13, 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 "shell_private.h"
+#include "bundle_activator.h"
+#include "std_commands.h"
+#include "service_tracker.h"
+#include "constants.h"
+
+#define NUMBER_OF_COMMANDS 11
+
+struct command {
+    celix_status_t (*exec)(void *handle, char *commandLine, FILE *out, FILE *err);
+    char *name;
+    char *description;
+    char *usage;
+    command_service_pt service;
+    properties_pt props;
+    long svcId; //used for service (un)registration
+};
+
+struct bundle_instance {
+	shell_service_pt shellService;
+	service_registration_pt registration;
+    service_tracker_pt tracker;
+
+    struct command std_commands[NUMBER_OF_COMMANDS];
+};
+
+typedef struct bundle_instance *bundle_instance_pt;
+
+celix_status_t bundleActivator_create(bundle_context_pt context_ptr, void **_pptr) {
+	celix_status_t status = CELIX_SUCCESS;
+
+    bundle_instance_pt instance_ptr = NULL;
+
+    if (!_pptr || !context_ptr) {
+        status = CELIX_ENOMEM;
+    }
+
+    if (status == CELIX_SUCCESS) {
+        instance_ptr = (bundle_instance_pt) calloc(1, sizeof(struct bundle_instance));
+        if (!instance_ptr) {
+            status = CELIX_ENOMEM;
+        }
+    }
+
+    if (status == CELIX_SUCCESS) {
+        status = shell_create(context_ptr, &instance_ptr->shellService);
+    }
+
+    if (status == CELIX_SUCCESS) {
+        instance_ptr->std_commands[0] =
+                (struct command) {
+                        .exec = psCommand_execute,
+                        .name = "lb",
+                        .description = "list bundles.",
+                        .usage = "lb [-l | -s | -u]"
+                };
+        instance_ptr->std_commands[1] =
+                (struct command) {
+                        .exec = startCommand_execute,
+                        .name = "start",
+                        .description = "start bundle(s).",
+                        .usage = "start <id> [<id> ...]"
+                };
+        instance_ptr->std_commands[2] =
+                (struct command) {
+                        .exec = stopCommand_execute,
+                        .name = "stop",
+                        .description = "stop bundle(s).",
+                        .usage = "stop <id> [<id> ...]"
+                };
+        instance_ptr->std_commands[3] =
+                (struct command) {
+                        .exec = installCommand_execute,
+                        .name = "install",
+                        .description = "install bundle(s).",
+                        .usage = "install <file> [<file> ...]"
+                };
+        instance_ptr->std_commands[4] =
+                (struct command) {
+                        .exec = uninstallCommand_execute,
+                        .name = "uninstall",
+                        .description = "uninstall bundle(s).",
+                        .usage = "uninstall <file> [<file> ...]"
+                };
+        instance_ptr->std_commands[5] =
+                (struct command) {
+                        .exec = updateCommand_execute,
+                        .name = "update",
+                        .description = "update bundle(s).",
+                        .usage = "update <id> [<URL>]"
+                };
+        instance_ptr->std_commands[6] =
+                (struct command) {
+                        .exec = helpCommand_execute,
+                        .name = "help",
+                        .description = "display available commands and description.",
+                        .usage = "help <command>]"
+                };
+        instance_ptr->std_commands[7] =
+                (struct command) {
+                        .exec = logCommand_execute,
+                        .name = "log",
+                        .description = "print log.",
+                        .usage = "log"
+                };
+        instance_ptr->std_commands[8] =
+                (struct command) {
+                        .exec = inspectCommand_execute,
+                        .name = "inspect",
+                        .description = "inspect services and components.",
+                        .usage = "inspect (service) (capability|requirement) [<id> ...]"
+                };
+        instance_ptr->std_commands[9] =
+                (struct command) {
+                        .exec = dmListCommand_execute,
+                        .name = "dm",
+                        .description = "Gives an overview of the component managemed by a dependency manager.",
+                        .usage = "dm [f|full] [<Bundle ID> [<Bundle ID> [...]]]"
+                };
+        instance_ptr->std_commands[10] =
+                (struct command) { NULL, NULL, NULL, NULL, NULL, NULL, -1L }; /*marker for last element*/
+
+        unsigned int i = 0;
+        while (instance_ptr->std_commands[i].exec != NULL) {
+            instance_ptr->std_commands[i].props = properties_create();
+            if (!instance_ptr->std_commands[i].props) {
+                status = CELIX_BUNDLE_EXCEPTION;
+                break;
+            }
+
+            properties_set(instance_ptr->std_commands[i].props, OSGI_SHELL_COMMAND_NAME, instance_ptr->std_commands[i].name);
+            properties_set(instance_ptr->std_commands[i].props, OSGI_SHELL_COMMAND_USAGE, instance_ptr->std_commands[i].usage);
+            properties_set(instance_ptr->std_commands[i].props, OSGI_SHELL_COMMAND_DESCRIPTION, instance_ptr->std_commands[i].description);
+            properties_set(instance_ptr->std_commands[i].props, CELIX_FRAMEWORK_SERVICE_LANGUAGE, CELIX_FRAMEWORK_SERVICE_C_LANGUAGE);
+
+            instance_ptr->std_commands[i].service = calloc(1, sizeof(*instance_ptr->std_commands[i].service));
+            if (!instance_ptr->std_commands[i].service) {
+                status = CELIX_ENOMEM;
+                break;
+            }
+
+            instance_ptr->std_commands[i].service->handle = context_ptr;
+            instance_ptr->std_commands[i].service->executeCommand = instance_ptr->std_commands[i].exec;
+
+            i += 1;
+        }
+    }
+
+    if (status == CELIX_SUCCESS) {
+        *_pptr = instance_ptr;
+    }
+
+
+    if (status != CELIX_SUCCESS) {
+        bundleActivator_destroy(instance_ptr, context_ptr);
+    }
+
+	return status;
+}
+
+celix_status_t bundleActivator_start(void *_ptr, bundle_context_pt context_ptr) {
+	celix_status_t status = CELIX_SUCCESS;
+
+	bundle_instance_pt instance_ptr  = (bundle_instance_pt) _ptr;
+
+    if (!instance_ptr || !context_ptr) {
+        status = CELIX_ILLEGAL_ARGUMENT;
+    }
+
+    if (status == CELIX_SUCCESS) {
+        properties_pt props = properties_create();
+        properties_set(props, CELIX_FRAMEWORK_SERVICE_LANGUAGE, CELIX_FRAMEWORK_SERVICE_C_LANGUAGE);
+        status = bundleContext_registerService(context_ptr, (char *) OSGI_SHELL_SERVICE_NAME, instance_ptr->shellService, props, &instance_ptr->registration);
+    }
+
+	if (status == CELIX_SUCCESS) {
+        service_tracker_customizer_pt cust = NULL;
+        serviceTrackerCustomizer_create(instance_ptr->shellService->shell, NULL, (void *)shell_addCommand, NULL, (void *)shell_removeCommand, &cust);
+        serviceTracker_create(context_ptr, (char *)OSGI_SHELL_COMMAND_SERVICE_NAME, cust, &instance_ptr->tracker);
+        serviceTracker_open(instance_ptr->tracker);
+    }
+
+
+    if (status == CELIX_SUCCESS) {
+        for (unsigned int i = 0; instance_ptr->std_commands[i].exec != NULL; i++) {
+            celix_service_registration_options_t opts = CELIX_EMPTY_SERVICE_REGISTRATION_OPTIONS;
+            opts.svc = instance_ptr->std_commands[i].service;
+            opts.serviceName = OSGI_SHELL_COMMAND_SERVICE_NAME;
+            opts.serviceVersion = OSGI_SHELL_COMMAND_SERVICE_VERSION;
+            opts.properties = instance_ptr->std_commands[i].props;
+            instance_ptr->std_commands[i].svcId = celix_bundleContext_registerServiceWithOptions(context_ptr, &opts);
+        }
+	}
+
+	return status;
+}
+
+celix_status_t bundleActivator_stop(void *_ptr, bundle_context_pt context_ptr) {
+    celix_status_t status = CELIX_SUCCESS;
+
+    bundle_instance_pt instance_ptr = (bundle_instance_pt) _ptr;
+
+    if (instance_ptr) {
+        for (unsigned int i = 0; instance_ptr->std_commands[i].exec != NULL; i++) {
+            if (instance_ptr->std_commands[i].svcId >= 0) {
+                celix_bundleContext_unregisterService(context_ptr, instance_ptr->std_commands[i].svcId);
+                instance_ptr->std_commands[i].props = NULL;
+            }
+        }
+
+        if (instance_ptr->tracker != NULL) {
+            serviceTracker_close(instance_ptr->tracker);
+        }
+    } else {
+        status = CELIX_ILLEGAL_ARGUMENT;
+    }
+
+    return status;
+}
+
+celix_status_t bundleActivator_destroy(void *_ptr, bundle_context_pt __attribute__((__unused__)) context_ptr) {
+    celix_status_t status = CELIX_SUCCESS;
+
+    bundle_instance_pt instance_ptr = (bundle_instance_pt) _ptr;
+
+    if (instance_ptr) {
+        serviceRegistration_unregister(instance_ptr->registration);
+
+        for (unsigned int i = 0; instance_ptr->std_commands[i].exec != NULL; i++) {
+            free(instance_ptr->std_commands[i].service);
+        }
+
+        shell_destroy(&instance_ptr->shellService);
+
+        if (instance_ptr->tracker != NULL) {
+            serviceTracker_destroy(instance_ptr->tracker);
+        }
+
+        free(instance_ptr);
+    } else {
+        status = CELIX_ILLEGAL_ARGUMENT;
+    }
+
+    return status;
+}