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;
+}