6 Commits

Author SHA1 Message Date
686cc550db webview jank 2025-06-25 15:44:45 +02:00
b6efcede21 some stuff
but it's somehow not possible to restart jvm after destruction, so it has to be redone anyway
2025-06-25 14:31:22 +02:00
e69f6e4bbb a little exception handling 2025-06-25 09:59:27 +02:00
6b89dbcc46 dump 2 2025-06-25 08:09:19 +02:00
651f1fc94b a start button 2025-06-24 17:33:43 +02:00
3bf4784c0d dump 2025-06-24 16:59:32 +02:00
19 changed files with 1869 additions and 0 deletions

80
launcher/.gitignore vendored Normal file
View File

@@ -0,0 +1,80 @@
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# AWS User-specific
.idea/**/aws.xml
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
build/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# SonarLint plugin
.idea/sonarlint/
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
Testing

34
launcher/CMakeLists.txt Normal file
View File

@@ -0,0 +1,34 @@
cmake_minimum_required(VERSION 3.10)
project(launcher)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED YES)
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
# if (NOT DEFINED SANITIZE)
# set(SANITIZE YES)
# endif ()
endif ()
if (SANITIZE STREQUAL "YES")
message(STATUS "Enabling sanitizers!")
add_compile_options(-Werror -O0 -Wall -Wextra -pedantic -Wno-unused-parameter -Wno-unused-variable
-Wno-error=unused-function
-Wshadow -Wformat=2 -Wfloat-equal -D_GLIBCXX_DEBUG -Wconversion)
add_compile_options(-fsanitize=address -fno-sanitize-recover)
add_link_options(-fsanitize=address -fno-sanitize-recover)
endif ()
if (CMAKE_BUILD_TYPE STREQUAL "Release")
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
endif ()
if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
add_compile_options(-O3)
add_link_options(-O3)
endif ()
add_subdirectory(utils)
add_subdirectory(libjvm_wrapper)
add_subdirectory(backend)
add_subdirectory(gui)

View File

@@ -0,0 +1,9 @@
add_library(backend
src/DhfsInstance.cpp
include_public/DhfsInstance.hpp
)
target_include_directories(backend PRIVATE include)
target_include_directories(backend PUBLIC include_public)
target_link_libraries(backend PUBLIC libjvm_wrapper utils)

View File

@@ -0,0 +1,37 @@
//
// Created by stepus53 on 24.6.25.
//
#ifndef DHFSINSTANCE_HPP
#define DHFSINSTANCE_HPP
#include <jni.h>
#include <string>
#include <vector>
enum class DhfsInstanceState {
RUNNING,
STOPPED,
};
class DhfsInstance {
public:
DhfsInstance();
~DhfsInstance();
DhfsInstanceState state();
void start(const std::string& mount_path, const std::vector<std::string>& extra_options);
void stop();
private:
DhfsInstanceState _state = DhfsInstanceState::STOPPED;
JavaVM* _jvm = nullptr;
JNIEnv* _env = nullptr;
};
#endif //DHFSINSTANCE_HPP

View File

@@ -0,0 +1,68 @@
//
// Created by stepus53 on 24.6.25.
//
#include "DhfsInstance.hpp"
#include <stdexcept>
#include <vector>
#include "Exception.h"
#include "LibjvmWrapper.hpp"
DhfsInstance::DhfsInstance() {
}
DhfsInstance::~DhfsInstance() {
}
DhfsInstanceState DhfsInstance::state() {
return _state;
}
void DhfsInstance::start(const std::string& mount_path, const std::vector<std::string>& extra_options) {
switch (_state) {
case DhfsInstanceState::RUNNING:
return;
case DhfsInstanceState::STOPPED:
break;
default:
throw std::runtime_error("Unknown DhfsInstanceState");
}
_state = DhfsInstanceState::RUNNING;
JavaVMInitArgs args;
std::vector<JavaVMOption> options;
for (const auto& option: extra_options) {
options.emplace_back((char*) option.c_str(), nullptr);
}
std::string mount_option = "-Ddhfs.fuse.root=";
mount_option += mount_path;
options.emplace_back((char*) mount_option.c_str(), nullptr);
args.version = JNI_VERSION_21;
args.nOptions = options.size();
args.options = options.data();
args.ignoreUnrecognized = false;
LibjvmWrapper::instance().get_JNI_CreateJavaVM()(&_jvm, (void**) &_env, &args);
}
void DhfsInstance::stop() {
switch (_state) {
case DhfsInstanceState::RUNNING:
break;
case DhfsInstanceState::STOPPED:
return;
default:
throw std::runtime_error("Unknown DhfsInstanceState");
}
if (_jvm == nullptr)
throw Exception("JVM not running");
JNIEnv* env;
_jvm->AttachCurrentThread((void**) &env, nullptr);
_jvm->DestroyJavaVM();
_jvm = nullptr;
_state = DhfsInstanceState::STOPPED;
}

View File

@@ -0,0 +1,14 @@
find_package(wxWidgets REQUIRED COMPONENTS net core base webview)
if (wxWidgets_USE_FILE) # not defined in CONFIG mode
include(${wxWidgets_USE_FILE})
endif ()
add_executable(launcher
src/LauncherApp.cpp
src/GLauncherApp.cpp
src/LauncherAppMainFrame.cpp
)
target_link_libraries(launcher ${wxWidgets_LIBRARIES})
target_link_libraries(launcher backend utils)

View File

@@ -0,0 +1,141 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#include "GLauncherApp.h"
///////////////////////////////////////////////////////////////////////////
MainFrame::MainFrame( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style, const wxString& name ) : wxFrame( parent, id, title, pos, size, style, name )
{
this->SetSizeHints( wxSize( 100,50 ), wxDefaultSize );
m_statusBar1 = this->CreateStatusBar( 1, wxSTB_SIZEGRIP, wxID_ANY );
wxBoxSizer* bSizer3;
bSizer3 = new wxBoxSizer( wxVERTICAL );
m_notebook1 = new wxNotebook( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 );
m_panel1 = new wxPanel( m_notebook1, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxBoxSizer* bSizer2;
bSizer2 = new wxBoxSizer( wxVERTICAL );
wxStaticBoxSizer* sbSizer4;
sbSizer4 = new wxStaticBoxSizer( new wxStaticBox( m_panel1, wxID_ANY, _("Status") ), wxVERTICAL );
wxGridBagSizer* gbSizer1;
gbSizer1 = new wxGridBagSizer( 0, 0 );
gbSizer1->SetFlexibleDirection( wxBOTH );
gbSizer1->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
m_statusText = new wxStaticText( sbSizer4->GetStaticBox(), wxID_ANY, _("Running"), wxDefaultPosition, wxDefaultSize, 0 );
m_statusText->Wrap( -1 );
gbSizer1->Add( m_statusText, wxGBPosition( 0, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxALL, 5 );
m_startStopButton = new wxButton( sbSizer4->GetStaticBox(), wxID_ANY, _("Start"), wxDefaultPosition, wxDefaultSize, 0 );
gbSizer1->Add( m_startStopButton, wxGBPosition( 0, 1 ), wxGBSpan( 1, 1 ), wxALL, 5 );
sbSizer4->Add( gbSizer1, 1, wxEXPAND, 5 );
bSizer2->Add( sbSizer4, 1, wxALL|wxEXPAND, 5 );
wxStaticBoxSizer* sbSizer6;
sbSizer6 = new wxStaticBoxSizer( new wxStaticBox( m_panel1, wxID_ANY, _("Statistics") ), wxVERTICAL );
bSizer2->Add( sbSizer6, 1, wxALL|wxEXPAND, 5 );
m_panel1->SetSizer( bSizer2 );
m_panel1->Layout();
bSizer2->Fit( m_panel1 );
m_notebook1->AddPage( m_panel1, _("Info"), false );
m_panel3 = new wxPanel( m_notebook1, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
m_notebook1->AddPage( m_panel3, _("Logs"), false );
m_panel2 = new wxPanel( m_notebook1, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxBoxSizer* bSizer5;
bSizer5 = new wxBoxSizer( wxVERTICAL );
wxStaticBoxSizer* sbSizer3;
sbSizer3 = new wxStaticBoxSizer( new wxStaticBox( m_panel2, wxID_ANY, _("JVM") ), wxVERTICAL );
wxGridBagSizer* gbSizer2;
gbSizer2 = new wxGridBagSizer( 0, 0 );
gbSizer2->SetFlexibleDirection( wxBOTH );
gbSizer2->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
m_button2 = new wxButton( sbSizer3->GetStaticBox(), wxID_ANY, _("Reset"), wxDefaultPosition, wxDefaultSize, 0 );
gbSizer2->Add( m_button2, wxGBPosition( 0, 3 ), wxGBSpan( 1, 1 ), wxALL, 5 );
gbSizer2->Add( 50, 0, wxGBPosition( 0, 2 ), wxGBSpan( 1, 1 ), wxEXPAND, 5 );
m_javaHomeDirPicker = new wxDirPickerCtrl( sbSizer3->GetStaticBox(), wxID_ANY, wxEmptyString, _("Select a folder"), wxDefaultPosition, wxDefaultSize, wxDIRP_DEFAULT_STYLE|wxDIRP_USE_TEXTCTRL );
gbSizer2->Add( m_javaHomeDirPicker, wxGBPosition( 0, 1 ), wxGBSpan( 1, 1 ), wxALL|wxEXPAND, 5 );
m_staticText2 = new wxStaticText( sbSizer3->GetStaticBox(), wxID_ANY, _("Java Home"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText2->Wrap( -1 );
gbSizer2->Add( m_staticText2, wxGBPosition( 0, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxALL, 5 );
gbSizer2->AddGrowableCol( 1 );
sbSizer3->Add( gbSizer2, 1, wxEXPAND, 5 );
bSizer5->Add( sbSizer3, 1, wxALL|wxEXPAND|wxFIXED_MINSIZE, 5 );
wxStaticBoxSizer* sbSizer41;
sbSizer41 = new wxStaticBoxSizer( new wxStaticBox( m_panel2, wxID_ANY, _("Paths") ), wxVERTICAL );
wxGridBagSizer* gbSizer3;
gbSizer3 = new wxGridBagSizer( 0, 0 );
gbSizer3->SetFlexibleDirection( wxBOTH );
gbSizer3->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
m_staticText6 = new wxStaticText( sbSizer41->GetStaticBox(), wxID_ANY, _("Mount path"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText6->Wrap( -1 );
gbSizer3->Add( m_staticText6, wxGBPosition( 0, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxALL, 5 );
m_mountPathDirPicker = new wxDirPickerCtrl( sbSizer41->GetStaticBox(), wxID_ANY, wxEmptyString, _("Select a folder"), wxDefaultPosition, wxDefaultSize, wxDIRP_DEFAULT_STYLE|wxDIRP_USE_TEXTCTRL );
gbSizer3->Add( m_mountPathDirPicker, wxGBPosition( 0, 1 ), wxGBSpan( 1, 1 ), wxALL|wxEXPAND, 5 );
gbSizer3->AddGrowableCol( 1 );
sbSizer41->Add( gbSizer3, 1, wxEXPAND, 5 );
bSizer5->Add( sbSizer41, 1, wxALL|wxEXPAND, 5 );
m_panel2->SetSizer( bSizer5 );
m_panel2->Layout();
bSizer5->Fit( m_panel2 );
m_notebook1->AddPage( m_panel2, _("Settings"), false );
m_panel4 = new wxPanel( m_notebook1, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
m_notebook1->AddPage( m_panel4, _("Advanced Settings"), false );
m_panel5 = new wxPanel( m_notebook1, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
m_notebook1->AddPage( m_panel5, _("a page"), true );
bSizer3->Add( m_notebook1, 1, wxALL|wxEXPAND, 5 );
this->SetSizer( bSizer3 );
this->Layout();
this->Centre( wxBOTH );
// Connect Events
m_startStopButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainFrame::OnStartStopButtonClick ), NULL, this );
m_javaHomeDirPicker->Connect( wxEVT_COMMAND_DIRPICKER_CHANGED, wxFileDirPickerEventHandler( MainFrame::OnJavaHomeChanged ), NULL, this );
m_mountPathDirPicker->Connect( wxEVT_COMMAND_DIRPICKER_CHANGED, wxFileDirPickerEventHandler( MainFrame::OnMountPathChanged ), NULL, this );
}
MainFrame::~MainFrame()
{
}

View File

@@ -0,0 +1,70 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#pragma once
#include <wx/artprov.h>
#include <wx/xrc/xmlres.h>
#include <wx/intl.h>
#include <wx/statusbr.h>
#include <wx/gdicmn.h>
#include <wx/font.h>
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/string.h>
#include <wx/stattext.h>
#include <wx/button.h>
#include <wx/bitmap.h>
#include <wx/image.h>
#include <wx/icon.h>
#include <wx/gbsizer.h>
#include <wx/sizer.h>
#include <wx/statbox.h>
#include <wx/panel.h>
#include <wx/filepicker.h>
#include <wx/notebook.h>
#include <wx/frame.h>
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
/// Class MainFrame
///////////////////////////////////////////////////////////////////////////////
class MainFrame : public wxFrame
{
private:
protected:
wxStatusBar* m_statusBar1;
wxNotebook* m_notebook1;
wxPanel* m_panel1;
wxStaticText* m_statusText;
wxButton* m_startStopButton;
wxPanel* m_panel3;
wxPanel* m_panel2;
wxButton* m_button2;
wxDirPickerCtrl* m_javaHomeDirPicker;
wxStaticText* m_staticText2;
wxStaticText* m_staticText6;
wxDirPickerCtrl* m_mountPathDirPicker;
wxPanel* m_panel4;
wxPanel* m_panel5;
// Virtual event handlers, override them in your derived class
virtual void OnStartStopButtonClick( wxCommandEvent& event ) { event.Skip(); }
virtual void OnJavaHomeChanged( wxFileDirPickerEvent& event ) { event.Skip(); }
virtual void OnMountPathChanged( wxFileDirPickerEvent& event ) { event.Skip(); }
public:
MainFrame( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("DHFS"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 499,341 ), long style = wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL, const wxString& name = wxT("DHFS") );
~MainFrame();
};

View File

@@ -0,0 +1,44 @@
//
// Created by Stepan Usatiuk on 11.07.2024.
//
// For compilers that don't support precompilation, include "wx/wx.h"
#include "wx/wxprec.h"
#ifndef WX_PRECOMP
# include "wx/wx.h"
#endif
#include "wx/notebook.h"
#include "LauncherApp.h"
#include "LauncherAppMainFrame.h"
#include "wx/taskbar.h"
#include <wx/fileconf.h>
IMPLEMENT_APP(LauncherApp)
// This is executed upon startup, like 'main()' in non-wxWidgets programs.
bool LauncherApp::OnInit() {
wxFileConfig::Get()->SetAppName("DHFS");
wxFrame* frame = new LauncherAppMainFrame(NULL);
frame->Show(true);
SetTopWindow(frame);
// wxTaskBarIcon* tb = new wxTaskBarIcon();
// auto img = new wxImage(32, 32, false);
// img->Clear(128);
// tb->SetIcon(*(new wxBitmapBundle(*(new wxBitmap(*img)))), "e");
return true;
}
bool LauncherApp::OnExceptionInMainLoop() {
try {
std::rethrow_exception(std::current_exception());
} catch (const std::exception& e) {
wxMessageBox(e.what(), "Error", wxOK | wxICON_ERROR | wxCENTRE, GetTopWindow());
}
return true;
}

View File

@@ -0,0 +1,19 @@
//
// Created by Stepan Usatiuk on 11.07.2024.
//
#ifndef HELLOWORLDAPP_H
#define HELLOWORLDAPP_H
// The HelloWorldApp class. This class shows a window
// containing a statusbar with the text "Hello World"
class LauncherApp : public wxApp {
public:
virtual bool OnInit() override;
virtual bool OnExceptionInMainLoop() override;
};
DECLARE_APP(LauncherApp)
#endif //HELLOWORLDAPP_H

View File

@@ -0,0 +1,52 @@
#include "LauncherAppMainFrame.h"
#include <iostream>
#include <wx/fileconf.h>
#include "Exception.h"
#include "LibjvmWrapper.hpp"
LauncherAppMainFrame::LauncherAppMainFrame(wxWindow* parent)
: MainFrame(parent) {
m_javaHomeDirPicker->SetPath(wxFileConfig::Get()->Read(kJavaHomeSettingsKey));
m_mountPathDirPicker->SetPath(wxFileConfig::Get()->Read(kMountPointSettingsKey));
wxGridSizer* bSizer4;
bSizer4 = new wxGridSizer(1, 0, 0);
m_panel5->SetSizer(bSizer4);
m_panel5->Layout();
bSizer4->Fit(m_panel5);
m_webView = wxWebView::New(m_panel5, wxID_ANY);
bSizer4->Add(m_webView, 0, wxALL | wxEXPAND);
m_webView->LoadURL("http://localhost:8080");
}
void LauncherAppMainFrame::OnStartStopButtonClick(wxCommandEvent& event) {
switch (_dhfsInstance.state()) {
case DhfsInstanceState::RUNNING:
m_statusText->SetLabel("Stopped");
m_startStopButton->SetLabel("Start");
m_statusBar1->SetStatusText("Stopped", 0);
_dhfsInstance.stop();
break;
case DhfsInstanceState::STOPPED:
LibjvmWrapper::instance().setJavaHome(wxFileConfig::Get()->Read(kJavaHomeSettingsKey).ToStdString());
m_statusText->SetLabel("Running");
m_startStopButton->SetLabel("Stop");
m_statusBar1->SetStatusText("Running", 0);
_dhfsInstance.start(wxFileConfig::Get()->Read(kMountPointSettingsKey).ToStdString(), {
});
break;
default:
throw Exception("Unhandled switch case");
}
}
void LauncherAppMainFrame::OnJavaHomeChanged(wxFileDirPickerEvent& event) {
wxFileConfig::Get()->Write(kJavaHomeSettingsKey, event.GetPath());
}
void LauncherAppMainFrame::OnMountPathChanged(wxFileDirPickerEvent& event) {
wxFileConfig::Get()->Write(kMountPointSettingsKey, event.GetPath());
}

View File

@@ -0,0 +1,40 @@
#ifndef __LauncherAppMainFrame__
#define __LauncherAppMainFrame__
/**
@file
Subclass of MainFrame, which is generated by wxFormBuilder.
*/
#include "GLauncherApp.h"
//// end generated include
#include "DhfsInstance.hpp"
#include <wx/webview.h>
static constexpr auto kJavaHomeSettingsKey = "DHFS/JavaHome";
static constexpr auto kMountPointSettingsKey = "DHFS/MountDir";
/** Implementing MainFrame */
class LauncherAppMainFrame : public MainFrame {
protected:
// Handlers for MainFrame events.
void OnStartStopButtonClick(wxCommandEvent& event) override;
void OnJavaHomeChanged(wxFileDirPickerEvent& event) override;
void OnMountPathChanged(wxFileDirPickerEvent& event) override;
public:
/** Constructor */
LauncherAppMainFrame(wxWindow* parent);
//// end generated class members
private:
wxWebView* m_webView;
DhfsInstance _dhfsInstance;
};
#endif // __LauncherAppMainFrame__

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,12 @@
add_library(libjvm_wrapper
src/LibjvmWrapper.cpp
include_public/LibjvmWrapper.hpp
)
target_include_directories(libjvm_wrapper PRIVATE include)
target_include_directories(libjvm_wrapper PUBLIC include_public)
find_package(JNI REQUIRED)
target_include_directories(libjvm_wrapper PUBLIC ${JNI_INCLUDE_DIRS})
target_link_libraries(libjvm_wrapper PUBLIC utils)

View File

@@ -0,0 +1,34 @@
//
// Created by Stepan Usatiuk on 24.06.2025.
//
#ifndef LIBJVMWRAPPER_HPP
#define LIBJVMWRAPPER_HPP
#include <jni.h>
#include <string>
class LibjvmWrapper {
public:
static LibjvmWrapper& instance();
void setJavaHome(const std::string& javaHome);
decltype(JNI_CreateJavaVM)* get_JNI_CreateJavaVM();
private:
void load();
void unload();
LibjvmWrapper();
~LibjvmWrapper();
void* _lib_handle = nullptr;
decltype(JNI_CreateJavaVM)* WJNI_CreateJavaVM = nullptr;
std::string _java_home;
};
#endif //LIBJVMWRAPPER_HPP

View File

@@ -0,0 +1,59 @@
//
// Created by Stepan Usatiuk on 24.06.2025.
//
#include "LibjvmWrapper.hpp"
#include <dlfcn.h>
#include <jni.h>
#include "Exception.h"
LibjvmWrapper& LibjvmWrapper::instance() {
static LibjvmWrapper instance;
return instance;
}
LibjvmWrapper::LibjvmWrapper() {
}
void LibjvmWrapper::load() {
if (_java_home == "")
throw Exception("Java home not set");
if (_lib_handle != nullptr)
throw Exception("load() called when already loaded");
std::string javaHomeAppended;
javaHomeAppended = _java_home + "/lib/server/libjvm.so";
_lib_handle = dlopen(javaHomeAppended.c_str(), RTLD_NOW | RTLD_GLOBAL);
if (_lib_handle == nullptr)
throw Exception(dlerror());
WJNI_CreateJavaVM = reinterpret_cast<decltype(WJNI_CreateJavaVM)>(
dlsym(_lib_handle, "JNI_CreateJavaVM"));
if (WJNI_CreateJavaVM == nullptr)
throw Exception(dlerror());
}
void LibjvmWrapper::unload() {
if (_lib_handle != nullptr) {
dlclose(_lib_handle);
_lib_handle = nullptr;
WJNI_CreateJavaVM = nullptr;
}
}
decltype(JNI_CreateJavaVM)* LibjvmWrapper::get_JNI_CreateJavaVM() {
if (WJNI_CreateJavaVM == nullptr) {
load();
}
return WJNI_CreateJavaVM;
}
LibjvmWrapper::~LibjvmWrapper() {
unload();
}
void LibjvmWrapper::setJavaHome(const std::string& javaHome) {
unload();
_java_home = javaHome;
}

View File

@@ -0,0 +1,7 @@
add_library(utils
src/Exception.cpp
include_public/Exception.h
)
target_include_directories(utils PRIVATE include)
target_include_directories(utils PUBLIC include_public)

View File

@@ -0,0 +1,30 @@
//
// Created by Stepan Usatiuk on 01.05.2023.
//
#ifndef SEMBACKUP_EXCEPTION_H
#define SEMBACKUP_EXCEPTION_H
#include <cstring>
#include <stdexcept>
#include <string>
#include <vector>
/// Custom exception class that uses execinfo to append a stacktrace to the exception message
class Exception : public std::runtime_error {
public:
Exception(const std::string& text);
Exception(const char* text);
private:
/// Static function to get the current stacktrace
static std::string getStacktrace();
};
class ErrnoException : public Exception {
public:
ErrnoException(const std::string& text) : Exception(text + " " + std::strerror(errno)) {}
ErrnoException(const char* text) : Exception(std::string(text) + " " + std::strerror(errno)) {}
};
#endif // SEMBACKUP_EXCEPTION_H

View File

@@ -0,0 +1,37 @@
//
// Created by Stepan Usatiuk on 01.05.2023.
//
#include "Exception.h"
#include <execinfo.h>
#include <sstream>
#include <openssl/err.h>
Exception::Exception(const std::string& text) : runtime_error(text + "\n" + getStacktrace()) {
}
Exception::Exception(const char* text) : runtime_error(std::string(text) + "\n" + getStacktrace()) {
}
// Based on: https://www.gnu.org/software/libc/manual/html_node/Backtraces.html
std::string Exception::getStacktrace() {
std::vector<void*> functions(50);
char** strings;
int n;
n = backtrace(functions.data(), 50);
strings = backtrace_symbols(functions.data(), n);
std::stringstream out;
if (strings != nullptr) {
out << "Stacktrace:" << std::endl;
for (int i = 0; i < n; i++)
out << strings[i] << std::endl;
}
free(strings);
return out.str();
}