comparison Odbc/Plugins/StoragePlugin.cpp @ 329:b5fb8b77ce4d

initial commit of ODBC framework
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 10 Aug 2021 20:08:53 +0200
parents
children 674bbb9d1c83
comparison
equal deleted inserted replaced
328:6a49c495c940 329:b5fb8b77ce4d
1 /**
2 * Orthanc - A Lightweight, RESTful DICOM Store
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
4 * Department, University Hospital of Liege, Belgium
5 * Copyright (C) 2017-2021 Osimis S.A., Belgium
6 *
7 * This program is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU Affero General Public License
9 * as published by the Free Software Foundation, either version 3 of
10 * the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Affero General Public License for more details.
16 *
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 **/
20
21
22 #include "../../Framework/Odbc/OdbcDatabase.h"
23 #include "../../Framework/Plugins/PluginInitialization.h"
24 #include "../../Framework/Plugins/StorageBackend.h"
25 #include "../../Resources/Orthanc/Plugins/OrthancPluginCppWrapper.h"
26
27 #include <EmbeddedResources.h> // Autogenerated file
28
29 #include <Logging.h>
30
31
32 namespace OrthancDatabases
33 {
34 class OdbcStorageArea : public StorageBackend
35 {
36 protected:
37 virtual bool HasReadRange() const ORTHANC_OVERRIDE
38 {
39 // Read range is only available in native PostgreSQL/MySQL plugins
40 return false;
41 }
42
43 public:
44 OdbcStorageArea(unsigned int maxConnectionRetries,
45 unsigned int connectionRetryInterval,
46 const std::string& connectionString) :
47 StorageBackend(OdbcDatabase::CreateDatabaseFactory(
48 maxConnectionRetries, connectionRetryInterval, connectionString, false),
49 maxConnectionRetries)
50 {
51 {
52 AccessorBase accessor(*this);
53 OdbcDatabase& db = dynamic_cast<OdbcDatabase&>(accessor.GetManager().GetDatabase());
54
55 if (!db.DoesTableExist("storagearea"))
56 {
57 std::string sql;
58 Orthanc::EmbeddedResources::GetFileResource(sql, Orthanc::EmbeddedResources::ODBC_PREPARE_STORAGE);
59
60 switch (db.GetDialect())
61 {
62 case Dialect_SQLite:
63 boost::replace_all(sql, "${BINARY}", "BLOB");
64 break;
65
66 case Dialect_PostgreSQL:
67 boost::replace_all(sql, "${BINARY}", "BYTEA");
68 break;
69
70 case Dialect_MySQL:
71 boost::replace_all(sql, "${BINARY}", "LONGBLOB");
72 break;
73
74 case Dialect_MSSQL:
75 boost::replace_all(sql, "${BINARY}", "VARBINARY(MAX)");
76 break;
77
78 default:
79 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
80 }
81
82 {
83 DatabaseManager::Transaction t(accessor.GetManager(), TransactionType_ReadWrite);
84 db.ExecuteMultiLines(sql);
85 t.Commit();
86 }
87 }
88 }
89 }
90 };
91 }
92
93
94
95 #if defined(_WIN32)
96 # include <windows.h>
97 #else
98 # include <ltdl.h>
99 # include <libltdl/lt_dlloader.h>
100 #endif
101
102
103 static const char* const KEY_ODBC = "Odbc";
104
105
106 extern "C"
107 {
108 #if !defined(_WIN32)
109 extern lt_dlvtable *dlopen_LTX_get_vtable(lt_user_data loader_data);
110 #endif
111
112
113 ORTHANC_PLUGINS_API int32_t OrthancPluginInitialize(OrthancPluginContext* context)
114 {
115 if (!OrthancDatabases::InitializePlugin(context, "ODBC", false))
116 {
117 return -1;
118 }
119
120 #if !defined(_WIN32)
121 lt_dlinit();
122
123 /**
124 * The following call is necessary for "libltdl" to access the
125 * "dlopen()" primitives if statically linking. Otherwise, only the
126 * "preopen" primitives are available.
127 **/
128 lt_dlloader_add(dlopen_LTX_get_vtable(NULL));
129 #endif
130
131 OrthancPlugins::OrthancConfiguration configuration;
132
133 if (!configuration.IsSection(KEY_ODBC))
134 {
135 LOG(WARNING) << "No available configuration for the ODBC storage area plugin";
136 return 0;
137 }
138
139 OrthancPlugins::OrthancConfiguration odbc;
140 configuration.GetSection(odbc, KEY_ODBC);
141
142 bool enable;
143 if (!odbc.LookupBooleanValue(enable, "EnableStorage") ||
144 !enable)
145 {
146 LOG(WARNING) << "The ODBC storage area is currently disabled, set \"EnableStorage\" "
147 << "to \"true\" in the \"" << KEY_ODBC << "\" section of the configuration file of Orthanc";
148 return 0;
149 }
150
151 try
152 {
153 const std::string connectionString = odbc.GetStringValue("StorageConnectionString", "");
154 const unsigned int maxConnectionRetries = odbc.GetUnsignedIntegerValue("MaxConnectionRetries", 10);
155 const unsigned int connectionRetryInterval = odbc.GetUnsignedIntegerValue("ConnectionRetryInterval", 5);
156
157 if (connectionString.empty())
158 {
159 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange,
160 "No connection string provided for the ODBC storage area");
161 }
162
163 OrthancDatabases::StorageBackend::Register(
164 context, new OrthancDatabases::OdbcStorageArea(
165 maxConnectionRetries, connectionRetryInterval, connectionString));
166 }
167 catch (Orthanc::OrthancException& e)
168 {
169 LOG(ERROR) << e.What();
170 return -1;
171 }
172 catch (...)
173 {
174 LOG(ERROR) << "Native exception while initializing the plugin";
175 return -1;
176 }
177
178 return 0;
179 }
180
181
182 ORTHANC_PLUGINS_API void OrthancPluginFinalize()
183 {
184 LOG(WARNING) << "ODBC storage area is finalizing";
185 OrthancDatabases::StorageBackend::Finalize();
186 }
187
188
189 ORTHANC_PLUGINS_API const char* OrthancPluginGetName()
190 {
191 return "odbc-storage";
192 }
193
194
195 ORTHANC_PLUGINS_API const char* OrthancPluginGetVersion()
196 {
197 return ORTHANC_PLUGIN_VERSION;
198 }
199 }