11#include < jni.h>
2+ #include < exception>
3+ #include < memory>
4+ #include < stdexcept>
25#include < string>
6+ #include < dlfcn.h>
7+ #include " firebird/Interface.h"
8+ #include " firebird/Message.h"
39
4- extern " C" JNIEXPORT jstring JNICALL
5- Java_com_example_firebirdandroidcpp_MainActivity_stringFromJNI (
6- JNIEnv* env,
7- jobject /* this */ ) {
8- std::string hello = " Hello from C++" ;
9- return env->NewStringUTF (hello.c_str ());
10- }
10+ namespace fb = Firebird;
11+
12+ using GetMasterPtr = decltype (&fb::fb_get_master_interface);
13+
14+ static constexpr auto LIB_FBCLIENT = " libfbclient.so" ;
15+ static constexpr auto SYMBOL_GET_MASTER_INTERFACE = " fb_get_master_interface" ;
16+
17+ static void * handle = nullptr ;
18+ static GetMasterPtr masterFunc = nullptr ;
19+ static fb::IMaster* master = nullptr ;
20+ static fb::IUtil* util = nullptr ;
21+ static fb::IProvider* dispatcher = nullptr ;
22+ static fb::IStatus* status = nullptr ;
23+ static std::unique_ptr<fb::ThrowStatusWrapper> statusWrapper;
24+ static fb::IAttachment* attachment = nullptr ;
25+
26+
27+ // Loads Firebird library and get main interfaces.
28+ static void loadLibrary () {
29+ if (handle)
30+ return ;
31+
32+ if (!(handle = dlopen (LIB_FBCLIENT , RTLD_NOW )))
33+ throw std::runtime_error (" Error loading Firebird client library." );
34+
35+ if (!(masterFunc = (GetMasterPtr) dlsym (handle, SYMBOL_GET_MASTER_INTERFACE ))) {
36+ dlclose (handle);
37+ handle = nullptr ;
38+ throw std::runtime_error (" Error getting Firebird master interface." );
39+ }
40+
41+ master = masterFunc ();
42+ util = master->getUtilInterface ();
43+ dispatcher = master->getDispatcher ();
44+ status = master->getStatus ();
45+ statusWrapper = std::make_unique<fb::ThrowStatusWrapper>(status);
46+ }
47+
48+ // Unloads Firebird library.
49+ static void unloadLibrary () {
50+ if (handle) {
51+ dispatcher->shutdown (statusWrapper.get (), 0 , fb_shutrsn_app_stopped);
52+ status->dispose ();
53+ dispatcher->release ();
54+ dlclose (handle);
55+ handle = nullptr ;
56+ }
57+ }
58+
59+ // Connects to Firebird database. Creates it if necessary.
60+ static void connect (std::string databaseName) {
61+ loadLibrary ();
62+
63+ try {
64+ attachment = dispatcher->attachDatabase (
65+ statusWrapper.get (),
66+ databaseName.c_str (),
67+ 0 ,
68+ nullptr );
69+ }
70+ catch (const fb::FbException&) {
71+ attachment = dispatcher->createDatabase (
72+ statusWrapper.get (),
73+ databaseName.c_str (),
74+ 0 ,
75+ nullptr );
76+ }
77+ }
78+
79+ // Disconnects the database.
80+ static void disconnect () {
81+ if (attachment) {
82+ attachment->detach (statusWrapper.get ());
83+ attachment->release ();
84+ attachment = nullptr ;
85+ }
86+
87+ unloadLibrary ();
88+ }
89+
90+ // Query CURRENT_TIMESTAMP using a Firebird query.
91+ static std::string getCurrentTimestamp () {
92+ const auto transaction = attachment->startTransaction (statusWrapper.get (), 0 , nullptr );
93+
94+ FB_MESSAGE (message, fb::ThrowStatusWrapper,
95+ (FB_VARCHAR (64 ), currentTimestamp)
96+ ) message (statusWrapper.get (), master);
97+
98+ attachment->execute (
99+ statusWrapper.get (),
100+ transaction,
101+ 0 ,
102+ " select current_timestamp from rdb$database" ,
103+ SQL_DIALECT_CURRENT ,
104+ nullptr ,
105+ nullptr ,
106+ message.getMetadata (),
107+ message.getData ());
108+
109+ transaction->commit (statusWrapper.get ());
110+ transaction->release ();
111+
112+ return std::string (message->currentTimestamp .str , message->currentTimestamp .length );
113+ }
114+
115+
116+ // Converts JNI string to std::string.
117+ static std::string convertJString (JNIEnv* env, jstring str) {
118+ if (!str)
119+ return {};
120+
121+ const auto len = env->GetStringUTFLength (str);
122+ const auto strChars = env->GetStringUTFChars (str, nullptr );
123+
124+ std::string result (strChars, len);
125+
126+ env->ReleaseStringUTFChars (str, strChars);
127+
128+ return result;
129+ }
130+
131+ // Rethrow C++ as JNI exception.
132+ static void jniRethrow (JNIEnv* env)
133+ {
134+ std::string message;
135+
136+ try {
137+ throw ;
138+ assert (false );
139+ return ;
140+ }
141+ catch (const fb::FbException& e) {
142+ char buffer[1024 ];
143+ util->formatStatus (buffer, sizeof (buffer), e.getStatus ());
144+ message = buffer;
145+ }
146+ catch (const std::exception& e) {
147+ message = e.what ();
148+ }
149+ catch (...) {
150+ message = " Unrecognized C++ exception" ;
151+ }
152+
153+ const auto exception = env->FindClass (" java/lang/Exception" );
154+ env->ThrowNew (exception, message.c_str ());
155+ }
156+
157+
158+ // JNI JMainActivity.connect.
159+ extern " C" JNIEXPORT
160+ void JNICALL Java_com_example_firebirdandroidcpp_MainActivity_connect (
161+ JNIEnv* env, jobject self, jstring databaseName) {
162+ try {
163+ connect (convertJString (env, databaseName));
164+ }
165+ catch (...) {
166+ jniRethrow (env);
167+ }
168+ }
169+
170+ // JNI JMainActivity.disconnect.
171+ extern " C" JNIEXPORT
172+ void JNICALL Java_com_example_firebirdandroidcpp_MainActivity_disconnect (
173+ JNIEnv* env, jobject self) {
174+ try {
175+ disconnect ();
176+ }
177+ catch (...) {
178+ jniRethrow (env);
179+ }
180+ }
181+
182+ // JNI JMainActivity.getCurrentTimestamp.
183+ extern " C" JNIEXPORT
184+ jstring JNICALL Java_com_example_firebirdandroidcpp_MainActivity_getCurrentTimestamp (
185+ JNIEnv* env, jobject self) {
186+ try {
187+ std::string currentTimestamp = getCurrentTimestamp ();
188+ return env->NewStringUTF (currentTimestamp.c_str ());
189+ }
190+ catch (...) {
191+ jniRethrow (env);
192+ return nullptr ;
193+ }
194+ }
0 commit comments