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 2019/01/07 20:11:53 UTC
[celix] 05/22: CELIX-438: Adds an initial setup for handling
resources in bundles
This is an automated email from the ASF dual-hosted git repository.
pnoltes pushed a commit to branch feature/cxx
in repository https://gitbox.apache.org/repos/asf/celix.git
commit 34dac36bbc4462ec3c4bb3adcf656a05c905352a
Author: Pepijn Noltes <pe...@gmail.com>
AuthorDate: Thu Jan 3 22:40:58 2019 +0100
CELIX-438: Adds an initial setup for handling resources in bundles
---
.travis.yml | 3 +-
CMakeLists.txt | 1 +
bundles/shell/cxx_shell/CMakeLists.txt | 21 +-
.../shell/cxx_shell/resources/version.properties | 3 +
bundles/shell/cxx_shell/src/ShellActivator.cc | 10 +-
bundles/shell/cxx_shell/src/VersionCommand.cc | 51 +++++
bundles/shell/cxx_shell/src/commands.h | 1 +
bundles/shell/cxx_shell_tui/CMakeLists.txt | 2 -
.../shell/cxx_shell_tui/src/ShellTuiActivator.cc | 1 +
bundles/shell/cxx_shell_tui/src/shell_test.cc | 1 -
cmake/celix_project/AddGLog.cmake | 8 +-
cmake/celix_project/AddGTest.cmake | 1 +
.../{AddGLog.cmake => AddLibzip.cmake} | 20 +-
libs/framework_cxx/CMakeLists.txt | 10 +-
libs/framework_cxx/include/celix/Framework.h | 25 ++-
libs/framework_cxx/src/Bundle.cc | 24 ++-
libs/framework_cxx/src/Bundle.h | 18 +-
libs/framework_cxx/src/BundleController.h | 196 ++++++++++++++++++-
libs/framework_cxx/src/Framework.cc | 103 ++++++++--
libs/registry/CMakeLists.txt | 3 +-
libs/registry/include/celix/IResourceBundle.h | 11 +-
libs/registry/include/celix/Properties.h | 8 +-
libs/registry/src/Properties.cc | 215 +++++++++++++++++++++
libs/registry/src/ServiceRegistry.cc | 11 +-
24 files changed, 665 insertions(+), 82 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index e3536d2..a95432b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -35,9 +35,8 @@ matrix:
#services: docker
before_install:
- - if [ "$TRAVIS_OS_NAME" = "linux" ] sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
- if [ "$TRAVIS_OS_NAME" = "linux" ] sudo apt-get update -qq
- - if [ "$TRAVIS_OS_NAME" = "linux" ] sudo apt-get install -qq uuid-dev libxml2-dev lcov libffi-dev libgoogle-glog-dev libczmq-dev libcpputest-dev libjansson-dev
+ - if [ "$TRAVIS_OS_NAME" = "linux" ] sudo apt-get install -qq uuid-dev libxml2-dev lcov libffi-dev libczmq-dev libcpputest-dev libjansson-dev
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew update && brew install lcov libffi zeromq czmq glog cpputest jansson && brew link --force libffi; fi
before_script:
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c1c4a43..7025630 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -58,6 +58,7 @@ if (ENABLE_TESTING)
include(cmake/celix_project/AddGTest.cmake)
endif ()
include(cmake/celix_project/AddGLog.cmake)
+include(cmake/celix_project/AddLibzip.cmake)
# Default bundle version
set(DEFAULT_VERSION 1.0.0)
diff --git a/bundles/shell/cxx_shell/CMakeLists.txt b/bundles/shell/cxx_shell/CMakeLists.txt
index a4ad2df..d2b2113 100644
--- a/bundles/shell/cxx_shell/CMakeLists.txt
+++ b/bundles/shell/cxx_shell/CMakeLists.txt
@@ -15,8 +15,6 @@
# specific language governing permissions and limitations
# under the License.
-find_package(glog REQUIRED)
-
#TODO rename to celix::shell && celix::shell_api
add_library(celix_cxx_shell_api INTERFACE)
@@ -25,6 +23,17 @@ target_include_directories(celix_cxx_shell_api INTERFACE
$<INSTALL_INTERFACE:include/celix/shell>
)
+#TODO should eventually be done by a CMake command (i.e. bundle_add_resources)
+add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/celix_cxx_shell_resources.zip
+ COMMAND zip -rq ${CMAKE_CURRENT_BINARY_DIR}/celix_cxx_shell_resources.zip *
+ COMMENT "Packaging Resources"
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/resources
+)
+
+add_custom_target(create_resources ALL
+ DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/celix_cxx_shell_resources.zip
+)
+
add_library(celix_cxx_shell SHARED
src/ShellActivator.cc
src/LbCommand.cc
@@ -32,10 +41,18 @@ add_library(celix_cxx_shell SHARED
src/StopAndStartCommand.cc
src/InspectCommand.cc
src/QueryCommand.cc
+ src/VersionCommand.cc
)
target_include_directories(celix_cxx_shell PRIVATE src)
target_link_libraries(celix_cxx_shell PRIVATE celix_cxx_shell_api glog::glog)
target_link_libraries(celix_cxx_shell PUBLIC celix_framework_cxx)
+add_dependencies(celix_cxx_shell create_resources)
+if (UNIX AND NOT APPLE)
+ target_link_libraries(celix_cxx_shell PRIVATE -Wl,--format=binary -Wl,celix_cxx_shell_resources.zip -Wl,--format=default)
+else ()
+ #TODO apple
+endif ()
+
#if (ENABLE_TESTING)
# add_subdirectory(gtest)
diff --git a/bundles/shell/cxx_shell/resources/version.properties b/bundles/shell/cxx_shell/resources/version.properties
new file mode 100644
index 0000000..2840a93
--- /dev/null
+++ b/bundles/shell/cxx_shell/resources/version.properties
@@ -0,0 +1,3 @@
+CELIX_VERSION=3.0.0
+COMMIT_ID=TODO
+COMMIT_DATA=TODO
\ No newline at end of file
diff --git a/bundles/shell/cxx_shell/src/ShellActivator.cc b/bundles/shell/cxx_shell/src/ShellActivator.cc
index bfbbb8f..ea54219 100644
--- a/bundles/shell/cxx_shell/src/ShellActivator.cc
+++ b/bundles/shell/cxx_shell/src/ShellActivator.cc
@@ -17,12 +17,17 @@
*under the License.
*/
+#include <glog/logging.h>
+
#include "celix/api.h"
#include "celix/IShellCommand.h"
#include "celix/IShell.h"
#include "commands.h"
+extern const uint8_t resources[] asm("_binary_celix_cxx_shell_resources_zip_start");
+extern const uint8_t resources_end[] asm("_binary_celix_cxx_shell_resources_zip_end");
+
namespace {
class Shell : public celix::IShell {
@@ -86,6 +91,7 @@ namespace {
registrations.push_back(impl::registerStart(ctx));
registrations.push_back(impl::registerInspect(ctx));
registrations.push_back(impl::registerQuery(ctx));
+ registrations.push_back(impl::registerVersion(ctx));
registrations.push_back(ctx->registerService(std::shared_ptr<celix::IShell>{new Shell{ctx}}));
}
@@ -93,12 +99,14 @@ namespace {
std::vector<celix::ServiceRegistration> registrations{};
};
+ //NOTE that eventually the (ctor) bundle register will be generated by a CMake command (i.e. add_bundle)
+ //This also applies for the resources, resources_end asm entries.
__attribute__((constructor))
static void registerShellBundle() {
celix::Properties manifest{};
manifest[celix::MANIFEST_BUNDLE_NAME] = "Shell";
manifest[celix::MANIFEST_BUNDLE_GROUP] = "Celix";
manifest[celix::MANIFEST_BUNDLE_VERSION] = "1.0.0";
- celix::registerStaticBundle<ShellBundleActivator>("celix::Shell", manifest);
+ celix::registerStaticBundle<ShellBundleActivator>("celix::Shell", manifest, resources, resources_end - resources);
}
}
diff --git a/bundles/shell/cxx_shell/src/VersionCommand.cc b/bundles/shell/cxx_shell/src/VersionCommand.cc
new file mode 100644
index 0000000..d95b7a4
--- /dev/null
+++ b/bundles/shell/cxx_shell/src/VersionCommand.cc
@@ -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.
+ */
+
+#include "commands.h"
+
+#include <functional>
+
+#include "celix/api.h"
+#include "celix/IShellCommand.h"
+
+namespace {
+
+ void version(std::shared_ptr<celix::BundleContext> ctx, const std::string &, const std::vector<std::string> &, std::ostream &out, std::ostream &err) {
+ if (ctx->bundle()->hasCacheEntry("version.properties")) {
+ auto path = ctx->bundle()->absPathForCacheEntry("version.properties");
+ celix::Properties versionInfo = celix::loadProperties(path);
+ std::string version = celix::getProperty(versionInfo, "CELIX_VERSION", "");
+ out << "Celix Version: " << version << std::endl;
+ } else {
+ err << "Cannot find version.properties entry in the " << ctx->bundle()->group() << " " << ctx->bundle()->name() << " bundle" << std::endl;
+ }
+ }
+}
+
+
+celix::ServiceRegistration impl::registerVersion(std::shared_ptr<celix::BundleContext> ctx) {
+ using namespace std::placeholders;
+ celix::ShellCommandFunction cmd = std::bind(&version, ctx, _1, _2, _3, _4);
+
+ celix::Properties props{};
+ props[celix::SHELL_COMMAND_FUNCTION_COMMAND_NAME] = "version";
+ props[celix::SHELL_COMMAND_FUNCTION_COMMAND_USAGE] = "version";
+ props[celix::SHELL_COMMAND_FUNCTION_COMMAND_DESCRIPTION] = "Show version information about the framework (TODO and installed bundles)";
+ return ctx->registerFunctionService(celix::SHELL_COMMAND_FUNCTION_SERVICE_FQN, std::move(cmd), std::move(props));
+}
\ No newline at end of file
diff --git a/bundles/shell/cxx_shell/src/commands.h b/bundles/shell/cxx_shell/src/commands.h
index b9d9a8f..9f1f18b 100644
--- a/bundles/shell/cxx_shell/src/commands.h
+++ b/bundles/shell/cxx_shell/src/commands.h
@@ -29,6 +29,7 @@ namespace impl {
celix::ServiceRegistration registerStart(std::shared_ptr<celix::BundleContext> ctx);
celix::ServiceRegistration registerInspect(std::shared_ptr<celix::BundleContext> ctx);
celix::ServiceRegistration registerQuery(std::shared_ptr<celix::BundleContext> ctx);
+ celix::ServiceRegistration registerVersion(std::shared_ptr<celix::BundleContext> ctx);
}
diff --git a/bundles/shell/cxx_shell_tui/CMakeLists.txt b/bundles/shell/cxx_shell_tui/CMakeLists.txt
index cfbf6cf..e9fa13b 100644
--- a/bundles/shell/cxx_shell_tui/CMakeLists.txt
+++ b/bundles/shell/cxx_shell_tui/CMakeLists.txt
@@ -15,8 +15,6 @@
# specific language governing permissions and limitations
# under the License.
-find_package(glog REQUIRED)
-
#TODO rename to celix::shell_tui
#OR static lib, but then with all symbols to force constructor attribute
diff --git a/bundles/shell/cxx_shell_tui/src/ShellTuiActivator.cc b/bundles/shell/cxx_shell_tui/src/ShellTuiActivator.cc
index a66bea5..ec48f6b 100644
--- a/bundles/shell/cxx_shell_tui/src/ShellTuiActivator.cc
+++ b/bundles/shell/cxx_shell_tui/src/ShellTuiActivator.cc
@@ -140,6 +140,7 @@ namespace {
celix::ServiceTracker trk{};
};
+ //NOTE that eventually the (ctor) bundle register will be generated by a CMake command (i.e. add_bundle)
__attribute__((constructor))
static void registerShellBundle() {
celix::Properties manifest{};
diff --git a/bundles/shell/cxx_shell_tui/src/shell_test.cc b/bundles/shell/cxx_shell_tui/src/shell_test.cc
index cd3af3c..8e92107 100644
--- a/bundles/shell/cxx_shell_tui/src/shell_test.cc
+++ b/bundles/shell/cxx_shell_tui/src/shell_test.cc
@@ -29,7 +29,6 @@ int main(int /*argc*/, char **argv) {
google::LogToStderr();
auto fw = celix::Framework{};
- std::cout << "Waiting for Framework shutdown\n";
fw.waitForShutdown();
return 0;
}
\ No newline at end of file
diff --git a/cmake/celix_project/AddGLog.cmake b/cmake/celix_project/AddGLog.cmake
index 8cc3414..4897f35 100644
--- a/cmake/celix_project/AddGLog.cmake
+++ b/cmake/celix_project/AddGLog.cmake
@@ -21,9 +21,15 @@ ExternalProject_Add(
googlelog_project
GIT_REPOSITORY https://github.com/google/glog.git
GIT_TAG v0.3.5
+ UPDATE_DISCONNECTED TRUE
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/glog
CMAKE_ARGS -DWITH_GFLAGS=OFF -DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR}/glog -DCMAKE_CXX_FLAGS=-w
)
-set(CMAKE_PREFIX_PATH "${CMAKE_CURRENT_BINARY_DIR}/glog ${CMAKE_PREFIX_PATH}")
+add_library(glog::glog IMPORTED STATIC GLOBAL)
+add_dependencies(glog::glog googlelog_project)
+set_target_properties(glog::glog PROPERTIES
+ IMPORTED_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/glog/lib/libglog.a"
+ INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/glog/include"
+)
diff --git a/cmake/celix_project/AddGTest.cmake b/cmake/celix_project/AddGTest.cmake
index 93227c1..2da1a47 100644
--- a/cmake/celix_project/AddGTest.cmake
+++ b/cmake/celix_project/AddGTest.cmake
@@ -20,6 +20,7 @@ ExternalProject_Add(
googletest_project
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG release-1.8.1
+ UPDATE_DISCONNECTED TRUE
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/gtest
INSTALL_COMMAND ""
)
diff --git a/cmake/celix_project/AddGLog.cmake b/cmake/celix_project/AddLibzip.cmake
similarity index 54%
copy from cmake/celix_project/AddGLog.cmake
copy to cmake/celix_project/AddLibzip.cmake
index 8cc3414..7d14cb6 100644
--- a/cmake/celix_project/AddGLog.cmake
+++ b/cmake/celix_project/AddLibzip.cmake
@@ -15,15 +15,19 @@
# specific language governing permissions and limitations
# under the License.
-
include(ExternalProject)
ExternalProject_Add(
- googlelog_project
- GIT_REPOSITORY https://github.com/google/glog.git
- GIT_TAG v0.3.5
- PREFIX ${CMAKE_CURRENT_BINARY_DIR}/glog
- CMAKE_ARGS -DWITH_GFLAGS=OFF -DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR}/glog -DCMAKE_CXX_FLAGS=-w
+ libzip_project
+ GIT_REPOSITORY https://github.com/nih-at/libzip.git
+ GIT_TAG rel-1-5-1
+ UPDATE_DISCONNECTED TRUE
+ PREFIX ${CMAKE_CURRENT_BINARY_DIR}/libzip
+ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR}/libzip -DCMAKE_C_FLAGS=-fPIC -DBUILD_SHARED_LIBS=OFF -DENABLE_COMMONCRYPTO=OFF -DENABLE_GNUTLS=OFF -DENABLE_OPENSSL=OFF -Wno-dev
)
-set(CMAKE_PREFIX_PATH "${CMAKE_CURRENT_BINARY_DIR}/glog ${CMAKE_PREFIX_PATH}")
-
+add_library(libzip::libzip IMPORTED STATIC GLOBAL)
+add_dependencies(libzip::libzip libzip_project)
+set_target_properties(libzip::libzip PROPERTIES
+ IMPORTED_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/libzip/lib64/libzip.a"
+ INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/libzip/include"
+)
\ No newline at end of file
diff --git a/libs/framework_cxx/CMakeLists.txt b/libs/framework_cxx/CMakeLists.txt
index c47ae80..f3c116e 100644
--- a/libs/framework_cxx/CMakeLists.txt
+++ b/libs/framework_cxx/CMakeLists.txt
@@ -15,17 +15,19 @@
# specific language governing permissions and limitations
# under the License.
-find_package(glog REQUIRED)
+find_package(UUID REQUIRED)
#TODO rename to celix::framework
add_library(celix_framework_cxx SHARED
src/Framework.cc
src/BundleContext.cc
- src/Bundle.cc)
+ src/Bundle.cc
+)
target_include_directories(celix_framework_cxx PRIVATE src)
target_include_directories(celix_framework_cxx PUBLIC include)
-target_link_libraries(celix_framework_cxx PRIVATE glog::glog)
-target_link_libraries(celix_framework_cxx PUBLIC celix::registry)
+target_link_libraries(celix_framework_cxx PRIVATE glog::glog libzip::libzip)
+#NOTE because of libzil libbz2 and libz is also needed. maybe more to other form of resources (i.e. tar)
+target_link_libraries(celix_framework_cxx PUBLIC celix::registry bz2 z ${UUID_LIBRARY})
if (ENABLE_TESTING)
add_subdirectory(gtest)
diff --git a/libs/framework_cxx/include/celix/Framework.h b/libs/framework_cxx/include/celix/Framework.h
index 27718f8..89e9a3b 100644
--- a/libs/framework_cxx/include/celix/Framework.h
+++ b/libs/framework_cxx/include/celix/Framework.h
@@ -35,16 +35,20 @@ namespace celix {
void registerStaticBundle(
std::string symbolicName,
std::function<celix::IBundleActivator*(std::shared_ptr<celix::BundleContext>)> bundleActivatorFactory = {},
- celix::Properties manifest = {});
+ celix::Properties manifest = {},
+ const uint8_t *resourcesZip = nullptr,
+ size_t resourcesZipLen = 0);
template<typename T>
void registerStaticBundle(
std::string symbolicName,
- celix::Properties manifest = {}) {
+ celix::Properties manifest = {},
+ const uint8_t *resourcesZip = nullptr,
+ size_t resourcesZipLen = 0) {
auto actFactory = [](std::shared_ptr<celix::BundleContext> ctx) {
return new T{std::move(ctx)};
};
- celix::registerStaticBundle(std::move(symbolicName), actFactory, std::move(manifest));
+ celix::registerStaticBundle(std::move(symbolicName), std::move(actFactory), std::move(manifest), resourcesZip, resourcesZipLen);
}
class Framework {
@@ -58,14 +62,20 @@ namespace celix {
Framework& operator=(const Framework &rhs) = delete;
template<typename T>
- long installBundle(std::string name, celix::Properties manifest = {}, bool autoStart = true) {
+ long installBundle(std::string name, celix::Properties manifest = {}, bool autoStart = true, const uint8_t *resourcesZip = nullptr, size_t resourcesZipLen = 0) {
auto actFactory = [](std::shared_ptr<celix::BundleContext> ctx) {
return new T{std::move(ctx)};
};
- return installBundle(name, std::move(actFactory), manifest, autoStart);
+ return installBundle(name, std::move(actFactory), std::move(manifest), autoStart, resourcesZip, resourcesZipLen);
}
- long installBundle(std::string name, std::function<celix::IBundleActivator*(std::shared_ptr<celix::BundleContext>)> actFactory, celix::Properties manifest = {}, bool autoStart = true);
+ long installBundle(
+ std::string name,
+ std::function<celix::IBundleActivator*(std::shared_ptr<celix::BundleContext>)> actFactory,
+ celix::Properties manifest = {},
+ bool autoStart = true,
+ const uint8_t *resourcesZip = nullptr,
+ const size_t resourcesZipLen = 0);
//long installBundle(const std::string &path);
@@ -76,6 +86,9 @@ namespace celix {
bool useBundle(long bndId, std::function<void(const celix::IBundle &bnd)> use) const;
int useBundles(std::function<void(const celix::IBundle &bnd)> use, bool includeFrameworkBundle = false) const;
+ std::string cacheDir() const;
+ std::string uuid() const;
+
//TODO trackBundles
//long bundleIdForName(const std::string &bndName) const;
diff --git a/libs/framework_cxx/src/Bundle.cc b/libs/framework_cxx/src/Bundle.cc
index 6f167f7..aba14a2 100644
--- a/libs/framework_cxx/src/Bundle.cc
+++ b/libs/framework_cxx/src/Bundle.cc
@@ -18,20 +18,30 @@
*/
#include <string>
+#include <sys/stat.h>
+#include <unistd.h>
#include "Bundle.h"
-bool celix::Bundle::has(const std::string &) const noexcept { return false; } //TODO
+bool celix::Bundle::hasCacheEntry(const std::string &path) const noexcept {
+ auto abs = absPathForCacheEntry(path);
+ struct stat st;
+ bool exists = stat(abs.c_str(), &st) == 0;
+ return exists;
+}
-bool celix::Bundle::isDir(const std::string &) const noexcept { return false; } //TODO
+bool celix::Bundle::isCacheEntryDir(const std::string &) const noexcept { return false; } //TODO
-bool celix::Bundle::isFile(const std::string &) const noexcept { return false; } //TODO
+bool celix::Bundle::isCacheEntryFile(const std::string &) const noexcept { return false; } //TODO
-std::vector <std::string> celix::Bundle::readDir(const std::string &) const noexcept { //TODO
+std::vector <std::string> celix::Bundle::readCacheDir(const std::string &) const noexcept { //TODO
return std::vector < std::string > {};
}
-const std::string& celix::Bundle::root() const noexcept { //TODO
- static std::string empty{};
- return empty;
+const std::string& celix::Bundle::cacheRoot() const noexcept {
+ return bundleCache;
+}
+
+std::string celix::Bundle::absPathForCacheEntry(const std::string &entryPath) const noexcept {
+ return bundleCache + "/" + entryPath;
}
\ No newline at end of file
diff --git a/libs/framework_cxx/src/Bundle.h b/libs/framework_cxx/src/Bundle.h
index 5541013..ce5e456 100644
--- a/libs/framework_cxx/src/Bundle.h
+++ b/libs/framework_cxx/src/Bundle.h
@@ -30,7 +30,9 @@ namespace celix {
class Bundle : public celix::IBundle {
public:
Bundle(long _bndId, celix::Framework *_fw, celix::Properties _manifest) :
- bndId{_bndId}, fw{_fw}, bndManifest{std::move(_manifest)}, bndState{BundleState::INSTALLED} {
+ bndId{_bndId}, fw{_fw}, bndManifest{std::move(_manifest)},
+ bundleCache{framework().cacheDir() + "/bundle" + std::to_string(_bndId)},
+ bndState{BundleState::INSTALLED} {
bndState.store(BundleState::INSTALLED, std::memory_order_release);
}
@@ -38,11 +40,12 @@ namespace celix {
Bundle& operator=(const Bundle&) = delete;
//resource part
- bool has(const std::string &) const noexcept override;
- bool isDir(const std::string &) const noexcept override;
- bool isFile(const std::string &) const noexcept override;
- std::vector <std::string> readDir(const std::string &) const noexcept override;
- const std::string &root() const noexcept override;
+ bool hasCacheEntry(const std::string &) const noexcept override;
+ bool isCacheEntryDir(const std::string &) const noexcept override;
+ bool isCacheEntryFile(const std::string &) const noexcept override;
+ std::string absPathForCacheEntry(const std::string &) const noexcept override;
+ std::vector <std::string> readCacheDir(const std::string &) const noexcept override;
+ const std::string &cacheRoot() const noexcept override;
//bundle part
bool isFrameworkBundle() const noexcept override { return false; }
@@ -58,7 +61,7 @@ namespace celix {
}
const std::string &group() const noexcept override {
- return bndManifest.at(celix::MANIFEST_BUNDLE_SYMBOLIC_NAME);
+ return bndManifest.at(celix::MANIFEST_BUNDLE_GROUP);
}
const std::string &version() const noexcept override { return bndManifest.at(celix::MANIFEST_BUNDLE_VERSION); }
@@ -81,6 +84,7 @@ namespace celix {
const long bndId;
celix::Framework *const fw;
const celix::Properties bndManifest;
+ const std::string bundleCache;
std::atomic<BundleState> bndState;
};
diff --git a/libs/framework_cxx/src/BundleController.h b/libs/framework_cxx/src/BundleController.h
index 3f4e1b7..1228066 100644
--- a/libs/framework_cxx/src/BundleController.h
+++ b/libs/framework_cxx/src/BundleController.h
@@ -20,7 +20,14 @@
#ifndef CXX_CELIX_BUNDLECONTROLLER_H
#define CXX_CELIX_BUNDLECONTROLLER_H
+#include <fstream>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
#include <glog/logging.h>
+#include <zip.h>
+#include <dirent.h>
#include "celix/IBundle.h"
#include "celix/BundleContext.h"
@@ -32,8 +39,13 @@ namespace celix {
BundleController(
std::function<celix::IBundleActivator*(std::shared_ptr<celix::BundleContext>)> _actFactory,
std::shared_ptr<celix::Bundle> _bnd,
- std::shared_ptr<celix::BundleContext> _ctx) :
- actFactory{std::move(_actFactory)}, bnd{std::move(_bnd)}, ctx{std::move(_ctx)} {}
+ std::shared_ptr<celix::BundleContext> _ctx,
+ const uint8_t *rZip,
+ size_t rZipLen) :
+ actFactory{std::move(_actFactory)}, bnd{std::move(_bnd)}, ctx{std::move(_ctx)}, resourcesZip{rZip}, resourcesZipLen{rZipLen} {}
+
+ BundleController(const BundleController&) = delete;
+ BundleController& operator=(const BundleController&) = delete;
//specific part
bool transitionTo(BundleState desired) {
@@ -44,13 +56,15 @@ namespace celix {
//nop
success = true;
} else if (state == BundleState::INSTALLED && desired == BundleState::ACTIVE) {
- act = std::unique_ptr<celix::IBundleActivator>{actFactory(ctx)};
- bnd->setState(BundleState::ACTIVE);
- success = true;
+ success = createBundleCache();
+ if (success) {
+ act = std::unique_ptr<celix::IBundleActivator>{actFactory(ctx)};
+ bnd->setState(BundleState::ACTIVE);
+ }
} else if (state == BundleState::ACTIVE && desired == BundleState::INSTALLED ) {
act = nullptr;
- bnd->setState(BundleState::INSTALLED);
- success = true;
+ success = deleteBundleCache();
+ bnd->setState(BundleState::INSTALLED); //note still going to installed
} else {
//LOG(ERROR) << "Unexpected desired state " << desired << " from state " << bndState << std::endl;
LOG(ERROR) << "Unexpected desired/form state combination " << std::endl;
@@ -61,9 +75,177 @@ namespace celix {
std::shared_ptr<celix::Bundle> bundle() const { return bnd; }
std::shared_ptr<celix::BundleContext> context() const { return ctx; }
private:
+ bool createBundleCache() {
+ auto bundleCache = bundle()->cacheRoot();
+ bool success = createDir(bundleCache);
+ if (success) {
+ //auto manifestPath = bundle()->absPathForCacheEntry("META-INF/manifest.mf");
+ //TODO success = celix::storeProperties(bundle()->manifest(), manifestPath);
+ }
+ if (success) {
+ success = extractResources(bundleCache);
+ }
+ return success;
+ }
+
+ bool deleteBundleCache() {
+ return deleteDir(bundle()->cacheRoot());
+ }
+
+ bool deleteDir(const std::string &path) {
+ bool success = false;
+ DIR *dir;
+ dir = opendir(path.c_str());
+ if (dir == NULL) {
+ LOG(WARNING) << "Cannot delete dir " << path << ". " << strerror(errno) << std::endl;
+ } else {
+ struct dirent* dent = NULL;
+ errno = 0;
+ dent = readdir(dir);
+ while (errno == 0 && dent != NULL) {
+ if ((strcmp((dent->d_name), ".") != 0) && (strcmp((dent->d_name), "..") != 0)) {
+ char subdir[512];
+ snprintf(subdir, 512, "%s/%s", path.c_str(), dent->d_name);
+
+ struct stat st;
+ if (stat(subdir, &st) == 0) {
+ if (S_ISDIR (st.st_mode)) {
+ std::string sd{subdir};
+ success = deleteDir(sd);
+ } else {
+ if (remove(subdir) != 0) {
+ LOG(WARNING) << "Cannot delete dir " << path << ". " << strerror(errno) << std::endl;
+ }
+ }
+ }
+ }
+ errno = 0;
+ dent = readdir(dir);
+ }
+
+ if (errno != 0) {
+ LOG(WARNING) << "Cannot delete dir " << path << ". " << strerror(errno) << std::endl;
+ } else if (closedir(dir) != 0) {
+ LOG(WARNING) << "Cannot close dir " << path << ". " << strerror(errno) << std::endl;
+ } else {
+ if (rmdir(path.c_str()) != 0) {
+ LOG(WARNING) << "Cannot delete dir " << path << ". " << strerror(errno) << std::endl;
+ } else {
+ success = true;
+ }
+ }
+ }
+
+ return success;
+ }
+
+ bool createDir(const std::string &path) {
+ bool success = false;
+
+ struct stat st;
+ bool exists = stat(path.c_str(), &st) == 0 && S_ISDIR(st.st_mode);
+
+ if (!exists) {
+ const char *slashAt = strrchr(path.c_str(), '/');
+ if (slashAt == nullptr) {
+ //no sub dir
+ if (mkdir(path.c_str(), S_IRWXU) == 0) {
+ success = true;
+ } else {
+ LOG(WARNING) << "Cannot create dir " << path << ". " << strerror(errno) << std::endl;
+ }
+ } else {
+ std::string subdir = path.substr(0, slashAt - path.c_str());
+ bool subdirCreated = createDir(subdir);
+ if (subdirCreated) {
+ if (mkdir(path.c_str(), S_IRWXU) == 0) {
+ success = true;
+ } else {
+ LOG(WARNING) << "Cannot create dir " << path << ". " << strerror(errno) << std::endl;
+ }
+ } else {
+ //nop, error should be reported in the recursion
+ }
+ }
+ } else {
+ //exists, so true
+ success = true;
+ }
+
+
+ return success;
+ }
+
+ bool extractResources(const std::string &bundleCache) {
+ bool success = false;
+ if (resourcesZip != nullptr) {
+ zip_error_t error;
+ zip_source_t *source = zip_source_buffer_create(resourcesZip, resourcesZipLen, 1, &error);
+ if (source != nullptr) {
+ zip_t *zip = zip_open_from_source(source, ZIP_RDONLY, &error);
+ if (zip != nullptr) {
+ extractZipSource(zip, bundleCache);
+ //zip_close(zip); ? not needed on zip_source ?
+ zip_source_close(source);
+ success = true;
+ } else {
+ LOG(WARNING) << "Cannot create zip from source: " << zip_error_strerror(&error) << std::endl;
+ }
+ } else {
+ LOG(WARNING) << "Cannot create zip source: " << zip_error_strerror(&error) << std::endl;
+ }
+ } else {
+ //no resources
+ success = true;
+ }
+ return success;
+ }
+
+ bool extractZipSource(zip_t *zip, const std::string &bundleCache) {
+ bool succes = true;
+ char buf[128];
+ zip_int64_t nrOfEntries = zip_get_num_entries(zip, 0);
+ for (int i = 0; i < nrOfEntries; ++i) {
+ zip_stat_t st;
+ zip_stat_index(zip, i, 0, &st);
+ if (st.name[strlen(st.name) - 1] == '/') {
+ //dir
+ //TODO
+ LOG(ERROR) << "TODO extract dirs" << std::endl;
+ succes = false;
+ } else {
+ //file
+ zip_file_t *f = zip_fopen_index(zip, i, 0);
+ if (f != nullptr) {
+ std::ofstream outf;
+ std::string p = bundleCache + "/" + st.name;
+ outf.open(p);
+ if (!outf.fail()) {
+ zip_int64_t read = zip_fread(f, buf, 128);
+ while (read != 0) {
+ outf.write(buf, read);
+ read = zip_fread(f, buf, 128);
+ }
+ outf.close();
+ } else {
+ LOG(WARNING) << "Cannot open file '" << p << "': " << std::endl;
+ }
+ zip_fclose(f);
+ } else {
+ LOG(WARNING) << "Cannot read file from zip: " << zip_strerror(zip) << std::endl;
+ succes = false;
+ break;
+ }
+ }
+ }
+ return succes;
+ }
+
const std::function<celix::IBundleActivator*(std::shared_ptr<celix::BundleContext>)> actFactory;
const std::shared_ptr<celix::Bundle> bnd;
const std::shared_ptr<celix::BundleContext> ctx;
+ const uint8_t *resourcesZip;
+ const size_t resourcesZipLen;
mutable std::mutex mutex{};
std::unique_ptr<celix::IBundleActivator> act{nullptr};
diff --git a/libs/framework_cxx/src/Framework.cc b/libs/framework_cxx/src/Framework.cc
index a96ce86..0b1d856 100644
--- a/libs/framework_cxx/src/Framework.cc
+++ b/libs/framework_cxx/src/Framework.cc
@@ -21,6 +21,8 @@
*under the License.
*/
+#include "celix/Framework.h"
+
#include <unordered_map>
#include <mutex>
#include <iostream>
@@ -32,15 +34,20 @@
#include <linux/limits.h>
#include <glog/logging.h>
-
-#include "celix/Framework.h"
+#include <uuid/uuid.h>
#include "BundleController.h"
+
+extern bool extractBundle(const char *bundleZip, const char *targetPath); //FROM miniunz.c
+
+
struct StaticBundleEntry {
const std::string symbolicName;
const celix::Properties manifest;
const std::function<celix::IBundleActivator*(std::shared_ptr<celix::BundleContext>)> activatorFactory;
+ const uint8_t *resourcesZip;
+ const size_t resourcesZipLen;
};
static struct {
@@ -55,7 +62,9 @@ static void unregisterFramework(celix::Framework *fw);
class celix::Framework::Impl : public IBundle {
public:
- Impl(celix::Framework *_fw, celix::Properties _config) : fw{_fw}, config{std::move(_config)}, bndManifest{createManifest()}, cwd{createCwd()} {}
+ Impl(celix::Framework *_fw, celix::Properties _config) : fw{_fw}, config{std::move(_config)}, bndManifest{createManifest()}, cwd{cwdString()}, fwUUID{uuidString()}{
+ startFramework();
+ }
Impl(const Impl&) = delete;
Impl& operator=(const Impl&) = delete;
@@ -78,8 +87,13 @@ public:
return result;
}
- long installBundle(std::string symbolicName, std::function<celix::IBundleActivator*(std::shared_ptr<celix::BundleContext>)> actFactory, celix::Properties manifest, bool autoStart) {
- //TODO if activator is nullptr -> use empty activator
+ long installBundle(
+ std::string symbolicName,
+ std::function<celix::IBundleActivator*(std::shared_ptr<celix::BundleContext>)> actFactory,
+ celix::Properties manifest,
+ bool autoStart,
+ const uint8_t *resourcesZip,
+ size_t resourcesZipLen) {
//TODO on separate thread ?? specific bundle resolve thread ??
long bndId = -1L;
if (symbolicName.empty()) {
@@ -104,7 +118,7 @@ public:
bndId = bundles.nextBundleId++;
auto bnd = std::shared_ptr<celix::Bundle>{new celix::Bundle{bndId, this->fw, std::move(manifest)}};
auto ctx = std::shared_ptr<celix::BundleContext>{new celix::BundleContext{bnd}};
- bndController = std::shared_ptr<celix::BundleController>{new celix::BundleController{std::move(actFactory), bnd, ctx}};
+ bndController = std::shared_ptr<celix::BundleController>{new celix::BundleController{std::move(actFactory), bnd, ctx, resourcesZip, resourcesZipLen}};
bundles.entries.emplace(std::piecewise_construct,
std::forward_as_tuple(bndId),
std::forward_as_tuple(bndController));
@@ -243,11 +257,15 @@ public:
//resource bundle part
long id() const noexcept override { return 1L /*note registry empty bundle is id 0, framework is id 1*/; }
- bool has(const std::string&) const noexcept override { return false; }
- bool isDir(const std::string&) const noexcept override { return false; }
- bool isFile(const std::string&) const noexcept override { return false; }
- std::vector<std::string> readDir(const std::string&) const noexcept override { return std::vector<std::string>{};}
- const std::string& root() const noexcept override { //TODO
+ bool hasCacheEntry(const std::string &) const noexcept override { return false; }
+ bool isCacheEntryDir(const std::string &) const noexcept override { return false; }
+ bool isCacheEntryFile(const std::string &) const noexcept override { return false; }
+
+ //virtual bool storeResource(const std::string &path, std::ostream content) noexcept = 0;
+ //virtual std::istream open(const std::string &path) const noexcept = 0;
+ //virtual std::fstream open(const std::string &path) noexcept = 0;
+ std::string absPathForCacheEntry(const std::string &) const noexcept override { return {}; }
+ const std::string& cacheRoot() const noexcept override { //TODO
return cwd;
}
@@ -263,7 +281,25 @@ public:
bool isValid() const noexcept override { return true; }
celix::Framework& framework() const noexcept override { return *fw; }
+ std::string cacheDir() const {
+ return cwd + "/.cache"; //TODO make configurable
+ }
+
+ std::vector<std::string> readCacheDir(const std::string &) const noexcept override { return {}; } //TODO
+
+ std::string uuid() const {
+ return fwUUID;
+ }
+
+ bool startFramework() {
+ //TODO create cache dir using a process id (and lock file?).
+ //Maybe also move to /var/cache or /tmp and when framework stop delete all framework caches of not running processes
+ std::cout << "Celix Framework Started";
+ return true;
+ }
+
bool stopFramework() {
+ //TODO create cache dir
std::lock_guard<std::mutex> lck{shutdown.mutex};
if (!shutdown.shutdownStarted) {
shutdown.future = std::async(std::launch::async, [this]{
@@ -279,6 +315,7 @@ public:
shutdown.shutdownStarted = true;
shutdown.cv.notify_all();
}
+ std::cout << "Celix Framework Stopped";
return true;
}
@@ -299,7 +336,15 @@ private:
return m;
}
- std::string createCwd() {
+ std::string uuidString() {
+ char uuidStr[37];
+ uuid_t uuid;
+ uuid_generate_time_safe(uuid);
+ uuid_unparse(uuid, uuidStr);
+ return std::string{uuidStr};
+ }
+
+ std::string cwdString() {
char workdir[PATH_MAX];
if (getcwd(workdir, sizeof(workdir)) != NULL) {
return std::string{workdir};
@@ -313,6 +358,7 @@ private:
const celix::Properties config;
const celix::Properties bndManifest;
const std::string cwd;
+ const std::string fwUUID;
struct {
@@ -352,8 +398,14 @@ celix::Framework::Framework(Framework &&rhs) = default;
celix::Framework& celix::Framework::operator=(Framework&& rhs) = default;
-long celix::Framework::installBundle(std::string name, std::function<celix::IBundleActivator*(std::shared_ptr<celix::BundleContext>)> actFactory, celix::Properties manifest, bool autoStart) {
- return pimpl->installBundle(std::move(name), actFactory, std::move(manifest), autoStart);
+long celix::Framework::installBundle(
+ std::string name,
+ std::function<celix::IBundleActivator*(std::shared_ptr<celix::BundleContext>)> actFactory,
+ celix::Properties manifest,
+ bool autoStart,
+ const uint8_t *resourcesZip,
+ size_t resourcesZipLen) {
+ return pimpl->installBundle(std::move(name), std::move(actFactory), std::move(manifest), autoStart, resourcesZip, resourcesZipLen);
}
@@ -373,6 +425,14 @@ bool celix::Framework::uninstallBundle(long bndId) { return pimpl->uninstallBund
celix::ServiceRegistry& celix::Framework::registry(const std::string &lang) { return pimpl->registry(lang); }
bool celix::Framework::waitForShutdown() const { return pimpl->waitForShutdown(); }
+std::string celix::Framework::cacheDir() const {
+ return pimpl->cacheDir();
+}
+
+std::string celix::Framework::uuid() const {
+ return pimpl->uuid();
+}
+
/***********************************************************************************************************************
* Celix 'global' functions
@@ -381,19 +441,26 @@ bool celix::Framework::waitForShutdown() const { return pimpl->waitForShutdown()
void celix::registerStaticBundle(
std::string symbolicName,
std::function<celix::IBundleActivator*(std::shared_ptr<celix::BundleContext>)> bundleActivatorFactory,
- celix::Properties manifest) {
+ celix::Properties manifest,
+ const uint8_t *resourcesZip,
+ size_t resourcesZipLen) {
std::lock_guard<std::mutex> lck{staticRegistry.mutex};
for (auto fw : staticRegistry.frameworks) {
- fw->installBundle(symbolicName, bundleActivatorFactory, manifest);
+ fw->installBundle(symbolicName, bundleActivatorFactory, manifest, true, resourcesZip, resourcesZipLen);
}
- staticRegistry.bundles.emplace_back(StaticBundleEntry{.symbolicName = std::move(symbolicName), .manifest = std::move(manifest), .activatorFactory = std::move(bundleActivatorFactory)});
+ staticRegistry.bundles.emplace_back(StaticBundleEntry{
+ .symbolicName = std::move(symbolicName),
+ .manifest = std::move(manifest),
+ .activatorFactory = std::move(bundleActivatorFactory),
+ .resourcesZip = resourcesZip,
+ .resourcesZipLen = resourcesZipLen});
}
static void registerFramework(celix::Framework *fw) {
std::lock_guard<std::mutex> lck{staticRegistry.mutex};
staticRegistry.frameworks.insert(fw);
for (auto &entry : staticRegistry.bundles) {
- fw->installBundle(entry.symbolicName, entry.activatorFactory, entry.manifest);
+ fw->installBundle(entry.symbolicName, entry.activatorFactory, entry.manifest, true, entry.resourcesZip, entry.resourcesZipLen);
}
}
diff --git a/libs/registry/CMakeLists.txt b/libs/registry/CMakeLists.txt
index 2a279de..5880f52 100644
--- a/libs/registry/CMakeLists.txt
+++ b/libs/registry/CMakeLists.txt
@@ -15,11 +15,10 @@
# specific language governing permissions and limitations
# under the License.
-find_package(glog REQUIRED)
-
add_library(celix_registry STATIC
src/ServiceRegistry.cc
src/Filter.cc
+ src/Properties.cc
)
target_include_directories(celix_registry PRIVATE src)
target_include_directories(celix_registry PUBLIC include)
diff --git a/libs/registry/include/celix/IResourceBundle.h b/libs/registry/include/celix/IResourceBundle.h
index 38b76b3..2b97c65 100644
--- a/libs/registry/include/celix/IResourceBundle.h
+++ b/libs/registry/include/celix/IResourceBundle.h
@@ -31,16 +31,17 @@ namespace celix {
virtual long id() const noexcept = 0;
- virtual const std::string& root() const noexcept = 0;
+ virtual const std::string& cacheRoot() const noexcept = 0;
- virtual bool has(const std::string &path) const noexcept = 0;
- virtual bool isDir(const std::string &path) const noexcept = 0;
- virtual bool isFile(const std::string &path) const noexcept = 0;
+ virtual bool hasCacheEntry(const std::string &entryPath) const noexcept = 0;
+ virtual bool isCacheEntryDir(const std::string &path) const noexcept = 0;
+ virtual bool isCacheEntryFile(const std::string &path) const noexcept = 0;
//virtual bool storeResource(const std::string &path, std::ostream content) noexcept = 0;
//virtual std::istream open(const std::string &path) const noexcept = 0;
//virtual std::fstream open(const std::string &path) noexcept = 0;
- virtual std::vector<std::string> readDir(const std::string &path) const noexcept = 0;
+ virtual std::string absPathForCacheEntry(const std::string &entry) const noexcept = 0;
+ virtual std::vector<std::string> readCacheDir(const std::string &path) const noexcept = 0;
};
diff --git a/libs/registry/include/celix/Properties.h b/libs/registry/include/celix/Properties.h
index 1002bfc..649cf4c 100644
--- a/libs/registry/include/celix/Properties.h
+++ b/libs/registry/include/celix/Properties.h
@@ -56,11 +56,11 @@ namespace celix {
return std::stoul(val, nullptr, 10);
}
- /*TODO
+
celix::Properties loadProperties(const std::string &path);
- celix::Properties loadProperties(std::istream stream);
- bool storeProperties(const celix::Properties &props, const std::string &path);
- */
+ celix::Properties loadProperties(std::istream &stream);
+ //bool storeProperties(const celix::Properties &props, const std::string &path); TODO
+ //bool storeProperties(const celix::Properties &props, std::ofstream &stream); TODO
}
#endif //CXX_CELIX_PROPERTIES_H
diff --git a/libs/registry/src/Properties.cc b/libs/registry/src/Properties.cc
new file mode 100644
index 0000000..403dee7
--- /dev/null
+++ b/libs/registry/src/Properties.cc
@@ -0,0 +1,215 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements. See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership. The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ */
+
+#include <fstream>
+#include <string>
+#include <cstring>
+
+#include <glog/logging.h>
+
+#include "celix/Properties.h"
+
+#define MALLOC_BLOCK_SIZE 5
+
+
+static char * utils_stringTrim(char * string) {
+ char* copy = string;
+
+ char *end;
+ // Trim leading space
+ while (isspace(*copy)) {
+ copy++;
+ }
+
+ // Trim trailing space
+ end = copy + strlen(copy) - 1;
+ while(end > copy && isspace(*end)) {
+ *(end) = '\0';
+ end--;
+ }
+
+ if (copy != string) {
+ //beginning whitespaces -> move char in copy to to begin string
+ //This to ensure free still works on the same pointer.
+ char* nstring = string;
+ while(*copy != '\0') {
+ *(nstring++) = *(copy++);
+ }
+ (*nstring) = '\0';
+ }
+
+ return string;
+}
+
+static void updateBuffers(char **key, char ** value, char **output, int outputPos, int *key_len, int *value_len) {
+ if (*output == *key) {
+ if (outputPos == (*key_len) - 1) {
+ (*key_len) += MALLOC_BLOCK_SIZE;
+ *key = (char*)realloc(*key, *key_len);
+ *output = *key;
+ }
+ }
+ else {
+ if (outputPos == (*value_len) - 1) {
+ (*value_len) += MALLOC_BLOCK_SIZE;
+ *value = (char*)realloc(*value, *value_len);
+ *output = *value;
+ }
+ }
+}
+
+static void parseLine(const char* line, celix::Properties &props) {
+ int linePos = 0;
+ bool precedingCharIsBackslash = false;
+ bool isComment = false;
+ int outputPos = 0;
+ char *output = NULL;
+ int key_len = MALLOC_BLOCK_SIZE;
+ int value_len = MALLOC_BLOCK_SIZE;
+ linePos = 0;
+ precedingCharIsBackslash = false;
+ isComment = false;
+ output = NULL;
+ outputPos = 0;
+
+ //Ignore empty lines
+ if (line[0] == '\n' && line[1] == '\0') {
+ return;
+ }
+
+ char *key = (char*)calloc(1, key_len);
+ char *value = (char*)calloc(1, value_len);
+ key[0] = '\0';
+ value[0] = '\0';
+
+ while (line[linePos] != '\0') {
+ if (line[linePos] == ' ' || line[linePos] == '\t') {
+ if (output == NULL) {
+ //ignore
+ linePos += 1;
+ continue;
+ }
+ }
+ else {
+ if (output == NULL) {
+ output = key;
+ }
+ }
+ if (line[linePos] == '=' || line[linePos] == ':' || line[linePos] == '#' || line[linePos] == '!') {
+ if (precedingCharIsBackslash) {
+ //escaped special character
+ output[outputPos++] = line[linePos];
+ updateBuffers(&key, &value, &output, outputPos, &key_len, &value_len);
+ precedingCharIsBackslash = false;
+ }
+ else {
+ if (line[linePos] == '#' || line[linePos] == '!') {
+ if (outputPos == 0) {
+ isComment = true;
+ break;
+ }
+ else {
+ output[outputPos++] = line[linePos];
+ updateBuffers(&key, &value, &output, outputPos, &key_len, &value_len);
+ }
+ }
+ else { // = or :
+ if (output == value) { //already have a seperator
+ output[outputPos++] = line[linePos];
+ updateBuffers(&key, &value, &output, outputPos, &key_len, &value_len);
+ }
+ else {
+ output[outputPos++] = '\0';
+ updateBuffers(&key, &value, &output, outputPos, &key_len, &value_len);
+ output = value;
+ outputPos = 0;
+ }
+ }
+ }
+ }
+ else if (line[linePos] == '\\') {
+ if (precedingCharIsBackslash) { //double backslash -> backslash
+ output[outputPos++] = '\\';
+ updateBuffers(&key, &value, &output, outputPos, &key_len, &value_len);
+ }
+ precedingCharIsBackslash = true;
+ }
+ else { //normal character
+ precedingCharIsBackslash = false;
+ output[outputPos++] = line[linePos];
+ updateBuffers(&key, &value, &output, outputPos, &key_len, &value_len);
+ }
+ linePos += 1;
+ }
+ if (output != NULL) {
+ output[outputPos] = '\0';
+ }
+
+ if (!isComment) {
+ //printf("putting 'key'/'value' '%s'/'%s' in properties\n", utils_stringTrim(key), utils_stringTrim(value));
+ props[std::string{utils_stringTrim(key)}] = std::string{utils_stringTrim(value)};
+ }
+ if(key) {
+ free(key);
+ }
+ if(value) {
+ free(value);
+ }
+
+}
+
+celix::Properties celix::loadProperties(const std::string &path) {
+ std::ifstream file;
+ file.open(path);
+ if (file.fail()) {
+ LOG(WARNING) << "Cannot open file " << path << ". " << file.failbit << std::endl;
+ return celix::Properties{};
+ } else {
+ return celix::loadProperties(file);
+ }
+}
+
+celix::Properties celix::loadProperties(std::istream &stream) {
+ celix::Properties props{};
+
+ if (!stream.fail()) {
+ stream.seekg(0, stream.end);
+ long size = stream.tellg();
+ stream.seekg(0, stream.beg);
+
+ if (size > 0){
+ while (!stream.eof()) {
+ std::string line;
+ std::getline(stream, line);
+ parseLine(line.c_str(), props);
+ }
+ }
+ }
+
+ //TODO howto singal an error with parsing ...
+ return props;
+}
+
+//bool celix::storeProperties(const celix::Properties &props, const std::string &path) {
+// return false; //TODO
+//}
+//
+//bool celix::storeProperties(const celix::Properties &props, std::ofstream &stream) {
+// return false; //TODO
+//}
\ No newline at end of file
diff --git a/libs/registry/src/ServiceRegistry.cc b/libs/registry/src/ServiceRegistry.cc
index a7465e2..001b08e 100644
--- a/libs/registry/src/ServiceRegistry.cc
+++ b/libs/registry/src/ServiceRegistry.cc
@@ -42,18 +42,19 @@ namespace {
long id() const noexcept override { return 0; }
- const std::string& root() const noexcept override {
+ const std::string& cacheRoot() const noexcept override {
static std::string empty{};
return empty;
}
- bool has(const std::string&) const noexcept override { return false; }
- bool isDir(const std::string&) const noexcept override { return false; }
- bool isFile(const std::string&) const noexcept override { return false; }
+ bool hasCacheEntry(const std::string&) const noexcept override { return false; }
+ bool isCacheEntryDir(const std::string&) const noexcept override { return false; }
+ bool isCacheEntryFile(const std::string&) const noexcept override { return false; }
//std::istream& open(const std::string &path) override {}
//std::fstream& open(const std::string &path) override {}
- std::vector<std::string> readDir(const std::string&) const noexcept override { return std::vector<std::string>{};}
+ std::string absPathForCacheEntry(const std::string &) const noexcept override { return {}; }
+ std::vector<std::string> readCacheDir(const std::string&) const noexcept override { return std::vector<std::string>{};}
};
struct SvcEntry {