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 cc671b6deb823fa06c79b1f88ac6a732eebab261 Author: Pepijn Noltes <pepijnnol...@gmail.com> AuthorDate: Sun Jan 6 20:29:25 2019 +0100 CELIX-438: Adds a assert and warning log for wrong useage of the use(Funcion)Service(s) calls and adds some unit tests for the C++ shell. --- CMakeLists.txt | 2 +- bundles/shell/cxx_shell/CMakeLists.txt | 6 +- bundles/shell/cxx_shell/gtest/CMakeLists.txt | 7 +- bundles/shell/cxx_shell/gtest/src/Shell_tests.cc | 163 ++++++++++++++++++ bundles/shell/cxx_shell/src/QueryCommand.cc | 2 +- libs/CMakeLists.txt | 6 +- libs/framework_cxx/gtest/src/Framework_tests.cc | 2 +- libs/framework_cxx/include/celix/BundleContext.h | 29 +++- libs/framework_cxx/include/celix/Framework.h | 2 + libs/framework_cxx/src/Bundle.h | 6 +- libs/framework_cxx/src/BundleContext.cc | 7 +- libs/framework_cxx/src/BundleController.h | 2 +- libs/framework_cxx/src/Framework.cc | 209 ++++++++++++----------- libs/registry/CMakeLists.txt | 5 +- libs/registry/gtest/CMakeLists.txt | 3 +- libs/registry/gtest/src/Registry_tests.cc | 2 +- libs/registry/gtest/src/Utils_tests.cc | 56 ++++++ libs/registry/include/celix/Constants.h | 6 +- libs/registry/include/celix/ServiceRegistry.h | 47 +++-- libs/registry/include/celix/Utils.h | 46 +++-- libs/registry/src/ServiceRegistry.cc | 44 +++-- libs/registry/src/Utils.cc | 51 ++++++ 22 files changed, 518 insertions(+), 185 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 968e74c..f1807f7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,7 +56,7 @@ option(ENABLE_TESTING "Enables unit testing" ON) if (ENABLE_TESTING) enable_testing() include(cmake/celix_project/AddGTest.cmake) - include(cmake/celix_project/AddCppUTest.cmake) + #include(cmake/celix_project/AddCppUTest.cmake) endif () include(cmake/celix_project/AddGLog.cmake) include(cmake/celix_project/AddLibzip.cmake) diff --git a/bundles/shell/cxx_shell/CMakeLists.txt b/bundles/shell/cxx_shell/CMakeLists.txt index c82d2ef..3dced30 100644 --- a/bundles/shell/cxx_shell/CMakeLists.txt +++ b/bundles/shell/cxx_shell/CMakeLists.txt @@ -56,6 +56,6 @@ else () endif () -#if (ENABLE_TESTING) -# add_subdirectory(gtest) -#endif () \ No newline at end of file +if (ENABLE_TESTING) + add_subdirectory(gtest) +endif () \ No newline at end of file diff --git a/bundles/shell/cxx_shell/gtest/CMakeLists.txt b/bundles/shell/cxx_shell/gtest/CMakeLists.txt index b4a7204..c95f364 100644 --- a/bundles/shell/cxx_shell/gtest/CMakeLists.txt +++ b/bundles/shell/cxx_shell/gtest/CMakeLists.txt @@ -17,9 +17,10 @@ set(SOURCES src/main.cc + src/Shell_tests.cc ) add_executable(celix_shell_cxx_tests ${SOURCES}) -target_link_libraries(celix_shell_cxx_tests PRIVATE gtest celix_framework_cxx celix_shell_cxx) +target_link_libraries(celix_shell_cxx_tests PRIVATE gtest celix_framework_cxx celix_cxx_shell celix_cxx_shell_api glog::glog) -add_test(NAME celix_shell_cxx_tests COMMAND celix_shell_cxx_tests) -SETUP_TARGET_FOR_COVERAGE(celix_shell_cxx_tests_cov celix_shell_cxx_tests ${CMAKE_BINARY_DIR}/coverage/celix_shell_cxx_tests/celix_shell_cxx_tests) \ No newline at end of file +add_test(NAME celix_cxx_shell_tests COMMAND celix_cxx_shell_tests) +SETUP_TARGET_FOR_COVERAGE(celix_cxx_shell_tests_cov celix_cxx_shell_tests ${CMAKE_BINARY_DIR}/coverage/celix_cxx_shell_tests/celix_cxx_shell_tests ..) \ No newline at end of file diff --git a/bundles/shell/cxx_shell/gtest/src/Shell_tests.cc b/bundles/shell/cxx_shell/gtest/src/Shell_tests.cc new file mode 100644 index 0000000..b6bbd8b --- /dev/null +++ b/bundles/shell/cxx_shell/gtest/src/Shell_tests.cc @@ -0,0 +1,163 @@ +/** + *Licensed to the Apache Software Foundation (ASF) under one + *or more contributor license agreements. See the NOTICE file + *distributed with this work for additional information + *regarding copyright ownership. The ASF licenses this file + *to you under the Apache License, Version 2.0 (the + *"License"); you may not use this file except in compliance + *with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + *Unless required by applicable law or agreed to in writing, + *software distributed under the License is distributed on an + *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + *specific language governing permissions and limitations + *under the License. + */ + +#include <sstream> + +#include "gtest/gtest.h" + +#include "celix/api.h" +#include "celix/IShellCommand.h" +#include "celix/IShell.h" + +class ShellTest : public ::testing::Test { +public: + ShellTest() {} + ~ShellTest(){} + + celix::Framework& framework() { return fw; } +private: + celix::Framework fw{}; +}; + + + + +TEST_F(ShellTest, AreCommandsAndShellRegistered) { + + std::string filter = std::string{"("} + celix::IShellCommand::COMMAND_NAME + "=lb)"; + long svcId = framework().context().findService<celix::IShellCommand>(filter); + EXPECT_TRUE(svcId > 0); + + filter = std::string{"("} + celix::SHELL_COMMAND_FUNCTION_COMMAND_NAME + "=help)"; + svcId = framework().context().findFunctionService<celix::ShellCommandFunction>(celix::SHELL_COMMAND_FUNCTION_SERVICE_FQN, filter); + EXPECT_TRUE(svcId > 0); + + filter = std::string{"("} + celix::SHELL_COMMAND_FUNCTION_COMMAND_NAME + "=inspect)"; + svcId = framework().context().findFunctionService<celix::ShellCommandFunction>(celix::SHELL_COMMAND_FUNCTION_SERVICE_FQN, filter); + EXPECT_TRUE(svcId > 0); + + filter = std::string{"("} + celix::SHELL_COMMAND_FUNCTION_COMMAND_NAME + "=query)"; + svcId = framework().context().findFunctionService<celix::ShellCommandFunction>(celix::SHELL_COMMAND_FUNCTION_SERVICE_FQN, filter); + EXPECT_TRUE(svcId > 0); + + filter = std::string{"("} + celix::SHELL_COMMAND_FUNCTION_COMMAND_NAME + "=stop)"; + svcId = framework().context().findFunctionService<celix::ShellCommandFunction>(celix::SHELL_COMMAND_FUNCTION_SERVICE_FQN, filter); + EXPECT_TRUE(svcId > 0); + + filter = std::string{"("} + celix::SHELL_COMMAND_FUNCTION_COMMAND_NAME + "=start)"; + svcId = framework().context().findFunctionService<celix::ShellCommandFunction>(celix::SHELL_COMMAND_FUNCTION_SERVICE_FQN, filter); + EXPECT_TRUE(svcId > 0); + + filter = std::string{"("} + celix::SHELL_COMMAND_FUNCTION_COMMAND_NAME + "=version)"; + svcId = framework().context().findFunctionService<celix::ShellCommandFunction>(celix::SHELL_COMMAND_FUNCTION_SERVICE_FQN, filter); + EXPECT_TRUE(svcId > 0); + + svcId = framework().context().findService<celix::IShell>(); + EXPECT_TRUE(svcId > 0); +}; + +TEST_F(ShellTest, LbCommandTest) { + std::stringstream ss{}; + std::function<void(celix::IShellCommand&)> useLb = [&ss](celix::IShellCommand& cmd){ + cmd.executeCommand("lb", {}, ss, ss); + }; + std::string filter = std::string{"("} + celix::SHELL_COMMAND_FUNCTION_COMMAND_NAME + "=lb)"; + bool called = framework().context().useService(useLb, filter); + EXPECT_TRUE(called); + + ss.flush(); + std::string output = ss.str(); + + size_t pos = output.find("1: Framework"); + EXPECT_LE(pos, output.size()); + pos = output.find("2: Shell"); + EXPECT_LE(pos, output.size()); + +} + +TEST_F(ShellTest, HelpCommandTest) { + std::string filter = std::string{"("} + celix::SHELL_COMMAND_FUNCTION_COMMAND_NAME + "=help)"; + { + //call general help + std::stringstream ss{}; + std::function<void(celix::ShellCommandFunction&)> useHelp = [&ss](celix::ShellCommandFunction& cmd){ + cmd("help", {}, ss, ss); + }; + bool called = framework().context().useFunctionService(celix::SHELL_COMMAND_FUNCTION_SERVICE_FQN, useHelp, filter); + EXPECT_TRUE(called); + + ss.flush(); + std::string output = ss.str(); + size_t pos = output.find("help"); //Expect help as command + EXPECT_LE(pos, output.size()); + pos = output.find("lb"); //Expect lb as command + EXPECT_LE(pos, output.size()); + pos = output.find("inspect"); //Expect inspect as command + EXPECT_LE(pos, output.size()); + } + + { + //call help with arg + std::stringstream ss{}; + std::vector<std::string> args{}; + std::function<void(celix::ShellCommandFunction&)> useHelp = [&ss, &args](celix::ShellCommandFunction& cmd){ + cmd("help", args, ss, ss); + }; + + args.emplace_back("lb"); + bool called = framework().context().useFunctionService(celix::SHELL_COMMAND_FUNCTION_SERVICE_FQN, useHelp, filter); + EXPECT_TRUE(called); + ss.flush(); + std::string output = ss.str(); + size_t pos = output.find("list bundles."); + EXPECT_LE(pos, output.size()); + + args.clear(); + args.emplace_back("unknown"); + ss.clear(); + called = framework().context().useFunctionService(celix::SHELL_COMMAND_FUNCTION_SERVICE_FQN, useHelp, filter); + EXPECT_TRUE(called); + ss.flush(); + output = ss.str(); + pos = output.find("not available"); + EXPECT_LE(pos, output.size()); + } +} + +TEST_F(ShellTest, VersionCommandTest) { + //NOTE that this also test if the resources zip usage (extender pattern). + + std::string filter = std::string{"("} + celix::SHELL_COMMAND_FUNCTION_COMMAND_NAME + "=version)"; + + //call general help + std::stringstream ss{}; + std::function<void(celix::ShellCommandFunction &)> useHelp = [&ss](celix::ShellCommandFunction &cmd) { + cmd("version", {}, ss, ss); + }; + bool called = framework().context().useFunctionService(celix::SHELL_COMMAND_FUNCTION_SERVICE_FQN, useHelp, filter); + EXPECT_TRUE(called); + + ss.flush(); + std::string output = ss.str(); + size_t pos = output.find("3.0.0"); //Expect 3.0.0 as version + EXPECT_LE(pos, output.size()); +} + + +//TODO rest of the commands \ No newline at end of file diff --git a/bundles/shell/cxx_shell/src/QueryCommand.cc b/bundles/shell/cxx_shell/src/QueryCommand.cc index 225709c..67206bc 100644 --- a/bundles/shell/cxx_shell/src/QueryCommand.cc +++ b/bundles/shell/cxx_shell/src/QueryCommand.cc @@ -45,7 +45,7 @@ namespace { svcName = cmdArgs[1]; filter = cmdArgs[2]; } else { - lang = celix::CXX_LANG; + lang = celix::C_AND_CXX_LANG_REG; svcName = cmdArgs[0]; filter = cmdArgs[1]; } diff --git a/libs/CMakeLists.txt b/libs/CMakeLists.txt index 928932a..c811b70 100644 --- a/libs/CMakeLists.txt +++ b/libs/CMakeLists.txt @@ -17,9 +17,9 @@ #utils, dfi and etcdlib are standalone #(e.g. no dependency on celix framework -add_subdirectory(utils) -add_subdirectory(dfi) -add_subdirectory(etcdlib) +#add_subdirectory(utils) +#add_subdirectory(dfi) +#add_subdirectory(etcdlib) #add_subdirectory(framework) diff --git a/libs/framework_cxx/gtest/src/Framework_tests.cc b/libs/framework_cxx/gtest/src/Framework_tests.cc index 88580f3..ab14713 100644 --- a/libs/framework_cxx/gtest/src/Framework_tests.cc +++ b/libs/framework_cxx/gtest/src/Framework_tests.cc @@ -40,7 +40,7 @@ TEST_F(FrameworkTest, CreateDestroy) { EXPECT_EQ(0, framework().listBundles(false).size()); bool isFramework = false; - framework().useBundle(0L, [&](const celix::IBundle &bnd) { + framework().useBundle(celix::FRAMEWORK_BUNDLE_ID, [&](const celix::IBundle &bnd) { isFramework = bnd.isFrameworkBundle(); }); EXPECT_TRUE(isFramework); diff --git a/libs/framework_cxx/include/celix/BundleContext.h b/libs/framework_cxx/include/celix/BundleContext.h index 296b5c0..21a879e 100644 --- a/libs/framework_cxx/include/celix/BundleContext.h +++ b/libs/framework_cxx/include/celix/BundleContext.h @@ -53,7 +53,7 @@ namespace celix { return registry().registerFunctionService(std::move(functionName), std::forward<F>(function), std::move(props), bundle()); } - //TODO register C services + //TODO reg svc fatories bool useBundle(long bndId, std::function<void(const celix::IBundle &bnd)> use) const { return bundle()->framework().useBundle(bndId, std::move(use)); @@ -163,7 +163,25 @@ namespace celix { return registry().useFunctionServices<F>(functionName, std::move(use), filter, bundle()); } - //TODO use C services + template<typename I> + long findService(const std::string &filter = "") { + return registry().findService<I>(filter); + } + + template<typename F> + long findFunctionService(const std::string &functionName, const std::string &filter = "") { + return registry().findFunctionService<F>(functionName, filter); + } + + template<typename I> + std::vector<long> findServices(const std::string &filter = "") { + return registry().findServices<I>(filter); + } + + template<typename F> + std::vector<long> findFunctionServices(const std::string &functionName, const std::string &filter = "") { + return registry().findFunctionServices<F>(functionName, filter); + } template<typename I> celix::ServiceTracker trackServices(celix::ServiceTrackerOptions<I> options = {}) { @@ -175,15 +193,8 @@ namespace celix { return registry().trackFunctionServices<F>(functionName, std::move(options), bundle()); } - //TODO track C Services - - //TODO track trackers - - //TODO track c trackers - celix::ServiceRegistry& registry() const; - celix::ServiceRegistry& cRegistry() const; private: class Impl; diff --git a/libs/framework_cxx/include/celix/Framework.h b/libs/framework_cxx/include/celix/Framework.h index 89e9a3b..22d6aef 100644 --- a/libs/framework_cxx/include/celix/Framework.h +++ b/libs/framework_cxx/include/celix/Framework.h @@ -89,6 +89,8 @@ namespace celix { std::string cacheDir() const; std::string uuid() const; + celix::BundleContext& context() const; + //TODO trackBundles //long bundleIdForName(const std::string &bndName) const; diff --git a/libs/framework_cxx/src/Bundle.h b/libs/framework_cxx/src/Bundle.h index ce5e456..1adb2c7 100644 --- a/libs/framework_cxx/src/Bundle.h +++ b/libs/framework_cxx/src/Bundle.h @@ -29,9 +29,9 @@ namespace celix { class Bundle : public celix::IBundle { public: - Bundle(long _bndId, celix::Framework *_fw, celix::Properties _manifest) : + Bundle(long _bndId, const std::string &cacheDir, celix::Framework *_fw, celix::Properties _manifest) : bndId{_bndId}, fw{_fw}, bndManifest{std::move(_manifest)}, - bundleCache{framework().cacheDir() + "/bundle" + std::to_string(_bndId)}, + bundleCache{cacheDir + "/bundle" + std::to_string(_bndId)}, bndState{BundleState::INSTALLED} { bndState.store(BundleState::INSTALLED, std::memory_order_release); } @@ -48,7 +48,7 @@ namespace celix { const std::string &cacheRoot() const noexcept override; //bundle part - bool isFrameworkBundle() const noexcept override { return false; } + bool isFrameworkBundle() const noexcept override { return bndId == 1 /*note 1 is the framework bundle id*/; } void *handle() const noexcept override { return nullptr; } //TODO diff --git a/libs/framework_cxx/src/BundleContext.cc b/libs/framework_cxx/src/BundleContext.cc index 5b9b192..045f2e3 100644 --- a/libs/framework_cxx/src/BundleContext.cc +++ b/libs/framework_cxx/src/BundleContext.cc @@ -26,15 +26,13 @@ namespace celix { public: Impl(std::shared_ptr<celix::IBundle> _bnd) : bnd{std::move(_bnd)}, - reg{&bnd->framework().registry(celix::CXX_LANG)}, - cReg(&bnd->framework().registry(celix::C_LANG)){} + reg{&bnd->framework().registry(celix::C_AND_CXX_LANG_REG)} {} Impl(const Impl&) = delete; Impl& operator=(const Impl&) = delete; const std::shared_ptr<celix::IBundle> bnd; celix::ServiceRegistry * const reg; //TODO make weak_ptr - celix::ServiceRegistry * const cReg; //TODO make weak_ptr }; } @@ -52,7 +50,4 @@ celix::ServiceRegistry& celix::BundleContext::registry() const { return *pimpl->reg; } -celix::ServiceRegistry& celix::BundleContext::cRegistry() const { - return *pimpl->cReg; -} diff --git a/libs/framework_cxx/src/BundleController.h b/libs/framework_cxx/src/BundleController.h index 1228066..01a821c 100644 --- a/libs/framework_cxx/src/BundleController.h +++ b/libs/framework_cxx/src/BundleController.h @@ -247,7 +247,7 @@ namespace celix { const uint8_t *resourcesZip; const size_t resourcesZipLen; - mutable std::mutex mutex{}; + mutable std::mutex mutex{}; //protects act and lock access to the bundle for state transitions std::unique_ptr<celix::IBundleActivator> act{nullptr}; }; } diff --git a/libs/framework_cxx/src/Framework.cc b/libs/framework_cxx/src/Framework.cc index 0740e5b..1b3ab87 100644 --- a/libs/framework_cxx/src/Framework.cc +++ b/libs/framework_cxx/src/Framework.cc @@ -62,28 +62,67 @@ static struct { static void registerFramework(celix::Framework *fw); 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{cwdString()}, fwUUID{uuidString()}{ - startFramework(); +namespace { + //some utils function + + celix::Properties createFwManifest() { + celix::Properties m{}; + m[celix::MANIFEST_BUNDLE_SYMBOLIC_NAME] = "framework"; + m[celix::MANIFEST_BUNDLE_NAME] = "Framework"; + m[celix::MANIFEST_BUNDLE_GROUP] = "Celix"; + m[celix::MANIFEST_BUNDLE_VERSION] = "3.0.0"; + return m; + } + + std::string genUUIDString() { + char uuidStr[37]; + uuid_t uuid; + uuid_generate(uuid); + uuid_unparse(uuid, uuidStr); + return std::string{uuidStr}; + } + + std::string createCwdString() { + char workdir[PATH_MAX]; + if (getcwd(workdir, sizeof(workdir)) != NULL) { + return std::string{workdir}; + } else { + return std::string{}; + } } + std::string genFwCacheDir(const celix::Properties &/*fwConfig*/) { + //TODO make configeruable + return createCwdString() + "/.cache"; + } +} + +class celix::Framework::Impl { +public: + Impl(celix::Framework *_fw, celix::Properties _config) : + fw{_fw}, + config{std::move(_config)}, + bndManifest{createFwManifest()}, + cwd{createCwdString()}, + fwUUID{genUUIDString()}, + fwCacheDir{genFwCacheDir(config)} {} + Impl(const Impl&) = delete; Impl& operator=(const Impl&) = delete; - ~Impl() { - stopFramework(); - waitForShutdown(); - } + ~Impl() {} std::vector<long> listBundles(bool includeFrameworkBundle) const { std::vector<long> result{}; - if (includeFrameworkBundle) { - result.push_back(0L); //framework bundle id - } std::lock_guard<std::mutex> lock{bundles.mutex}; for (auto &entry : bundles.entries) { - result.push_back(entry.first); + if (entry.second->bundle()->id() == FRAMEWORK_BUNDLE_ID) { + if (includeFrameworkBundle) { + result.push_back(entry.first); + } + } else { + result.push_back(entry.first); + } } std::sort(result.begin(), result.end());//ensure that the bundles are order by bndId -> i.e. time of install return result; @@ -118,7 +157,7 @@ public: std::lock_guard<std::mutex> lck{bundles.mutex}; bndId = bundles.nextBundleId++; - auto bnd = std::shared_ptr<celix::Bundle>{new celix::Bundle{bndId, this->fw, std::move(manifest)}}; + auto bnd = std::shared_ptr<celix::Bundle>{new celix::Bundle{bndId, this->cacheDir(), 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, resourcesZip, resourcesZipLen}}; bundles.entries.emplace(std::piecewise_construct, @@ -141,16 +180,15 @@ public: } bool startBundle(long bndId) { - if (bndId == this->fwBndId) { - //TODO - return false; + if (bndId == FRAMEWORK_BUNDLE_ID) { + return startFramework(); } else { return transitionBundleTo(bndId, BundleState::ACTIVE); } } bool stopBundle(long bndId) { - if (bndId == this->fwBndId) { + if (bndId == FRAMEWORK_BUNDLE_ID) { return stopFramework(); } else { return transitionBundleTo(bndId, BundleState::INSTALLED); @@ -201,26 +239,20 @@ public: bool useBundle(long bndId, std::function<void(const celix::IBundle &bnd)> use) const { bool called = false; - if (bndId == 0) { - //framework bundle - use(*this); - called = true; - } else { - std::shared_ptr<celix::BundleController> match = nullptr; - { - std::lock_guard<std::mutex> lck{bundles.mutex}; - auto it = bundles.entries.find(bndId); - if (it != bundles.entries.end()) { - match = it->second; - //TODO increase usage - } - } - if (match) { - use(*match->bundle()); - called = true; - //TODO decrease usage -> use shared ptr instead + std::shared_ptr<celix::BundleController> match = nullptr; + { + std::lock_guard<std::mutex> lck{bundles.mutex}; + auto it = bundles.entries.find(bndId); + if (it != bundles.entries.end()) { + match = it->second; + //TODO increase usage } } + if (match) { + use(*match->bundle()); + called = true; + //TODO decrease usage -> use shared ptr instead + } return called; } @@ -229,13 +261,16 @@ public: { std::lock_guard<std::mutex> lck{bundles.mutex}; for (const auto &it : bundles.entries) { - useBundles[it.first] = it.second; + if (it.second->bundle()->id() == FRAMEWORK_BUNDLE_ID) { + if (includeFramework) { + useBundles[it.first] = it.second; + } + } else { + useBundles[it.first] = it.second; + } } } - if (includeFramework) { - use(*this); - } for (const auto &cntr : useBundles) { use(*cntr.second->bundle()); } @@ -257,51 +292,45 @@ public: } } - //resource bundle part - long id() const noexcept override { return 1L /*note registry empty bundle is id 0, framework is id 1*/; } - 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; - } - - //bundle stuff - bool isFrameworkBundle() const noexcept override { return true; } - void* handle() const noexcept override { return nullptr; } - celix::BundleState state() const noexcept override { return BundleState::ACTIVE ; } - const std::string& name() const noexcept override { return bndManifest.at(celix::MANIFEST_BUNDLE_NAME); } - const std::string& symbolicName() const noexcept override { return bndManifest.at(celix::MANIFEST_BUNDLE_SYMBOLIC_NAME); } - const std::string& group() const noexcept override { return bndManifest.at(celix::MANIFEST_BUNDLE_GROUP); } - const std::string& version() const noexcept override { return bndManifest.at(celix::MANIFEST_BUNDLE_VERSION); } - const celix::Properties& manifest() const noexcept override { return bndManifest;} - 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 + return fwCacheDir; } - std::vector<std::string> readCacheDir(const std::string &) const noexcept override { return {}; } //TODO - std::string uuid() const { return fwUUID; } + celix::BundleContext& frameworkContext() const { + std::lock_guard<std::mutex> lck(bundles.mutex); + return *bundles.entries.at(celix::FRAMEWORK_BUNDLE_ID)->context(); + } + 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"; + + { + //Adding framework bundle to the bundles. + auto bnd = std::shared_ptr<celix::Bundle>{new celix::Bundle{FRAMEWORK_BUNDLE_ID, this->fwCacheDir, this->fw, bndManifest}}; + bnd->setState(BundleState::ACTIVE); + auto ctx = std::shared_ptr<celix::BundleContext>{new celix::BundleContext{bnd}}; + class EmptyActivator : public IBundleActivator {}; + std::function<celix::IBundleActivator*(std::shared_ptr<celix::BundleContext>)> fac = [](std::shared_ptr<celix::BundleContext>) { + return new EmptyActivator{}; + }; + auto ctr = std::shared_ptr<celix::BundleController>{new celix::BundleController{std::move(fac), std::move(bnd), std::move(ctx), nullptr, 0}}; + std::lock_guard<std::mutex> lck{bundles.mutex}; + bundles.entries[FRAMEWORK_BUNDLE_ID] = std::move(ctr); + } + + //TODO update state + + std::cout << "Celix Framework Started\n"; 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]{ @@ -317,7 +346,12 @@ public: shutdown.shutdownStarted = true; shutdown.cv.notify_all(); } - std::cout << "Celix Framework Stopped"; + + //TODO update bundle state + + //TODO clean cache dir + + std::cout << "Celix Framework Stopped\n"; return true; } @@ -329,38 +363,13 @@ public: return true; } private: - celix::Properties createManifest() { - celix::Properties m{}; - m[celix::MANIFEST_BUNDLE_SYMBOLIC_NAME] = "framework"; - m[celix::MANIFEST_BUNDLE_NAME] = "Framework"; - m[MANIFEST_BUNDLE_GROUP] = "Celix"; - m[celix::MANIFEST_BUNDLE_VERSION] = "3.0.0"; - return m; - } - std::string uuidString() { - char uuidStr[37]; - uuid_t uuid; - uuid_generate(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}; - } else { - return std::string{}; - } - } - - const long fwBndId = 1L; celix::Framework * const fw; const celix::Properties config; const celix::Properties bndManifest; const std::string cwd; const std::string fwUUID; + const std::string fwCacheDir; struct { @@ -374,7 +383,7 @@ private: struct { std::unordered_map<long, std::shared_ptr<celix::BundleController>> entries{}; - long nextBundleId = 2; + long nextBundleId = FRAMEWORK_BUNDLE_ID + 1; mutable std::mutex mutex{}; } bundles{}; @@ -389,11 +398,14 @@ private: **********************************************************************************************************************/ celix::Framework::Framework(celix::Properties config) : pimpl{std::unique_ptr<Impl>{new Impl{this, std::move(config)}}} { + pimpl->startFramework(); registerFramework(this); } celix::Framework::~Framework() { unregisterFramework(this); + pimpl->stopFramework(); + pimpl->waitForShutdown(); } celix::Framework::Framework(Framework &&rhs) = default; @@ -435,6 +447,9 @@ std::string celix::Framework::uuid() const { return pimpl->uuid(); } +celix::BundleContext& celix::Framework::context() const { + return pimpl->frameworkContext(); +} /*********************************************************************************************************************** * Celix 'global' functions diff --git a/libs/registry/CMakeLists.txt b/libs/registry/CMakeLists.txt index 5880f52..a7de533 100644 --- a/libs/registry/CMakeLists.txt +++ b/libs/registry/CMakeLists.txt @@ -16,10 +16,11 @@ # under the License. add_library(celix_registry STATIC - src/ServiceRegistry.cc + src/Utils.cc src/Filter.cc src/Properties.cc -) + src/ServiceRegistry.cc) + target_include_directories(celix_registry PRIVATE src) target_include_directories(celix_registry PUBLIC include) target_link_libraries(celix_registry PRIVATE glog::glog) diff --git a/libs/registry/gtest/CMakeLists.txt b/libs/registry/gtest/CMakeLists.txt index b534c50..88a8b87 100644 --- a/libs/registry/gtest/CMakeLists.txt +++ b/libs/registry/gtest/CMakeLists.txt @@ -17,8 +17,9 @@ set(SOURCES src/main.cc - src/Registry_tests.cc + src/Utils_tests.cc src/Filter_tests.cc + src/Registry_tests.cc src/ServiceTracking_tests.cc src/RegistryConcurrency_tests.cc ) diff --git a/libs/registry/gtest/src/Registry_tests.cc b/libs/registry/gtest/src/Registry_tests.cc index d8fad0e..49941ea 100644 --- a/libs/registry/gtest/src/Registry_tests.cc +++ b/libs/registry/gtest/src/Registry_tests.cc @@ -180,7 +180,7 @@ TEST_F(RegistryTest, UseServices) { EXPECT_EQ(&svc, &intf1); long id = celix::getProperty(props, celix::SERVICE_ID, 0); EXPECT_EQ(svcId1, id); - EXPECT_EQ(0, bnd.id()); //not nullptr -> use empty bundle (bndId 0) + EXPECT_EQ(LONG_MAX, bnd.id()); //not nullptr -> use empty bundle (bndId 0) }); EXPECT_TRUE(called); } diff --git a/libs/registry/gtest/src/Utils_tests.cc b/libs/registry/gtest/src/Utils_tests.cc new file mode 100644 index 0000000..3994109 --- /dev/null +++ b/libs/registry/gtest/src/Utils_tests.cc @@ -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. + */ + +#include "gtest/gtest.h" + +#include "celix/Utils.h" + +class UtilsTest : public ::testing::Test { +public: + UtilsTest() {} + ~UtilsTest(){} +}; + +class MarkerInterface; + +namespace example { + class MarkerInterface; +} + +class SvcWithFqn { + static constexpr const char * const FQN = "SvcWithFqn[Version 1]"; +}; + +TEST_F(UtilsTest, svcName) { + std::string name = celix::serviceName<MarkerInterface>(); + EXPECT_EQ("MarkerInterface", name); + + name = celix::serviceName<example::MarkerInterface>(); + EXPECT_EQ("example::MarkerInterface", name); + + name = celix::serviceName<SvcWithFqn>(); + //TODO EXPECT_EQ("SvcWithFqn[Version 1]", name); + + name = celix::functionServiceName<std::function<void()>>("do"); + EXPECT_EQ("do[std::function<void()>]", name); + + + name = celix::functionServiceName<std::function<std::vector<std::vector<long>>(long, int, std::vector<double>)>>("collect"); + //TODO EXPECT_EQ("collect[std::function<std::vector<std::vector<long>>(long, int, std::vector<double>)>]", name); +} \ No newline at end of file diff --git a/libs/registry/include/celix/Constants.h b/libs/registry/include/celix/Constants.h index 517a372..96f6326 100644 --- a/libs/registry/include/celix/Constants.h +++ b/libs/registry/include/celix/Constants.h @@ -31,14 +31,14 @@ namespace celix { static constexpr const char *const FRAMEWORK_UUID = "framework.uuid"; - static constexpr const char *const CXX_LANG = "C++"; - static constexpr const char *const C_LANG = "C"; - + static constexpr const char *const C_AND_CXX_LANG_REG = "C/C++"; static constexpr const char *const MANIFEST_BUNDLE_SYMBOLIC_NAME = "Bundle-SymbolicName"; static constexpr const char *const MANIFEST_BUNDLE_NAME = "Bundle-Name"; static constexpr const char *const MANIFEST_BUNDLE_VERSION = "Bundle-Version"; static constexpr const char *const MANIFEST_BUNDLE_GROUP = "Bundle-Group"; + + static constexpr long FRAMEWORK_BUNDLE_ID = 1L; } #endif //CXX_CELIX_CONSTANTS_H diff --git a/libs/registry/include/celix/ServiceRegistry.h b/libs/registry/include/celix/ServiceRegistry.h index 76b277d..c9a9a8e 100644 --- a/libs/registry/include/celix/ServiceRegistry.h +++ b/libs/registry/include/celix/ServiceRegistry.h @@ -145,10 +145,29 @@ namespace celix { } template<typename F> - celix::ServiceRegistration registerFunctionService(const std::string &functionName, F&& func, celix::Properties props = {}, std::shared_ptr<const celix::IResourceBundle> owner = {}); + celix::ServiceRegistration registerFunctionService( + const std::string &functionName, + F&& func, celix::Properties props = {}, + std::shared_ptr<const celix::IResourceBundle> owner = {}); template<typename I> - celix::ServiceRegistration registerServiceFactory(std::shared_ptr<celix::IServiceFactory<I>> factory, celix::Properties props = {}, std::shared_ptr<const celix::IResourceBundle> owner = {}); + celix::ServiceRegistration registerServiceFactory( + std::shared_ptr<celix::IServiceFactory<I>> factory, + celix::Properties props = {}, + std::shared_ptr<const celix::IResourceBundle> owner = {}) { + auto svcName = celix::serviceName<I>(); + return registerServiceFactory(svcName, std::move(factory), std::move(props), std::move(owner)); + } + + template<typename F> + celix::ServiceRegistration registerFunctionServiceFactory( + const std::string &functionName, + std::shared_ptr<celix::IServiceFactory<F>> factory, + celix::Properties props = {}, + std::shared_ptr<const celix::IResourceBundle> owner = {}) { + auto svcName = celix::functionServiceName<F>(functionName); + return registerServiceFactory(svcName, std::move(factory), std::move(props), std::move(owner)); + } template<typename I> //NOTE C++17 typename std::enable_if<!std::is_callable<I>::value, long>::type @@ -160,7 +179,7 @@ namespace celix { template<typename I> //NOTE C++17 typename std::enable_if<std::is_callable<I>::value, long>::type long findFunctionService(const std::string &functionName, const std::string &filter = "") const { - auto services = findFunctionService<I>(functionName, filter); + auto services = findFunctionServices<I>(functionName, filter); return services.size() > 0 ? services[0] : -1L; } @@ -190,8 +209,6 @@ namespace celix { return trackServices<F>(svcName, std::move(options), std::move(requester)); } - //TODO trackTrackers - template<typename I> int useServices(std::function<void(I& svc)> use, const std::string &filter = "", std::shared_ptr<const celix::IResourceBundle> requester = {}) const { auto svcName = celix::serviceName<I>(); @@ -338,8 +355,18 @@ namespace celix { std::unique_ptr<celix::ServiceRegistry::Impl> pimpl; //register services - celix::ServiceRegistration registerService(std::string svcName, std::shared_ptr<void> svc, celix::Properties props, std::shared_ptr<const celix::IResourceBundle> owner); - celix::ServiceRegistration registerServiceFactory(std::string svcName, std::shared_ptr<celix::IServiceFactory<void>> factory, celix::Properties props, std::shared_ptr<const celix::IResourceBundle> owner); + celix::ServiceRegistration registerService( + std::string svcName, + std::shared_ptr<void> svc, + celix::Properties props, + std::shared_ptr<const celix::IResourceBundle> owner); + + template<typename I> + celix::ServiceRegistration registerServiceFactory( + std::string svcName, + std::shared_ptr<celix::IServiceFactory<I>> factory, + celix::Properties props, + std::shared_ptr<const celix::IResourceBundle> owner); //use Services template<typename I> @@ -351,6 +378,8 @@ namespace celix { const std::string &filter, std::shared_ptr<const celix::IResourceBundle> requester) const; + celix::ServiceRegistration registerServiceFactory(std::string svcName, std::shared_ptr<celix::IServiceFactory<void>> factory, celix::Properties props, std::shared_ptr<const celix::IResourceBundle> owner); + template<typename I> bool useService( const std::string &svcName, @@ -394,9 +423,7 @@ inline celix::ServiceRegistration celix::ServiceRegistry::registerFunctionServic } template<typename I> -inline celix::ServiceRegistration celix::ServiceRegistry::registerServiceFactory(std::shared_ptr<celix::IServiceFactory<I>> factory, celix::Properties props, std::shared_ptr<const celix::IResourceBundle> owner) { - std::string svcName = celix::serviceName<I>(); - +inline celix::ServiceRegistration celix::ServiceRegistry::registerServiceFactory(std::string svcName, std::shared_ptr<celix::IServiceFactory<I>> factory, celix::Properties props, std::shared_ptr<const celix::IResourceBundle> owner) { class VoidServiceFactory : public celix::IServiceFactory<void> { public: VoidServiceFactory(std::shared_ptr<celix::IServiceFactory<I>> _factory) : factory{std::move(_factory)} {} diff --git a/libs/registry/include/celix/Utils.h b/libs/registry/include/celix/Utils.h index 5640636..09d674d 100644 --- a/libs/registry/include/celix/Utils.h +++ b/libs/registry/include/celix/Utils.h @@ -24,29 +24,20 @@ #include <string> #include <iostream> +namespace celix { +namespace impl { + void assertIsNotFunctionService(const std::string &svcName); + std::string typeNameFromPrettyFunction(const std::string &templateName, const std::string &pretty); +} +} + namespace { template<typename INTERFACE_TYPENAME> std::string typeName() { - std::string result; - - const char *templateStr = "INTERFACE_TYPENAME = "; - const size_t templateStrLen = strlen(templateStr); - - result = __PRETTY_FUNCTION__; //USING pretty function to retrieve the filled in template argument without using typeid() - size_t bpos = result.find(templateStr) + templateStrLen; //find begin pos after INTERFACE_TYPENAME = entry - size_t epos = bpos; - while (isalnum(result[epos]) || result[epos] == '_' || result[epos] == ':' || result[epos] == ' ' || result[epos] == '*' || result[epos] == '&' || result[epos] == '<' || result[epos] == '>') { - epos += 1; - } - size_t len = epos - bpos; - result = result.substr(bpos, len); - - if (result.empty()) { - std::cerr << "Cannot infer type name in function call '" << __PRETTY_FUNCTION__ << "'\n'"; - } - - return result; + static const std::string templateStr = "INTERFACE_TYPENAME = "; + std::string pretty = __PRETTY_FUNCTION__; + return celix::impl::typeNameFromPrettyFunction(templateStr, __PRETTY_FUNCTION__); } template<typename Arg> @@ -60,13 +51,13 @@ namespace { } template<typename R> - std::string functionName(const std::string &funcName) { - return funcName + " [std::function<" + typeName<R>() + "()>]"; + std::string functionName() { + return "std::function<" + typeName<R>() + "()>"; } template<typename R, typename Arg1, typename... Args> - std::string functionName(const std::string &funcName) { - return funcName + " [std::function<" + typeName<R>() + "(" + argName<Arg1, Args...>() + ")>]"; + std::string functionName() { + return "std::function<" + typeName<R>() + "(" + argName<Arg1, Args...>() + ")>"; } }; @@ -85,9 +76,13 @@ namespace celix { template<typename I> //NOTE C++17 typename std::enable_if<!std::is_callable<I>::value, std::string>::type std::string serviceName() { - return typeName<I>(); + std::string svcName = typeName<I>(); + celix::impl::assertIsNotFunctionService(svcName); + return svcName; } + //TODO resolve FQN for Function Service. + /** * Returns the service name for a std::function I. * Note that for a std::function the additional function name is needed to get a fully qualified service name; @@ -95,7 +90,8 @@ namespace celix { template<typename F> //NOTE C++17 typename std::enable_if<std::is_callable<I>::value, std::string>::type std::string functionServiceName(const std::string &fName) { - return functionName<decltype(&F::operator())>(fName); + std::string func = functionName<decltype(&F::operator())>(); + return fName + "[" + func + "]"; } } diff --git a/libs/registry/src/ServiceRegistry.cc b/libs/registry/src/ServiceRegistry.cc index 58d5778..6ed83f7 100644 --- a/libs/registry/src/ServiceRegistry.cc +++ b/libs/registry/src/ServiceRegistry.cc @@ -40,7 +40,11 @@ namespace { public: ~EmptyBundle() override = default; - long id() const noexcept override { return 0; } + long id() const noexcept override { + //TODO not sure what todo. 1 is reserved for the framework and I would like to keep <= 0 as invalid, so + //that default initialized long are not a valid bundle / svc id. + return LONG_MAX; + } const std::string& cacheRoot() const noexcept override { static std::string empty{}; @@ -94,7 +98,11 @@ namespace { void decrUsage() const { std::lock_guard<std::mutex> lck{mutex}; - usage -= 1; + if (usage == 0) { + LOG(ERROR) << "Usage count decrease below 0!" << std::endl; + } else { + usage -= 1; + } cond.notify_all(); } @@ -298,7 +306,11 @@ namespace { void decrUsage() const { std::lock_guard<std::mutex> lck{mutex}; - usage -= 1; + if (usage == 0) { + LOG(ERROR) << "Usage count decrease below 0!" << std::endl; + } else { + usage -= 1; + } cond.notify_all(); } @@ -516,8 +528,8 @@ public: celix::ServiceRegistry::ServiceRegistry(std::string name) : pimpl{new ServiceRegistry::Impl{std::move(name)}} {} -celix::ServiceRegistry::ServiceRegistry(celix::ServiceRegistry &&rhs) = default; -celix::ServiceRegistry& celix::ServiceRegistry::operator=(celix::ServiceRegistry &&rhs) = default; +celix::ServiceRegistry::ServiceRegistry(celix::ServiceRegistry &&) = default; +celix::ServiceRegistry& celix::ServiceRegistry::operator=(celix::ServiceRegistry &&) = default; celix::ServiceRegistry::~ServiceRegistry() { if (pimpl) { //TODO @@ -637,6 +649,7 @@ int celix::ServiceRegistry::useAnyServices(const std::string &svcName, const celix::IResourceBundle &bnd)> use, const std::string &f, std::shared_ptr<const celix::IResourceBundle> requester) const { + celix::Filter filter = f; if (!filter.valid()) { LOG(WARNING) << "Invalid filter (" << f << ") provided. Cannot find services" << std::endl; @@ -664,18 +677,19 @@ int celix::ServiceRegistry::useAnyServices(const std::string &svcName, entry->decrUsage(); }}; use(svc, entry->props, *entry->owner); - entry->decrUsage(); } return (int)matches.size(); } //TODO move to Impl -bool celix::ServiceRegistry::useAnyService(const std::string &svcName, - std::function<void(std::shared_ptr<void> svc, const celix::Properties &props, - const celix::IResourceBundle &bnd)> use, - const std::string &f, - std::shared_ptr<const celix::IResourceBundle> requester) const { +bool celix::ServiceRegistry::useAnyService( + const std::string &svcName, + std::function<void(std::shared_ptr<void> svc, const celix::Properties &props, + const celix::IResourceBundle &bnd)> use, + const std::string &f, + std::shared_ptr<const celix::IResourceBundle> requester) const { + celix::Filter filter = f; if (!filter.valid()) { LOG(WARNING) << "Invalid filter (" << f << ") provided. Cannot find services" << std::endl; @@ -720,8 +734,8 @@ std::vector<std::string> celix::ServiceRegistry::listAllRegisteredServiceNames() celix::ServiceRegistration::ServiceRegistration() : pimpl{nullptr} {} celix::ServiceRegistration::ServiceRegistration(celix::ServiceRegistration::Impl *impl) : pimpl{impl} {} -celix::ServiceRegistration::ServiceRegistration(celix::ServiceRegistration &&rhs) noexcept = default; -celix::ServiceRegistration& celix::ServiceRegistration::operator=(celix::ServiceRegistration &&rhs) noexcept = default; +celix::ServiceRegistration::ServiceRegistration(celix::ServiceRegistration &&) noexcept = default; +celix::ServiceRegistration& celix::ServiceRegistration::operator=(celix::ServiceRegistration &&) noexcept = default; celix::ServiceRegistration::~ServiceRegistration() { unregister(); } long celix::ServiceRegistration::serviceId() const { return pimpl ? pimpl->entry->svcId : -1L; } @@ -774,8 +788,8 @@ void celix::ServiceTracker::stop() { } } -celix::ServiceTracker::ServiceTracker(celix::ServiceTracker &&rhs) noexcept = default; -celix::ServiceTracker& celix::ServiceTracker::operator=(celix::ServiceTracker &&rhs) noexcept = default; +celix::ServiceTracker::ServiceTracker(celix::ServiceTracker &&) noexcept = default; +celix::ServiceTracker& celix::ServiceTracker::operator=(celix::ServiceTracker &&) noexcept = default; int celix::ServiceTracker::trackCount() const { return pimpl ? pimpl->entry->count() : 0; } const std::string& celix::ServiceTracker::serviceName() const { return pimpl? pimpl->entry->svcName : emptyString; } diff --git a/libs/registry/src/Utils.cc b/libs/registry/src/Utils.cc new file mode 100644 index 0000000..27feccb --- /dev/null +++ b/libs/registry/src/Utils.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 "celix/Utils.h" + +#include <string> + +#include <glog/logging.h> + +void celix::impl::assertIsNotFunctionService(const std::string &svcName) { + size_t pos = svcName.find("::function"); //note could be std::fuction or st::__1::function, etc? + if (pos <= svcName.size()) { + //match + LOG(WARNING) << "Unexpected std::function as template argument. For function use the find/use/trackFunctionService instead of find/use/trackService!" << std::endl; + assert(false); + } +} + +std::string celix::impl::typeNameFromPrettyFunction(const std::string &templateName, const std::string &prettyFunction) { + std::string result = prettyFunction; //USING pretty function to retrieve the filled in template argument without using typeid() + size_t bpos = result.find(templateName) + templateName.size(); //find begin pos after INTERFACE_TYPENAME = entry + size_t epos = bpos; + while (isalnum(result[epos]) || result[epos] == '_' || result[epos] == ':' || result[epos] == '*' || result[epos] == '&' || result[epos] == '<' || result[epos] == '>') { + epos += 1; + } + size_t len = epos - bpos; + result = result.substr(bpos, len); + + if (result.empty()) { + LOG(WARNING) << "Cannot infer type name in function call '" << prettyFunction << "'\n'"; + } + + return result; +} +