<commit_before>/*=============================================================================

  Library: CppMicroServices

  Copyright (c) The CppMicroServices developers. See the COPYRIGHT
  file at the top-level directory of this distribution and at
  https://github.com/CppMicroServices/CppMicroServices/COPYRIGHT .

  Licensed 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 "cppmicroservices/GlobalConfig.h"

US_MSVC_DISABLE_WARNING(4355)

#include "CoreBundleContext.h"

#include "cppmicroservices/BundleInitialization.h"
#include "cppmicroservices/Constants.h"

#include "BundleStorageMemory.h"
#include "BundleThread.h"
#include "BundleUtils.h"
#include "FrameworkPrivate.h"
#include "Utils.h" // cppmicroservices::ToString()

#include <iomanip>

CPPMICROSERVICES_INITIALIZE_BUNDLE

namespace cppmicroservices {

std::atomic<int> CoreBundleContext::globalId{0};

std::map<std::string, Any> InitProperties(std::map<std::string, Any> configuration)
{
  // Framework internal diagnostic logging is off by default
  configuration.insert(std::pair<std::string, Any>(Constants::FRAMEWORK_LOG, false));

  // Framework::PROP_THREADING_SUPPORT is a read-only property whose value is based off of a compile-time switch.
  // Run-time modification of the property should be ignored as it is irrelevant.
  configuration.erase(Constants::FRAMEWORK_THREADING_SUPPORT);
#ifdef US_ENABLE_THREADING_SUPPORT
  configuration.insert(std::pair<std::string, Any>(Constants::FRAMEWORK_THREADING_SUPPORT, std::string("multi")));
#else
  configuration.insert(std::pair<std::string, Any>(Constants::FRAMEWORK_THREADING_SUPPORT, std::string("single")));
#endif

  return configuration;
}

CoreBundleContext::CoreBundleContext(const std::map<std::string, Any>& props, std::ostream* logger)
  : id(globalId++)
  , frameworkProperties(InitProperties(props))
  , listeners(this)
  , services(this)
  , serviceHooks(this)
  , bundleHooks(this)
  , bundleRegistry(this)
  , firstInit(true)
  , initCount(0)
{
  bool enableDiagLog = any_cast<bool>(frameworkProperties.at(Constants::FRAMEWORK_LOG));
  std::ostream* diagnosticLogger = (logger) ? logger : &std::clog;
  sink = std::make_shared<detail::LogSink>(diagnosticLogger, enableDiagLog);
  systemBundle = std::shared_ptr<FrameworkPrivate>(new FrameworkPrivate(this));
  DIAG_LOG(*sink) << "created";
}

CoreBundleContext::~CoreBundleContext()
{
  std::shared_ptr<CoreBundleContext> dummy(this, [](CoreBundleContext*){});
  systemBundle->Shutdown(false);
  systemBundle->WaitForStop(std::chrono::milliseconds(0));
}

void CoreBundleContext::Init()
{
  DIAG_LOG(*sink) << "initializing";
  initCount++;

  auto storageCleanProp = frameworkProperties.find(Constants::FRAMEWORK_STORAGE_CLEAN);
  if (firstInit && storageCleanProp != frameworkProperties.end() &&
      storageCleanProp->second == Constants::FRAMEWORK_STORAGE_CLEAN_ONFIRSTINIT)
  {
    // DeleteFWDir();
    firstInit = false;
  }

  // We use a "pseudo" random UUID.
  const std::string sid_base = "04f4f884-31bb-45c0-b176-";
  std::stringstream ss;
  ss << sid_base << std::setfill('0') << std::setw(8) << std::hex << static_cast<int32_t>(id * 65536 + initCount);

  frameworkProperties[Constants::FRAMEWORK_UUID] = ss.str();

  // $TODO we only support non-persistent (main memory) storage yet
  storage.reset(new BundleStorageMemory());
//  if (frameworkProperties[FWProps::READ_ONLY_PROP] == true)
//  {
//    dataStorage.clear();
//  }
//  else
//  {
//    dataStorage = GetFileStorage(this, "data");
//  }
  dataStorage = GetFileStorage(this, "data");

  systemBundle->InitSystemBundle();
  _us_set_bundle_context_instance_system_bundle(systemBundle->bundleContext.Load().get());

  bundleRegistry.Init();

  serviceHooks.Open();
  //resolverHooks.Open();
  
  // auto-install all embedded bundles inside the executable
  auto execPath = BundleUtils::GetExecutablePath();
  if (IsBundleFile(execPath))
  {
    bundleRegistry.Install(execPath, systemBundle.get(), true);
  }

  bundleRegistry.Load();

  DIAG_LOG(*sink) << "inited\nInstalled bundles: ";
  for (auto b : bundleRegistry.GetBundles())
  {
    DIAG_LOG(*sink) << " #" << b->id << " " << b->symbolicName << ":"
                    << b->version << " location:" << b->location;
  }
}

void CoreBundleContext::Uninit0()
{
  DIAG_LOG(*sink) << "uninit";
  serviceHooks.Close();
  systemBundle->UninitSystemBundle();
}

void CoreBundleContext::Uninit1()
{
  bundleRegistry.Clear();
  services.Clear();
  listeners.Clear();
  resolver.Clear();

  {
    auto l = bundleThreads.Lock(); US_UNUSED(l);
    while (!bundleThreads.value.empty())
    {
      bundleThreads.value.front()->Quit();
      bundleThreads.value.pop_front();
    }
    while (!bundleThreads.zombies.empty())
    {
      bundleThreads.zombies.front()->Join();
      bundleThreads.zombies.pop_front();
    }
  }

  dataStorage.clear();
  storage->Close();
}

std::string CoreBundleContext::GetDataStorage(long id) const
{
  if (!dataStorage.empty())
  {
    return dataStorage + DIR_SEP + cppmicroservices::ToString(id);
  }
  return std::string();
}

}
<commit_msg>Auto-install executable bundles after the registry was loaded.<commit_after>/*=============================================================================

  Library: CppMicroServices

  Copyright (c) The CppMicroServices developers. See the COPYRIGHT
  file at the top-level directory of this distribution and at
  https://github.com/CppMicroServices/CppMicroServices/COPYRIGHT .

  Licensed 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 "cppmicroservices/GlobalConfig.h"

US_MSVC_DISABLE_WARNING(4355)

#include "CoreBundleContext.h"

#include "cppmicroservices/BundleInitialization.h"
#include "cppmicroservices/Constants.h"

#include "BundleStorageMemory.h"
#include "BundleThread.h"
#include "BundleUtils.h"
#include "FrameworkPrivate.h"
#include "Utils.h" // cppmicroservices::ToString()

#include <iomanip>

CPPMICROSERVICES_INITIALIZE_BUNDLE

namespace cppmicroservices {

std::atomic<int> CoreBundleContext::globalId{0};

std::map<std::string, Any> InitProperties(std::map<std::string, Any> configuration)
{
  // Framework internal diagnostic logging is off by default
  configuration.insert(std::pair<std::string, Any>(Constants::FRAMEWORK_LOG, false));

  // Framework::PROP_THREADING_SUPPORT is a read-only property whose value is based off of a compile-time switch.
  // Run-time modification of the property should be ignored as it is irrelevant.
  configuration.erase(Constants::FRAMEWORK_THREADING_SUPPORT);
#ifdef US_ENABLE_THREADING_SUPPORT
  configuration.insert(std::pair<std::string, Any>(Constants::FRAMEWORK_THREADING_SUPPORT, std::string("multi")));
#else
  configuration.insert(std::pair<std::string, Any>(Constants::FRAMEWORK_THREADING_SUPPORT, std::string("single")));
#endif

  return configuration;
}

CoreBundleContext::CoreBundleContext(const std::map<std::string, Any>& props, std::ostream* logger)
  : id(globalId++)
  , frameworkProperties(InitProperties(props))
  , listeners(this)
  , services(this)
  , serviceHooks(this)
  , bundleHooks(this)
  , bundleRegistry(this)
  , firstInit(true)
  , initCount(0)
{
  bool enableDiagLog = any_cast<bool>(frameworkProperties.at(Constants::FRAMEWORK_LOG));
  std::ostream* diagnosticLogger = (logger) ? logger : &std::clog;
  sink = std::make_shared<detail::LogSink>(diagnosticLogger, enableDiagLog);
  systemBundle = std::shared_ptr<FrameworkPrivate>(new FrameworkPrivate(this));
  DIAG_LOG(*sink) << "created";
}

CoreBundleContext::~CoreBundleContext()
{
  std::shared_ptr<CoreBundleContext> dummy(this, [](CoreBundleContext*){});
  systemBundle->Shutdown(false);
  systemBundle->WaitForStop(std::chrono::milliseconds(0));
}

void CoreBundleContext::Init()
{
  DIAG_LOG(*sink) << "initializing";
  initCount++;

  auto storageCleanProp = frameworkProperties.find(Constants::FRAMEWORK_STORAGE_CLEAN);
  if (firstInit && storageCleanProp != frameworkProperties.end() &&
      storageCleanProp->second == Constants::FRAMEWORK_STORAGE_CLEAN_ONFIRSTINIT)
  {
    // DeleteFWDir();
    firstInit = false;
  }

  // We use a "pseudo" random UUID.
  const std::string sid_base = "04f4f884-31bb-45c0-b176-";
  std::stringstream ss;
  ss << sid_base << std::setfill('0') << std::setw(8) << std::hex << static_cast<int32_t>(id * 65536 + initCount);

  frameworkProperties[Constants::FRAMEWORK_UUID] = ss.str();

  // $TODO we only support non-persistent (main memory) storage yet
  storage.reset(new BundleStorageMemory());
//  if (frameworkProperties[FWProps::READ_ONLY_PROP] == true)
//  {
//    dataStorage.clear();
//  }
//  else
//  {
//    dataStorage = GetFileStorage(this, "data");
//  }
  dataStorage = GetFileStorage(this, "data");

  systemBundle->InitSystemBundle();
  _us_set_bundle_context_instance_system_bundle(systemBundle->bundleContext.Load().get());

  bundleRegistry.Init();

  serviceHooks.Open();
  //resolverHooks.Open();

  bundleRegistry.Load();

  auto const execPath = BundleUtils::GetExecutablePath();
  if (bundleRegistry.GetBundles(execPath).empty() &&
      IsBundleFile(execPath))
  {
  // auto-install all embedded bundles inside the executable
    bundleRegistry.Install(execPath, systemBundle.get(), true);
  }

  DIAG_LOG(*sink) << "inited\nInstalled bundles: ";
  for (auto b : bundleRegistry.GetBundles())
  {
    DIAG_LOG(*sink) << " #" << b->id << " " << b->symbolicName << ":"
                    << b->version << " location:" << b->location;
  }
}

void CoreBundleContext::Uninit0()
{
  DIAG_LOG(*sink) << "uninit";
  serviceHooks.Close();
  systemBundle->UninitSystemBundle();
}

void CoreBundleContext::Uninit1()
{
  bundleRegistry.Clear();
  services.Clear();
  listeners.Clear();
  resolver.Clear();

  {
    auto l = bundleThreads.Lock(); US_UNUSED(l);
    while (!bundleThreads.value.empty())
    {
      bundleThreads.value.front()->Quit();
      bundleThreads.value.pop_front();
    }
    while (!bundleThreads.zombies.empty())
    {
      bundleThreads.zombies.front()->Join();
      bundleThreads.zombies.pop_front();
    }
  }

  dataStorage.clear();
  storage->Close();
}

std::string CoreBundleContext::GetDataStorage(long id) const
{
  if (!dataStorage.empty())
  {
    return dataStorage + DIR_SEP + cppmicroservices::ToString(id);
  }
  return std::string();
}

}

{'fraction_non_alphanumeric': 0.16115485564304463, 'fraction_numerical': 0.006299212598425197, 'mean_word_length': 5.2091254752851714, 'pattern_counts': {'":': 2, '<': 97, '<?xml version=': 0, '>': 55, 'https://': 2, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4141313', 'n_tokens_mistral': 3560, 'n_tokens_neox': 3460, 'n_words': 713}